@rubytech/create-maxy-code 0.1.190 → 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/docs/references/admin-ui.md +16 -0
- 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-extract.d.ts +9 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.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 +44 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +2 -0
- 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 +21 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +140 -2
- 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 +546 -361
- package/payload/server/public/assets/admin-Cv2A5vnQ.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-DIa-MKNj.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DeTNsAO0.js +0 -1
- package/payload/server/public/assets/graph-Y5y3kw6J.js +0 -1
- package/payload/server/public/assets/graph-labels-BIRCh328.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-BCCqlOmj.js +0 -1
- package/payload/server/public/assets/page-DwNvJOvr.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 resolve23, join as join15, basename 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
|
|
|
@@ -8004,10 +8004,10 @@ function computeSpecialistDomains(accountId) {
|
|
|
8004
8004
|
const resolveDesc = (qualified) => {
|
|
8005
8005
|
if (!qualified.startsWith("mcp__")) return void 0;
|
|
8006
8006
|
const rest = qualified.slice(5);
|
|
8007
|
-
const
|
|
8008
|
-
if (
|
|
8009
|
-
const plugin = rest.slice(0,
|
|
8010
|
-
const tool = rest.slice(
|
|
8007
|
+
const sep7 = rest.indexOf("__");
|
|
8008
|
+
if (sep7 < 0) return void 0;
|
|
8009
|
+
const plugin = rest.slice(0, sep7);
|
|
8010
|
+
const tool = rest.slice(sep7 + 2);
|
|
8011
8011
|
let map = descByPlugin.get(plugin);
|
|
8012
8012
|
if (!map) {
|
|
8013
8013
|
const dir = pluginDirs.get(plugin);
|
|
@@ -8396,6 +8396,7 @@ import { realpathSync as realpathSync3 } from "fs";
|
|
|
8396
8396
|
import { resolve as resolve12, normalize, sep as sep2, relative } from "path";
|
|
8397
8397
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve12(process.cwd(), "../platform");
|
|
8398
8398
|
var DATA_ROOT = resolve12(PLATFORM_ROOT5, "..", "data");
|
|
8399
|
+
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve12(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
8399
8400
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
8400
8401
|
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8401
8402
|
function crossesForeignAccountPartition(relPath2, accountId) {
|
|
@@ -8406,17 +8407,17 @@ function crossesForeignAccountPartition(relPath2, accountId) {
|
|
|
8406
8407
|
if (!ACCOUNT_UUID_RE.test(owner)) return false;
|
|
8407
8408
|
return owner !== accountId;
|
|
8408
8409
|
}
|
|
8409
|
-
function
|
|
8410
|
+
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
8410
8411
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
8411
|
-
const absolute = resolve12(
|
|
8412
|
-
let
|
|
8412
|
+
const absolute = resolve12(rootAbs, cleaned);
|
|
8413
|
+
let rootReal;
|
|
8413
8414
|
try {
|
|
8414
|
-
|
|
8415
|
+
rootReal = realpathSync3(rootAbs);
|
|
8415
8416
|
} catch (err) {
|
|
8416
8417
|
return {
|
|
8417
8418
|
ok: false,
|
|
8418
8419
|
status: 500,
|
|
8419
|
-
error:
|
|
8420
|
+
error: `${rootLabel} not accessible: ${err instanceof Error ? err.message : String(err)}`
|
|
8420
8421
|
};
|
|
8421
8422
|
}
|
|
8422
8423
|
let resolvedReal;
|
|
@@ -8425,8 +8426,8 @@ function resolveDataPath(raw) {
|
|
|
8425
8426
|
} catch (err) {
|
|
8426
8427
|
const code = err.code;
|
|
8427
8428
|
if (code === "ENOENT") {
|
|
8428
|
-
if (absolute !==
|
|
8429
|
-
return { ok: false, status: 403, error:
|
|
8429
|
+
if (absolute !== rootReal && !absolute.startsWith(rootReal + sep2)) {
|
|
8430
|
+
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
|
|
8430
8431
|
}
|
|
8431
8432
|
return { ok: false, status: 404, error: "Not found" };
|
|
8432
8433
|
}
|
|
@@ -8436,11 +8437,20 @@ function resolveDataPath(raw) {
|
|
|
8436
8437
|
error: err instanceof Error ? err.message : String(err)
|
|
8437
8438
|
};
|
|
8438
8439
|
}
|
|
8439
|
-
if (resolvedReal !==
|
|
8440
|
-
return { ok: false, status: 403, error:
|
|
8440
|
+
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep2)) {
|
|
8441
|
+
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
|
|
8442
|
+
}
|
|
8443
|
+
const relPath2 = relative(rootReal, resolvedReal) || ".";
|
|
8444
|
+
return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath2 };
|
|
8445
|
+
}
|
|
8446
|
+
function resolveDataPath(raw) {
|
|
8447
|
+
return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
|
|
8448
|
+
}
|
|
8449
|
+
function resolveClaudeUploadsPath(raw) {
|
|
8450
|
+
if (!CLAUDE_UPLOADS_ROOT) {
|
|
8451
|
+
return { ok: false, status: 404, error: "Not found" };
|
|
8441
8452
|
}
|
|
8442
|
-
|
|
8443
|
-
return { ok: true, absolute: resolvedReal, dataRootReal, relative: relPath2 };
|
|
8453
|
+
return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
|
|
8444
8454
|
}
|
|
8445
8455
|
|
|
8446
8456
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -8759,11 +8769,23 @@ async function cascadeDeleteDocument(params) {
|
|
|
8759
8769
|
// app/lib/file-index.ts
|
|
8760
8770
|
import * as fsp from "fs/promises";
|
|
8761
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";
|
|
8762
8773
|
import { execFile as execFile2 } from "child_process";
|
|
8763
8774
|
import { promisify as promisify2 } from "util";
|
|
8764
8775
|
var execFileAsync2 = promisify2(execFile2);
|
|
8765
8776
|
var CONTENT_CAP = 1e5;
|
|
8766
|
-
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;
|
|
8767
8789
|
var lastReconcileAt = /* @__PURE__ */ new Map();
|
|
8768
8790
|
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8769
8791
|
".txt",
|
|
@@ -8816,26 +8838,60 @@ async function extractPdf(absolute) {
|
|
|
8816
8838
|
});
|
|
8817
8839
|
return stdout.trim();
|
|
8818
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
|
+
}
|
|
8819
8866
|
function stripHtml(html) {
|
|
8820
8867
|
return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8821
8868
|
}
|
|
8822
8869
|
async function extractFileContent(absolute) {
|
|
8823
8870
|
const ext = extname2(absolute).toLowerCase();
|
|
8824
8871
|
try {
|
|
8825
|
-
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
|
+
}
|
|
8826
8878
|
if (HTML_EXTENSIONS.has(ext)) {
|
|
8827
8879
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8828
|
-
return stripHtml(raw).slice(0, CONTENT_CAP);
|
|
8880
|
+
return { content: stripHtml(raw).slice(0, CONTENT_CAP), route: "html" };
|
|
8829
8881
|
}
|
|
8830
8882
|
if (TEXT_EXTENSIONS.has(ext)) {
|
|
8831
8883
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8832
|
-
return raw.slice(0, CONTENT_CAP);
|
|
8884
|
+
return { content: raw.slice(0, CONTENT_CAP), route: "text" };
|
|
8833
8885
|
}
|
|
8834
|
-
|
|
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" };
|
|
8835
8891
|
} catch (err) {
|
|
8836
8892
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8837
8893
|
console.error(`[file-index] extract-failed path="${relative2(DATA_ROOT, absolute)}" err="${msg}"`);
|
|
8838
|
-
return "";
|
|
8894
|
+
return { content: "", route: "name-only" };
|
|
8839
8895
|
}
|
|
8840
8896
|
}
|
|
8841
8897
|
async function readDisplayName(absolute) {
|
|
@@ -8899,9 +8955,86 @@ async function upsertFileArtifact(session, f) {
|
|
|
8899
8955
|
f
|
|
8900
8956
|
);
|
|
8901
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
|
+
}
|
|
8902
9035
|
async function buildArtifact(accountId, wf, embed2) {
|
|
8903
9036
|
const name = basename3(wf.absolute);
|
|
8904
|
-
const content = await extractFileContent(wf.absolute);
|
|
9037
|
+
const { content, route } = await extractFileContent(wf.absolute);
|
|
8905
9038
|
const displayName = await readDisplayName(wf.absolute);
|
|
8906
9039
|
const embedInput = `${name}
|
|
8907
9040
|
${content}`.slice(0, CONTENT_CAP);
|
|
@@ -8913,7 +9046,7 @@ ${content}`.slice(0, CONTENT_CAP);
|
|
|
8913
9046
|
console.error(`[file-index] embed-failed path="${wf.relativePath}" err="${err.message}"`);
|
|
8914
9047
|
}
|
|
8915
9048
|
console.error(
|
|
8916
|
-
`[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}`
|
|
8917
9050
|
);
|
|
8918
9051
|
return {
|
|
8919
9052
|
accountId,
|
|
@@ -8972,14 +9105,29 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
8972
9105
|
const unchanged = prior && prior.sizeBytes === wf.sizeBytes && prior.modifiedAt === wf.modifiedAt && prior.hasEmbedding;
|
|
8973
9106
|
if (unchanged) {
|
|
8974
9107
|
skipped++;
|
|
8975
|
-
|
|
9108
|
+
} else {
|
|
9109
|
+
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9110
|
+
upserted++;
|
|
8976
9111
|
}
|
|
8977
|
-
await
|
|
8978
|
-
upserted++;
|
|
9112
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, wf.relativePath, wf.absolute);
|
|
8979
9113
|
}
|
|
8980
9114
|
let pruned = 0;
|
|
9115
|
+
let cascadeKds = 0, cascadeSections = 0, cascadeChunks = 0;
|
|
8981
9116
|
if (clean) {
|
|
8982
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
|
+
}
|
|
8983
9131
|
const pruneRes = await session.run(
|
|
8984
9132
|
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
8985
9133
|
WHERE NOT f.relativePath IN $foundPaths
|
|
@@ -8991,7 +9139,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
8991
9139
|
pruned = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
8992
9140
|
}
|
|
8993
9141
|
console.error(
|
|
8994
|
-
`[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}`
|
|
8995
9143
|
);
|
|
8996
9144
|
return { walked: walked.length, upserted, skipped, pruned };
|
|
8997
9145
|
});
|
|
@@ -9020,10 +9168,12 @@ async function indexFile(accountId, relativePath, opts) {
|
|
|
9020
9168
|
modifiedAt: st.mtime.toISOString()
|
|
9021
9169
|
};
|
|
9022
9170
|
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9171
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolute);
|
|
9023
9172
|
});
|
|
9024
9173
|
}
|
|
9025
9174
|
async function dropFileIndex(accountId, relativePath, opts) {
|
|
9026
9175
|
await withSession(opts, async (session) => {
|
|
9176
|
+
const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, [relativePath]);
|
|
9027
9177
|
const res = await session.run(
|
|
9028
9178
|
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
9029
9179
|
DETACH DELETE f
|
|
@@ -9032,7 +9182,9 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
9032
9182
|
);
|
|
9033
9183
|
const c = res.records[0]?.get("dropped");
|
|
9034
9184
|
const dropped = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9035
|
-
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
|
+
);
|
|
9036
9188
|
});
|
|
9037
9189
|
}
|
|
9038
9190
|
|
|
@@ -9109,10 +9261,28 @@ function buildDisplayPath(relPath2, accountNames) {
|
|
|
9109
9261
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
9110
9262
|
});
|
|
9111
9263
|
}
|
|
9264
|
+
async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
9265
|
+
if (!attachmentId) return false;
|
|
9266
|
+
const session = getSession();
|
|
9267
|
+
try {
|
|
9268
|
+
const result = await session.run(
|
|
9269
|
+
`MATCH (d:KnowledgeDocument { accountId: $accountId, attachmentId: $attachmentId })
|
|
9270
|
+
RETURN count(d) > 0 AS owned`,
|
|
9271
|
+
{ accountId, attachmentId }
|
|
9272
|
+
);
|
|
9273
|
+
return result.records[0]?.get("owned") === true;
|
|
9274
|
+
} catch (err) {
|
|
9275
|
+
console.error(`[data] kd-ownership-check-failed attachmentId="${attachmentId.slice(0, 8)}\u2026" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
9276
|
+
return false;
|
|
9277
|
+
} finally {
|
|
9278
|
+
await session.close();
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
9112
9281
|
var app15 = new Hono();
|
|
9113
9282
|
app15.get("/", requireAdminSession, async (c) => {
|
|
9114
9283
|
const cacheKey = c.var.cacheKey;
|
|
9115
|
-
|
|
9284
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9285
|
+
if (!accountId) {
|
|
9116
9286
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
9117
9287
|
return c.json({ error: "Account not found for session" }, 401);
|
|
9118
9288
|
}
|
|
@@ -9125,17 +9295,26 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9125
9295
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9126
9296
|
}
|
|
9127
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
|
+
}
|
|
9128
9302
|
try {
|
|
9129
9303
|
const info = await stat4(absolute);
|
|
9130
9304
|
if (!info.isDirectory()) {
|
|
9131
9305
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
9132
9306
|
}
|
|
9133
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");
|
|
9134
9310
|
const entries = [];
|
|
9135
9311
|
for (const name of names) {
|
|
9136
9312
|
if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
9137
9313
|
continue;
|
|
9138
9314
|
}
|
|
9315
|
+
if (isAccountParent && UUID_RE3.test(name) && name !== accountId) {
|
|
9316
|
+
continue;
|
|
9317
|
+
}
|
|
9139
9318
|
try {
|
|
9140
9319
|
const entryPath = join12(absolute, name);
|
|
9141
9320
|
const s = await stat4(entryPath);
|
|
@@ -9180,15 +9359,26 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
9180
9359
|
}
|
|
9181
9360
|
const rawPath = c.req.query("path") ?? "";
|
|
9182
9361
|
if (!rawPath) return c.json({ error: "path required" }, 400);
|
|
9183
|
-
const
|
|
9362
|
+
const root = c.req.query("root") ?? "data";
|
|
9363
|
+
if (root !== "data" && root !== "claude-uploads") {
|
|
9364
|
+
return c.json({ error: "invalid root" }, 400);
|
|
9365
|
+
}
|
|
9366
|
+
const resolution = root === "claude-uploads" ? resolveClaudeUploadsPath(rawPath) : resolveDataPath(rawPath);
|
|
9184
9367
|
if (!resolution.ok) {
|
|
9185
9368
|
if (resolution.status === 403) {
|
|
9186
|
-
console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
|
|
9369
|
+
console.error(`[data] path-traversal-blocked root="${root}" requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
|
|
9187
9370
|
}
|
|
9188
9371
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9189
9372
|
}
|
|
9190
9373
|
const { absolute, relative: relPath2 } = resolution;
|
|
9191
|
-
if (
|
|
9374
|
+
if (root === "claude-uploads") {
|
|
9375
|
+
const attachmentId = relPath2.split("/").filter(Boolean)[0] ?? "";
|
|
9376
|
+
const owned = await knowledgeDocOwnedByAccount(accountId, attachmentId);
|
|
9377
|
+
if (!owned) {
|
|
9378
|
+
console.error(`[data] account-scope-blocked root="claude-uploads" attachmentId="${attachmentId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
9379
|
+
return c.json({ error: "Not found" }, 404);
|
|
9380
|
+
}
|
|
9381
|
+
} else if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9192
9382
|
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9193
9383
|
return c.json({ error: "Not found" }, 404);
|
|
9194
9384
|
}
|
|
@@ -9201,7 +9391,7 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
9201
9391
|
const mimeType = detectMimeType(absolute);
|
|
9202
9392
|
const nodeStream = createReadStream2(absolute);
|
|
9203
9393
|
const webStream = Readable2.toWeb(nodeStream);
|
|
9204
|
-
console.error(`[data] file-download path="${relPath2}" size=${info.size}`);
|
|
9394
|
+
console.error(`[data] file-download root="${root}" path="${relPath2}" size=${info.size}`);
|
|
9205
9395
|
const safeQuotedName = filename.replace(/[\r\n"\\]/g, "_");
|
|
9206
9396
|
const encodedName = encodeURIComponent(filename);
|
|
9207
9397
|
return new Response(webStream, {
|
|
@@ -9302,6 +9492,10 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9302
9492
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9303
9493
|
}
|
|
9304
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
|
+
}
|
|
9305
9499
|
const base = basename4(absolute);
|
|
9306
9500
|
const segments = relPath2.split("/").filter(Boolean);
|
|
9307
9501
|
if (base === "account.json" || segments.includes(".git")) {
|
|
@@ -11359,35 +11553,15 @@ var WRITE_CYPHER = `
|
|
|
11359
11553
|
var graph_default_view_default = app21;
|
|
11360
11554
|
|
|
11361
11555
|
// server/routes/admin/sidebar-artefacts.ts
|
|
11362
|
-
import
|
|
11363
|
-
import {
|
|
11364
|
-
import { resolve as resolve15, relative as relative3, isAbsolute, sep as sep5 } 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";
|
|
11365
11558
|
import { existsSync as existsSync16 } from "fs";
|
|
11366
11559
|
var LIMIT = 50;
|
|
11367
|
-
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
11368
11560
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
11369
11561
|
function toDataRootRelPath(absPath) {
|
|
11370
11562
|
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep5)) return null;
|
|
11371
11563
|
return relative3(DATA_ROOT, absPath);
|
|
11372
11564
|
}
|
|
11373
|
-
async function resolveDocAbsPath(accountId, attachmentId) {
|
|
11374
|
-
if (!attachmentId) return null;
|
|
11375
|
-
const accountDir = resolve15(ATTACHMENTS_ROOT, accountId);
|
|
11376
|
-
const dir = resolve15(accountDir, attachmentId);
|
|
11377
|
-
try {
|
|
11378
|
-
validateFilePathInAccount(dir, accountDir);
|
|
11379
|
-
} catch {
|
|
11380
|
-
return null;
|
|
11381
|
-
}
|
|
11382
|
-
try {
|
|
11383
|
-
const entries = await readdir4(dir);
|
|
11384
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11385
|
-
if (!dataFile) return null;
|
|
11386
|
-
return resolve15(dir, dataFile);
|
|
11387
|
-
} catch {
|
|
11388
|
-
return null;
|
|
11389
|
-
}
|
|
11390
|
-
}
|
|
11391
11565
|
var app22 = new Hono();
|
|
11392
11566
|
app22.get("/", requireAdminSession, async (c) => {
|
|
11393
11567
|
const cacheKey = c.var.cacheKey;
|
|
@@ -11396,102 +11570,58 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
11396
11570
|
return c.json({ error: "Account not found for session" }, 401);
|
|
11397
11571
|
}
|
|
11398
11572
|
const start = Date.now();
|
|
11399
|
-
const
|
|
11400
|
-
if (
|
|
11573
|
+
const outputs = await fetchOutputArtefacts(accountId);
|
|
11574
|
+
if (outputs === null) {
|
|
11401
11575
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
11402
11576
|
}
|
|
11403
11577
|
const accountDir = resolve15(ACCOUNTS_DIR, accountId);
|
|
11404
11578
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
11405
|
-
const artefacts = [...
|
|
11579
|
+
const artefacts = [...outputs, ...agents].sort(
|
|
11406
11580
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
11407
11581
|
).slice(0, LIMIT);
|
|
11408
11582
|
const ms = Date.now() - start;
|
|
11409
11583
|
console.log(
|
|
11410
|
-
`[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}`
|
|
11411
11585
|
);
|
|
11412
11586
|
return c.json({ artefacts });
|
|
11413
11587
|
});
|
|
11414
|
-
async function
|
|
11588
|
+
async function fetchOutputArtefacts(accountId) {
|
|
11415
11589
|
const session = getSession();
|
|
11416
|
-
let metas = [];
|
|
11417
11590
|
try {
|
|
11418
11591
|
const result = await session.run(
|
|
11419
|
-
`MATCH (
|
|
11420
|
-
WHERE
|
|
11421
|
-
RETURN
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
mimeType
|
|
11433
|
-
|
|
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
|
+
});
|
|
11434
11618
|
} catch (err) {
|
|
11435
11619
|
const message = err instanceof Error ? err.message : String(err);
|
|
11436
11620
|
console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
|
|
11437
|
-
await session.close();
|
|
11438
11621
|
return null;
|
|
11439
11622
|
} finally {
|
|
11440
11623
|
await session.close();
|
|
11441
11624
|
}
|
|
11442
|
-
return Promise.all(metas.map(async (m) => {
|
|
11443
|
-
const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
|
|
11444
|
-
const absPath = await resolveDocAbsPath(accountId, m.attachmentId);
|
|
11445
|
-
return {
|
|
11446
|
-
id: m.id,
|
|
11447
|
-
name: m.name,
|
|
11448
|
-
kind: "knowledge-doc",
|
|
11449
|
-
updatedAt: m.updatedAt,
|
|
11450
|
-
content,
|
|
11451
|
-
editable: skipReason === null,
|
|
11452
|
-
mimeType: m.mimeType,
|
|
11453
|
-
skipReason,
|
|
11454
|
-
downloadPath: absPath ? toDataRootRelPath(absPath) : null
|
|
11455
|
-
};
|
|
11456
|
-
}));
|
|
11457
|
-
}
|
|
11458
|
-
async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
|
|
11459
|
-
if (!attachmentId) {
|
|
11460
|
-
logSkip(displayName, "null-attachmentId", mimeType);
|
|
11461
|
-
return { content: "", skipReason: "null-attachmentId" };
|
|
11462
|
-
}
|
|
11463
|
-
const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
|
|
11464
|
-
if (!isText) {
|
|
11465
|
-
logSkip(displayName, "non-text-mime", mimeType);
|
|
11466
|
-
return { content: "", skipReason: "non-text-mime" };
|
|
11467
|
-
}
|
|
11468
|
-
const accountDir = resolve15(ATTACHMENTS_ROOT, accountId);
|
|
11469
|
-
const dir = resolve15(accountDir, attachmentId);
|
|
11470
|
-
try {
|
|
11471
|
-
validateFilePathInAccount(dir, accountDir);
|
|
11472
|
-
} catch {
|
|
11473
|
-
logSkip(displayName, "containment-rejected", mimeType);
|
|
11474
|
-
return { content: "", skipReason: "containment-rejected" };
|
|
11475
|
-
}
|
|
11476
|
-
try {
|
|
11477
|
-
const entries = await readdir4(dir);
|
|
11478
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11479
|
-
if (!dataFile) {
|
|
11480
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11481
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11482
|
-
}
|
|
11483
|
-
return { content: await readFile5(resolve15(dir, dataFile), "utf-8"), skipReason: null };
|
|
11484
|
-
} catch (err) {
|
|
11485
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
11486
|
-
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
11487
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11488
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11489
|
-
}
|
|
11490
|
-
}
|
|
11491
|
-
function logSkip(name, reason, mimeType) {
|
|
11492
|
-
console.log(
|
|
11493
|
-
`[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
|
|
11494
|
-
);
|
|
11495
11625
|
}
|
|
11496
11626
|
async function fetchAgentTemplateRows(accountDir) {
|
|
11497
11627
|
const rows = [];
|
|
@@ -11571,23 +11701,22 @@ async function readAgentTemplateRow(inp) {
|
|
|
11571
11701
|
}
|
|
11572
11702
|
if (!chosenPath) return null;
|
|
11573
11703
|
try {
|
|
11574
|
-
const
|
|
11575
|
-
|
|
11576
|
-
stat5(chosenPath)
|
|
11577
|
-
]);
|
|
11704
|
+
const st = await stat5(chosenPath);
|
|
11705
|
+
const dlPath = toDataRootRelPath(chosenPath);
|
|
11578
11706
|
return {
|
|
11579
11707
|
id: inp.id,
|
|
11580
11708
|
name: inp.displayName,
|
|
11581
11709
|
kind: "agent-template",
|
|
11582
11710
|
updatedAt: st.mtime.toISOString(),
|
|
11583
|
-
content,
|
|
11584
11711
|
editable: inp.editable,
|
|
11585
11712
|
mimeType: "text/markdown",
|
|
11586
|
-
skipReason: null,
|
|
11587
11713
|
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
11588
11714
|
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
11589
11715
|
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
11590
|
-
|
|
11716
|
+
// Agent templates only ever resolve under DATA_ROOT, so the download
|
|
11717
|
+
// root is `data` whenever the path is non-null.
|
|
11718
|
+
downloadPath: dlPath,
|
|
11719
|
+
downloadRoot: dlPath ? "data" : null
|
|
11591
11720
|
};
|
|
11592
11721
|
} catch (err) {
|
|
11593
11722
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -11724,57 +11853,8 @@ function relPath(absPath, root) {
|
|
|
11724
11853
|
}
|
|
11725
11854
|
var sidebar_artefact_save_default = app23;
|
|
11726
11855
|
|
|
11727
|
-
// server/routes/admin/sidebar-artefact-content.ts
|
|
11728
|
-
import { readFile as readFile6, readdir as readdir6 } from "fs/promises";
|
|
11729
|
-
import { existsSync as existsSync18 } from "fs";
|
|
11730
|
-
import { resolve as resolve17 } from "path";
|
|
11731
|
-
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11732
|
-
var app24 = new Hono();
|
|
11733
|
-
app24.get("/", requireAdminSession, async (c) => {
|
|
11734
|
-
const cacheKey = c.var.cacheKey;
|
|
11735
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
11736
|
-
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
11737
|
-
const id = c.req.query("id") ?? "";
|
|
11738
|
-
if (!UUID_RE5.test(id)) {
|
|
11739
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11740
|
-
return new Response("Not found", { status: 404 });
|
|
11741
|
-
}
|
|
11742
|
-
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
11743
|
-
if (!existsSync18(dir)) {
|
|
11744
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11745
|
-
return new Response("Not found", { status: 404 });
|
|
11746
|
-
}
|
|
11747
|
-
let meta;
|
|
11748
|
-
try {
|
|
11749
|
-
meta = JSON.parse(await readFile6(resolve17(dir, `${id}.meta.json`), "utf-8"));
|
|
11750
|
-
} catch {
|
|
11751
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11752
|
-
return new Response("Not found", { status: 404 });
|
|
11753
|
-
}
|
|
11754
|
-
const entries = await readdir6(dir);
|
|
11755
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11756
|
-
if (!dataFile) {
|
|
11757
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11758
|
-
return new Response("Not found", { status: 404 });
|
|
11759
|
-
}
|
|
11760
|
-
const start = Date.now();
|
|
11761
|
-
const buffer = await readFile6(resolve17(dir, dataFile));
|
|
11762
|
-
const ms = Date.now() - start;
|
|
11763
|
-
console.log(
|
|
11764
|
-
`[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
|
|
11765
|
-
);
|
|
11766
|
-
return new Response(new Uint8Array(buffer), {
|
|
11767
|
-
headers: {
|
|
11768
|
-
"Content-Type": meta.mimeType,
|
|
11769
|
-
"Content-Disposition": `inline; filename="${meta.filename}"`,
|
|
11770
|
-
"Cache-Control": "private, max-age=3600"
|
|
11771
|
-
}
|
|
11772
|
-
});
|
|
11773
|
-
});
|
|
11774
|
-
var sidebar_artefact_content_default = app24;
|
|
11775
|
-
|
|
11776
11856
|
// server/routes/admin/system-stats.ts
|
|
11777
|
-
import { readFile as
|
|
11857
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
11778
11858
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
11779
11859
|
function parseCpuStat(blob) {
|
|
11780
11860
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
@@ -11818,11 +11898,11 @@ function parseMeminfo(blob) {
|
|
|
11818
11898
|
}
|
|
11819
11899
|
var SAMPLE_DELAY_MS = 100;
|
|
11820
11900
|
async function sampleLinux() {
|
|
11821
|
-
const a = parseCpuStat(await
|
|
11901
|
+
const a = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
|
|
11822
11902
|
await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
|
|
11823
|
-
const b = parseCpuStat(await
|
|
11824
|
-
const meminfo = parseMeminfo(await
|
|
11825
|
-
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();
|
|
11826
11906
|
const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
|
|
11827
11907
|
if (![l1, l5, l15].every(Number.isFinite)) {
|
|
11828
11908
|
throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
|
|
@@ -11868,8 +11948,8 @@ async function sample() {
|
|
|
11868
11948
|
if (process.platform === "linux") return sampleLinux();
|
|
11869
11949
|
return sampleOsFallback();
|
|
11870
11950
|
}
|
|
11871
|
-
var
|
|
11872
|
-
|
|
11951
|
+
var app24 = new Hono();
|
|
11952
|
+
app24.get("/", async (c) => {
|
|
11873
11953
|
const started = Date.now();
|
|
11874
11954
|
if (!inflight) {
|
|
11875
11955
|
inflight = sample().finally(() => {
|
|
@@ -11892,26 +11972,26 @@ app25.get("/", async (c) => {
|
|
|
11892
11972
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
11893
11973
|
}
|
|
11894
11974
|
});
|
|
11895
|
-
var system_stats_default =
|
|
11975
|
+
var system_stats_default = app24;
|
|
11896
11976
|
|
|
11897
11977
|
// server/routes/admin/health.ts
|
|
11898
|
-
import { existsSync as
|
|
11899
|
-
import { resolve as
|
|
11900
|
-
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(), "..");
|
|
11901
11981
|
var brandHostname = "maxy";
|
|
11902
11982
|
var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
|
|
11903
|
-
if (
|
|
11983
|
+
if (existsSync18(brandJsonPath)) {
|
|
11904
11984
|
try {
|
|
11905
11985
|
const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
|
|
11906
11986
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
11907
11987
|
} catch {
|
|
11908
11988
|
}
|
|
11909
11989
|
}
|
|
11910
|
-
var VERSION_FILE =
|
|
11990
|
+
var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
11911
11991
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
11912
11992
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
11913
11993
|
function readVersion() {
|
|
11914
|
-
if (!
|
|
11994
|
+
if (!existsSync18(VERSION_FILE)) return "unknown";
|
|
11915
11995
|
return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
11916
11996
|
}
|
|
11917
11997
|
async function probeConversationDb() {
|
|
@@ -11937,8 +12017,8 @@ async function probeConversationDb() {
|
|
|
11937
12017
|
});
|
|
11938
12018
|
}
|
|
11939
12019
|
}
|
|
11940
|
-
var
|
|
11941
|
-
|
|
12020
|
+
var app25 = new Hono();
|
|
12021
|
+
app25.get("/", async (c) => {
|
|
11942
12022
|
const version = readVersion();
|
|
11943
12023
|
const probe = await probeConversationDb();
|
|
11944
12024
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -11960,7 +12040,7 @@ app26.get("/", async (c) => {
|
|
|
11960
12040
|
uptimeMs
|
|
11961
12041
|
});
|
|
11962
12042
|
});
|
|
11963
|
-
var health_default2 =
|
|
12043
|
+
var health_default2 = app25;
|
|
11964
12044
|
|
|
11965
12045
|
// server/routes/admin/linkedin-ingest.ts
|
|
11966
12046
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12056,8 +12136,8 @@ function buildInitialMessage(env) {
|
|
|
12056
12136
|
}
|
|
12057
12137
|
return header;
|
|
12058
12138
|
}
|
|
12059
|
-
var
|
|
12060
|
-
|
|
12139
|
+
var app26 = new Hono();
|
|
12140
|
+
app26.post("/", requireAdminSession, async (c) => {
|
|
12061
12141
|
let body;
|
|
12062
12142
|
try {
|
|
12063
12143
|
body = await c.req.json();
|
|
@@ -12111,10 +12191,10 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
12111
12191
|
);
|
|
12112
12192
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
12113
12193
|
});
|
|
12114
|
-
var linkedin_ingest_default =
|
|
12194
|
+
var linkedin_ingest_default = app26;
|
|
12115
12195
|
|
|
12116
12196
|
// server/routes/admin/post-turn-context.ts
|
|
12117
|
-
import
|
|
12197
|
+
import neo4j2 from "neo4j-driver";
|
|
12118
12198
|
var TAG21 = "[post-turn-context]";
|
|
12119
12199
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
12120
12200
|
"embedding",
|
|
@@ -12127,10 +12207,10 @@ function isLoopbackAddr2(addr) {
|
|
|
12127
12207
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12128
12208
|
}
|
|
12129
12209
|
function convertValue(value) {
|
|
12130
|
-
if (
|
|
12210
|
+
if (neo4j2.isDateTime(value) || neo4j2.isDate(value) || neo4j2.isLocalDateTime(value) || neo4j2.isLocalTime(value) || neo4j2.isTime(value) || neo4j2.isDuration(value)) {
|
|
12131
12211
|
return value.toString();
|
|
12132
12212
|
}
|
|
12133
|
-
if (
|
|
12213
|
+
if (neo4j2.isInt(value)) {
|
|
12134
12214
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12135
12215
|
}
|
|
12136
12216
|
if (Array.isArray(value)) {
|
|
@@ -12153,8 +12233,8 @@ function pruneProperties(raw) {
|
|
|
12153
12233
|
}
|
|
12154
12234
|
return out;
|
|
12155
12235
|
}
|
|
12156
|
-
var
|
|
12157
|
-
|
|
12236
|
+
var app27 = new Hono();
|
|
12237
|
+
app27.get("/", async (c) => {
|
|
12158
12238
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12159
12239
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
12160
12240
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12214,10 +12294,10 @@ app28.get("/", async (c) => {
|
|
|
12214
12294
|
await session.close();
|
|
12215
12295
|
}
|
|
12216
12296
|
});
|
|
12217
|
-
var post_turn_context_default =
|
|
12297
|
+
var post_turn_context_default = app27;
|
|
12218
12298
|
|
|
12219
12299
|
// server/routes/admin/public-session-context.ts
|
|
12220
|
-
import
|
|
12300
|
+
import neo4j3 from "neo4j-driver";
|
|
12221
12301
|
var TAG22 = "[public-session-context]";
|
|
12222
12302
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
12223
12303
|
"embedding",
|
|
@@ -12230,10 +12310,10 @@ function isLoopbackAddr3(addr) {
|
|
|
12230
12310
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12231
12311
|
}
|
|
12232
12312
|
function convertValue2(value) {
|
|
12233
|
-
if (
|
|
12313
|
+
if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
|
|
12234
12314
|
return value.toString();
|
|
12235
12315
|
}
|
|
12236
|
-
if (
|
|
12316
|
+
if (neo4j3.isInt(value)) {
|
|
12237
12317
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12238
12318
|
}
|
|
12239
12319
|
if (Array.isArray(value)) {
|
|
@@ -12256,8 +12336,8 @@ function pruneProperties2(raw) {
|
|
|
12256
12336
|
}
|
|
12257
12337
|
return out;
|
|
12258
12338
|
}
|
|
12259
|
-
var
|
|
12260
|
-
|
|
12339
|
+
var app28 = new Hono();
|
|
12340
|
+
app28.get("/", async (c) => {
|
|
12261
12341
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12262
12342
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
12263
12343
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12316,15 +12396,15 @@ app29.get("/", async (c) => {
|
|
|
12316
12396
|
await session.close();
|
|
12317
12397
|
}
|
|
12318
12398
|
});
|
|
12319
|
-
var public_session_context_default =
|
|
12399
|
+
var public_session_context_default = app28;
|
|
12320
12400
|
|
|
12321
12401
|
// server/routes/admin/public-session-exit.ts
|
|
12322
12402
|
var TAG23 = "[public-session-exit-route]";
|
|
12323
12403
|
function isLoopbackAddr4(addr) {
|
|
12324
12404
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12325
12405
|
}
|
|
12326
|
-
var
|
|
12327
|
-
|
|
12406
|
+
var app29 = new Hono();
|
|
12407
|
+
app29.post("/", async (c) => {
|
|
12328
12408
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12329
12409
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12330
12410
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12351,15 +12431,15 @@ app30.post("/", async (c) => {
|
|
|
12351
12431
|
handlePublicSessionExit(sessionId);
|
|
12352
12432
|
return c.json({ ok: true });
|
|
12353
12433
|
});
|
|
12354
|
-
var public_session_exit_default =
|
|
12434
|
+
var public_session_exit_default = app29;
|
|
12355
12435
|
|
|
12356
12436
|
// server/routes/admin/access-session-evict.ts
|
|
12357
12437
|
var TAG24 = "[access-session-evict]";
|
|
12358
12438
|
function isLoopbackAddr5(addr) {
|
|
12359
12439
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12360
12440
|
}
|
|
12361
|
-
var
|
|
12362
|
-
|
|
12441
|
+
var app30 = new Hono();
|
|
12442
|
+
app30.post("/", async (c) => {
|
|
12363
12443
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12364
12444
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12365
12445
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12387,48 +12467,47 @@ app31.post("/", async (c) => {
|
|
|
12387
12467
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12388
12468
|
return c.json({ ok: true, dropped });
|
|
12389
12469
|
});
|
|
12390
|
-
var access_session_evict_default =
|
|
12470
|
+
var access_session_evict_default = app30;
|
|
12391
12471
|
|
|
12392
12472
|
// server/routes/admin/index.ts
|
|
12393
|
-
var
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
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;
|
|
12421
12500
|
|
|
12422
12501
|
// app/lib/access-gate.ts
|
|
12423
|
-
import
|
|
12502
|
+
import neo4j4 from "neo4j-driver";
|
|
12424
12503
|
import { readFileSync as readFileSync15 } from "fs";
|
|
12425
|
-
import { resolve as
|
|
12504
|
+
import { resolve as resolve18 } from "path";
|
|
12426
12505
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12427
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12506
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
12428
12507
|
var driver = null;
|
|
12429
12508
|
function readPassword() {
|
|
12430
12509
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12431
|
-
const passwordFile =
|
|
12510
|
+
const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12432
12511
|
try {
|
|
12433
12512
|
return readFileSync15(passwordFile, "utf-8").trim();
|
|
12434
12513
|
} catch {
|
|
@@ -12448,7 +12527,7 @@ function getDriver() {
|
|
|
12448
12527
|
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
12449
12528
|
const password = readPassword();
|
|
12450
12529
|
console.error(`[ui/access-gate] resolved neo4j_uri=${uri}`);
|
|
12451
|
-
driver =
|
|
12530
|
+
driver = neo4j4.driver(uri, neo4j4.auth.basic(user, password), {
|
|
12452
12531
|
maxConnectionPoolSize: 5
|
|
12453
12532
|
});
|
|
12454
12533
|
}
|
|
@@ -12631,8 +12710,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12631
12710
|
var TAG25 = "[access-verify]";
|
|
12632
12711
|
var MINT_TAG = "[access-session-mint]";
|
|
12633
12712
|
var COOKIE_NAME = "__access_session";
|
|
12634
|
-
var
|
|
12635
|
-
|
|
12713
|
+
var app32 = new Hono();
|
|
12714
|
+
app32.post("/", async (c) => {
|
|
12636
12715
|
const ip = c.var.clientIp || "unknown";
|
|
12637
12716
|
let body;
|
|
12638
12717
|
try {
|
|
@@ -12714,13 +12793,13 @@ app33.post("/", async (c) => {
|
|
|
12714
12793
|
displayName: grant.displayName
|
|
12715
12794
|
});
|
|
12716
12795
|
});
|
|
12717
|
-
var verify_token_default =
|
|
12796
|
+
var verify_token_default = app32;
|
|
12718
12797
|
|
|
12719
12798
|
// app/lib/access-email.ts
|
|
12720
12799
|
import { spawn as spawn2 } from "child_process";
|
|
12721
|
-
import { resolve as
|
|
12722
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12723
|
-
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(
|
|
12724
12803
|
PLATFORM_ROOT8,
|
|
12725
12804
|
"plugins",
|
|
12726
12805
|
"email",
|
|
@@ -12777,9 +12856,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12777
12856
|
|
|
12778
12857
|
// server/routes/access/request-magic-link.ts
|
|
12779
12858
|
var TAG26 = "[access-request-link]";
|
|
12780
|
-
var
|
|
12859
|
+
var app33 = new Hono();
|
|
12781
12860
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12782
|
-
|
|
12861
|
+
app33.post("/", async (c) => {
|
|
12783
12862
|
let body;
|
|
12784
12863
|
try {
|
|
12785
12864
|
body = await c.req.json();
|
|
@@ -12853,17 +12932,17 @@ app34.post("/", async (c) => {
|
|
|
12853
12932
|
);
|
|
12854
12933
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
12855
12934
|
});
|
|
12856
|
-
var request_magic_link_default =
|
|
12935
|
+
var request_magic_link_default = app33;
|
|
12857
12936
|
|
|
12858
12937
|
// server/routes/access/index.ts
|
|
12859
|
-
var
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
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;
|
|
12863
12942
|
|
|
12864
12943
|
// server/routes/sites.ts
|
|
12865
|
-
import { existsSync as
|
|
12866
|
-
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";
|
|
12867
12946
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12868
12947
|
var MIME = {
|
|
12869
12948
|
".html": "text/html; charset=utf-8",
|
|
@@ -12894,8 +12973,8 @@ function getExt(p) {
|
|
|
12894
12973
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12895
12974
|
return p.slice(idx).toLowerCase();
|
|
12896
12975
|
}
|
|
12897
|
-
var
|
|
12898
|
-
|
|
12976
|
+
var app35 = new Hono();
|
|
12977
|
+
app35.get("/:rel{.*}", (c) => {
|
|
12899
12978
|
const reqPath = c.req.path;
|
|
12900
12979
|
const rawRel = c.req.param("rel") ?? "";
|
|
12901
12980
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -12920,19 +12999,19 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
12920
12999
|
}
|
|
12921
13000
|
segments.push(seg);
|
|
12922
13001
|
}
|
|
12923
|
-
const rootDir =
|
|
12924
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
13002
|
+
const rootDir = resolve20(account.accountDir, "sites");
|
|
13003
|
+
let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
|
|
12925
13004
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
12926
13005
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
12927
13006
|
return c.text("Forbidden", 403);
|
|
12928
13007
|
}
|
|
12929
|
-
let
|
|
13008
|
+
let stat8;
|
|
12930
13009
|
try {
|
|
12931
|
-
|
|
13010
|
+
stat8 = existsSync19(filePath) ? statSync7(filePath) : null;
|
|
12932
13011
|
} catch {
|
|
12933
|
-
|
|
13012
|
+
stat8 = null;
|
|
12934
13013
|
}
|
|
12935
|
-
if (
|
|
13014
|
+
if (stat8?.isDirectory() && !reqPath.endsWith("/")) {
|
|
12936
13015
|
const search = new URL(c.req.url).search;
|
|
12937
13016
|
const target = `${reqPath}/${search}`;
|
|
12938
13017
|
console.log(
|
|
@@ -12940,14 +13019,14 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
12940
13019
|
);
|
|
12941
13020
|
return c.redirect(target, 301);
|
|
12942
13021
|
}
|
|
12943
|
-
if (
|
|
12944
|
-
filePath =
|
|
13022
|
+
if (stat8?.isDirectory()) {
|
|
13023
|
+
filePath = resolve20(filePath, "index.html");
|
|
12945
13024
|
}
|
|
12946
13025
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
12947
13026
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
12948
13027
|
return c.text("Forbidden", 403);
|
|
12949
13028
|
}
|
|
12950
|
-
if (!
|
|
13029
|
+
if (!existsSync19(filePath)) {
|
|
12951
13030
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
12952
13031
|
return c.text("Not found", 404);
|
|
12953
13032
|
}
|
|
@@ -12998,7 +13077,7 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
12998
13077
|
"X-Content-Type-Options": "nosniff"
|
|
12999
13078
|
});
|
|
13000
13079
|
});
|
|
13001
|
-
var sites_default =
|
|
13080
|
+
var sites_default = app35;
|
|
13002
13081
|
|
|
13003
13082
|
// app/lib/visitor-token.ts
|
|
13004
13083
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -13078,7 +13157,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13078
13157
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13079
13158
|
|
|
13080
13159
|
// app/lib/brand-config.ts
|
|
13081
|
-
import { existsSync as
|
|
13160
|
+
import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
|
|
13082
13161
|
import { join as join14 } from "path";
|
|
13083
13162
|
var cached2 = null;
|
|
13084
13163
|
var cachedAttempted = false;
|
|
@@ -13088,7 +13167,7 @@ function readBrandConfig() {
|
|
|
13088
13167
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13089
13168
|
if (!platformRoot) return null;
|
|
13090
13169
|
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
13091
|
-
if (!
|
|
13170
|
+
if (!existsSync20(brandPath)) return null;
|
|
13092
13171
|
try {
|
|
13093
13172
|
cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
13094
13173
|
return cached2;
|
|
@@ -13098,7 +13177,7 @@ function readBrandConfig() {
|
|
|
13098
13177
|
}
|
|
13099
13178
|
|
|
13100
13179
|
// server/routes/visitor-consent.ts
|
|
13101
|
-
var
|
|
13180
|
+
var app36 = new Hono();
|
|
13102
13181
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
13103
13182
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
13104
13183
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -13143,17 +13222,17 @@ function siteSlugFromReferer(referer) {
|
|
|
13143
13222
|
return "";
|
|
13144
13223
|
}
|
|
13145
13224
|
}
|
|
13146
|
-
|
|
13225
|
+
app36.options("/consent", (c) => {
|
|
13147
13226
|
const origin = getOrigin(c);
|
|
13148
13227
|
setCorsHeaders(c, origin);
|
|
13149
13228
|
return c.body(null, 204);
|
|
13150
13229
|
});
|
|
13151
|
-
|
|
13230
|
+
app36.options("/brand-config", (c) => {
|
|
13152
13231
|
const origin = getOrigin(c);
|
|
13153
13232
|
setCorsHeaders(c, origin);
|
|
13154
13233
|
return c.body(null, 204);
|
|
13155
13234
|
});
|
|
13156
|
-
|
|
13235
|
+
app36.post("/consent", async (c) => {
|
|
13157
13236
|
const origin = getOrigin(c);
|
|
13158
13237
|
setCorsHeaders(c, origin);
|
|
13159
13238
|
let raw;
|
|
@@ -13193,7 +13272,7 @@ app37.post("/consent", async (c) => {
|
|
|
13193
13272
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
13194
13273
|
return c.body(null, 204);
|
|
13195
13274
|
});
|
|
13196
|
-
|
|
13275
|
+
app36.get("/brand-config", (c) => {
|
|
13197
13276
|
const origin = getOrigin(c);
|
|
13198
13277
|
setCorsHeaders(c, origin);
|
|
13199
13278
|
const brand = readBrandConfig();
|
|
@@ -13203,7 +13282,7 @@ app37.get("/brand-config", (c) => {
|
|
|
13203
13282
|
c.header("Cache-Control", "public, max-age=300");
|
|
13204
13283
|
return c.json({ consent: { copy, palette } });
|
|
13205
13284
|
});
|
|
13206
|
-
var visitor_consent_default =
|
|
13285
|
+
var visitor_consent_default = app36;
|
|
13207
13286
|
|
|
13208
13287
|
// server/routes/listings.ts
|
|
13209
13288
|
function getCookie(headerValue, name) {
|
|
@@ -13224,14 +13303,14 @@ function appendConsentParams(pageUrl, token) {
|
|
|
13224
13303
|
const hashIdx = pageUrl.indexOf("#");
|
|
13225
13304
|
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
13226
13305
|
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
13227
|
-
const
|
|
13228
|
-
return base +
|
|
13306
|
+
const sep7 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
13307
|
+
return base + sep7 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
13229
13308
|
}
|
|
13230
13309
|
}
|
|
13231
13310
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
13232
13311
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
13233
|
-
var
|
|
13234
|
-
|
|
13312
|
+
var app37 = new Hono();
|
|
13313
|
+
app37.get("/:slug/click", async (c) => {
|
|
13235
13314
|
const slug = c.req.param("slug") ?? "";
|
|
13236
13315
|
const rawSession = c.req.query("session") ?? "";
|
|
13237
13316
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13295,10 +13374,10 @@ app38.get("/:slug/click", async (c) => {
|
|
|
13295
13374
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13296
13375
|
return c.redirect(redirectUrl, 302);
|
|
13297
13376
|
});
|
|
13298
|
-
var listings_default =
|
|
13377
|
+
var listings_default = app37;
|
|
13299
13378
|
|
|
13300
13379
|
// server/routes/visitor-event.ts
|
|
13301
|
-
var
|
|
13380
|
+
var app38 = new Hono();
|
|
13302
13381
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13303
13382
|
var buckets = /* @__PURE__ */ new Map();
|
|
13304
13383
|
var RATE_LIMIT = 60;
|
|
@@ -13365,12 +13444,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13365
13444
|
return false;
|
|
13366
13445
|
}
|
|
13367
13446
|
}
|
|
13368
|
-
|
|
13447
|
+
app38.options("/event", (c) => {
|
|
13369
13448
|
const origin = getOrigin2(c);
|
|
13370
13449
|
setCorsHeaders2(c, origin);
|
|
13371
13450
|
return c.body(null, 204);
|
|
13372
13451
|
});
|
|
13373
|
-
|
|
13452
|
+
app38.post("/event", async (c) => {
|
|
13374
13453
|
const origin = getOrigin2(c);
|
|
13375
13454
|
setCorsHeaders2(c, origin);
|
|
13376
13455
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13575,7 +13654,7 @@ async function writeEvent(opts) {
|
|
|
13575
13654
|
);
|
|
13576
13655
|
}
|
|
13577
13656
|
}
|
|
13578
|
-
var visitor_event_default =
|
|
13657
|
+
var visitor_event_default = app38;
|
|
13579
13658
|
|
|
13580
13659
|
// app/lib/graph-health.ts
|
|
13581
13660
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13658,6 +13737,109 @@ function startGraphHealthTimer() {
|
|
|
13658
13737
|
if (typeof timer.unref === "function") timer.unref();
|
|
13659
13738
|
}
|
|
13660
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
|
+
|
|
13661
13843
|
// app/lib/whatsapp/inbound/claude-bridge.ts
|
|
13662
13844
|
var TAG27 = "[whatsapp-adaptor]";
|
|
13663
13845
|
function whatsappTurnTimeoutMs() {
|
|
@@ -13719,7 +13901,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
13719
13901
|
|
|
13720
13902
|
// ../lib/entitlement/src/index.ts
|
|
13721
13903
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13722
|
-
import { existsSync as
|
|
13904
|
+
import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
|
|
13723
13905
|
import { resolve as resolve22 } from "path";
|
|
13724
13906
|
|
|
13725
13907
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -13768,11 +13950,11 @@ function resolveEntitlement(brand, account) {
|
|
|
13768
13950
|
return logResolved(implicitTrust(account), null);
|
|
13769
13951
|
}
|
|
13770
13952
|
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
13771
|
-
if (!
|
|
13953
|
+
if (!existsSync21(entitlementPath)) {
|
|
13772
13954
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13773
13955
|
}
|
|
13774
|
-
const
|
|
13775
|
-
const key = memoKey(
|
|
13956
|
+
const stat8 = statSync8(entitlementPath);
|
|
13957
|
+
const key = memoKey(stat8.mtimeMs, account);
|
|
13776
13958
|
if (memo && memo.key === key) {
|
|
13777
13959
|
return memo.result;
|
|
13778
13960
|
}
|
|
@@ -13960,10 +14142,10 @@ function clientFrom(c) {
|
|
|
13960
14142
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
13961
14143
|
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
13962
14144
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
13963
|
-
if (BRAND_JSON_PATH && !
|
|
14145
|
+
if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
|
|
13964
14146
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
13965
14147
|
}
|
|
13966
|
-
if (BRAND_JSON_PATH &&
|
|
14148
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
13967
14149
|
try {
|
|
13968
14150
|
const parsed = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
13969
14151
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -13987,7 +14169,7 @@ var brandLoginOpts = {
|
|
|
13987
14169
|
var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
13988
14170
|
function loadAliasDomains() {
|
|
13989
14171
|
try {
|
|
13990
|
-
if (!
|
|
14172
|
+
if (!existsSync22(ALIAS_DOMAINS_PATH)) return null;
|
|
13991
14173
|
const parsed = JSON.parse(readFileSync20(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
13992
14174
|
if (!Array.isArray(parsed)) {
|
|
13993
14175
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -14012,9 +14194,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
14012
14194
|
function isPublicHost(host) {
|
|
14013
14195
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
14014
14196
|
}
|
|
14015
|
-
var
|
|
14016
|
-
|
|
14017
|
-
|
|
14197
|
+
var app39 = new Hono();
|
|
14198
|
+
app39.use("*", clientIpMiddleware);
|
|
14199
|
+
app39.use("*", async (c, next) => {
|
|
14018
14200
|
await next();
|
|
14019
14201
|
c.header("X-Content-Type-Options", "nosniff");
|
|
14020
14202
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -14024,7 +14206,7 @@ app40.use("*", async (c, next) => {
|
|
|
14024
14206
|
);
|
|
14025
14207
|
});
|
|
14026
14208
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
14027
|
-
|
|
14209
|
+
app39.use("*", async (c, next) => {
|
|
14028
14210
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
14029
14211
|
await next();
|
|
14030
14212
|
return;
|
|
@@ -14057,7 +14239,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
14057
14239
|
"/sites/"
|
|
14058
14240
|
];
|
|
14059
14241
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
14060
|
-
|
|
14242
|
+
app39.use("*", async (c, next) => {
|
|
14061
14243
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14062
14244
|
if (!isPublicHost(host)) {
|
|
14063
14245
|
await next();
|
|
@@ -14097,7 +14279,7 @@ function resolveRemoteAuthOpts() {
|
|
|
14097
14279
|
return brandLoginOpts;
|
|
14098
14280
|
}
|
|
14099
14281
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
14100
|
-
|
|
14282
|
+
app39.post("/__remote-auth/login", async (c) => {
|
|
14101
14283
|
const client = clientFrom(c);
|
|
14102
14284
|
const clientIp = client.ip || "unknown";
|
|
14103
14285
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -14142,7 +14324,7 @@ app40.post("/__remote-auth/login", async (c) => {
|
|
|
14142
14324
|
}
|
|
14143
14325
|
});
|
|
14144
14326
|
});
|
|
14145
|
-
|
|
14327
|
+
app39.get("/__remote-auth/logout", (c) => {
|
|
14146
14328
|
const client = clientFrom(c);
|
|
14147
14329
|
const clientIp = client.ip || "unknown";
|
|
14148
14330
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -14155,7 +14337,7 @@ app40.get("/__remote-auth/logout", (c) => {
|
|
|
14155
14337
|
}
|
|
14156
14338
|
});
|
|
14157
14339
|
});
|
|
14158
|
-
|
|
14340
|
+
app39.post("/__remote-auth/change-password", async (c) => {
|
|
14159
14341
|
const client = clientFrom(c);
|
|
14160
14342
|
const clientIp = client.ip || "unknown";
|
|
14161
14343
|
const rateLimited = checkRateLimit(client);
|
|
@@ -14206,13 +14388,13 @@ app40.post("/__remote-auth/change-password", async (c) => {
|
|
|
14206
14388
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
14207
14389
|
}
|
|
14208
14390
|
});
|
|
14209
|
-
|
|
14391
|
+
app39.get("/__remote-auth/setup", (c) => {
|
|
14210
14392
|
if (isRemoteAuthConfigured()) {
|
|
14211
14393
|
return c.redirect("/");
|
|
14212
14394
|
}
|
|
14213
14395
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
14214
14396
|
});
|
|
14215
|
-
|
|
14397
|
+
app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
14216
14398
|
if (isRemoteAuthConfigured()) {
|
|
14217
14399
|
return c.redirect("/");
|
|
14218
14400
|
}
|
|
@@ -14250,10 +14432,10 @@ app40.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
14250
14432
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
14251
14433
|
}
|
|
14252
14434
|
});
|
|
14253
|
-
|
|
14435
|
+
app39.get("/api/remote-auth/status", (c) => {
|
|
14254
14436
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
14255
14437
|
});
|
|
14256
|
-
|
|
14438
|
+
app39.post("/api/remote-auth/set-password", async (c) => {
|
|
14257
14439
|
let body;
|
|
14258
14440
|
try {
|
|
14259
14441
|
body = await c.req.json();
|
|
@@ -14284,9 +14466,9 @@ app40.post("/api/remote-auth/set-password", async (c) => {
|
|
|
14284
14466
|
return c.json({ error: "Failed to save password" }, 500);
|
|
14285
14467
|
}
|
|
14286
14468
|
});
|
|
14287
|
-
|
|
14469
|
+
app39.route("/api/_client-error", client_error_default);
|
|
14288
14470
|
console.log("[client-error-route] mounted");
|
|
14289
|
-
|
|
14471
|
+
app39.use("*", async (c, next) => {
|
|
14290
14472
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14291
14473
|
const path2 = c.req.path;
|
|
14292
14474
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14319,12 +14501,12 @@ app40.use("*", async (c, next) => {
|
|
|
14319
14501
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14320
14502
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14321
14503
|
});
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
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);
|
|
14328
14510
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14329
14511
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14330
14512
|
var IMAGE_MIME = {
|
|
@@ -14336,7 +14518,7 @@ var IMAGE_MIME = {
|
|
|
14336
14518
|
".svg": "image/svg+xml",
|
|
14337
14519
|
".ico": "image/x-icon"
|
|
14338
14520
|
};
|
|
14339
|
-
|
|
14521
|
+
app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
14340
14522
|
const slug = c.req.param("slug");
|
|
14341
14523
|
const filename = c.req.param("filename");
|
|
14342
14524
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14358,7 +14540,7 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14358
14540
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14359
14541
|
return c.text("Forbidden", 403);
|
|
14360
14542
|
}
|
|
14361
|
-
if (!
|
|
14543
|
+
if (!existsSync22(filePath)) {
|
|
14362
14544
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14363
14545
|
return c.text("Not found", 404);
|
|
14364
14546
|
}
|
|
@@ -14371,7 +14553,7 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14371
14553
|
"Cache-Control": "public, max-age=3600"
|
|
14372
14554
|
});
|
|
14373
14555
|
});
|
|
14374
|
-
|
|
14556
|
+
app39.get("/generated/:filename", (c) => {
|
|
14375
14557
|
const filename = c.req.param("filename");
|
|
14376
14558
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14377
14559
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14388,7 +14570,7 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14388
14570
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14389
14571
|
return c.text("Forbidden", 403);
|
|
14390
14572
|
}
|
|
14391
|
-
if (!
|
|
14573
|
+
if (!existsSync22(filePath)) {
|
|
14392
14574
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14393
14575
|
return c.text("Not found", 404);
|
|
14394
14576
|
}
|
|
@@ -14401,14 +14583,14 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14401
14583
|
"Cache-Control": "public, max-age=86400"
|
|
14402
14584
|
});
|
|
14403
14585
|
});
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
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);
|
|
14408
14590
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14409
14591
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14410
14592
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14411
|
-
if (BRAND_JSON_PATH &&
|
|
14593
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14412
14594
|
try {
|
|
14413
14595
|
const fullBrand = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
14414
14596
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -14428,7 +14610,7 @@ function readInstalledVersion() {
|
|
|
14428
14610
|
try {
|
|
14429
14611
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14430
14612
|
const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14431
|
-
if (!
|
|
14613
|
+
if (!existsSync22(versionFile)) return "unknown";
|
|
14432
14614
|
const content = readFileSync20(versionFile, "utf-8").trim();
|
|
14433
14615
|
return content || "unknown";
|
|
14434
14616
|
} catch {
|
|
@@ -14489,12 +14671,12 @@ function loadBrandingCache(agentSlug) {
|
|
|
14489
14671
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14490
14672
|
try {
|
|
14491
14673
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14492
|
-
if (!
|
|
14674
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14493
14675
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14494
14676
|
const accountId = account.accountId;
|
|
14495
14677
|
if (!accountId) return null;
|
|
14496
14678
|
const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14497
|
-
if (!
|
|
14679
|
+
if (!existsSync22(cachePath)) return null;
|
|
14498
14680
|
return JSON.parse(readFileSync20(cachePath, "utf-8"));
|
|
14499
14681
|
} catch {
|
|
14500
14682
|
return null;
|
|
@@ -14504,7 +14686,7 @@ function resolveDefaultSlug() {
|
|
|
14504
14686
|
try {
|
|
14505
14687
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14506
14688
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14507
|
-
if (!
|
|
14689
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14508
14690
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14509
14691
|
return account.defaultAgent || null;
|
|
14510
14692
|
} catch {
|
|
@@ -14541,7 +14723,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14541
14723
|
function escapeHtml(s) {
|
|
14542
14724
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14543
14725
|
}
|
|
14544
|
-
|
|
14726
|
+
app39.get("/", (c) => {
|
|
14545
14727
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14546
14728
|
if (isPublicHost(host)) {
|
|
14547
14729
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14549,12 +14731,12 @@ app40.get("/", (c) => {
|
|
|
14549
14731
|
}
|
|
14550
14732
|
return c.html(cachedHtml("index.html"));
|
|
14551
14733
|
});
|
|
14552
|
-
|
|
14734
|
+
app39.get("/public", (c) => {
|
|
14553
14735
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14554
14736
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14555
14737
|
return c.html(cachedHtml("public.html"));
|
|
14556
14738
|
});
|
|
14557
|
-
|
|
14739
|
+
app39.get("/chat", (c) => {
|
|
14558
14740
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14559
14741
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14560
14742
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14573,9 +14755,9 @@ async function logViewerFetch(c, next) {
|
|
|
14573
14755
|
duration_ms: Date.now() - start
|
|
14574
14756
|
});
|
|
14575
14757
|
}
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14758
|
+
app39.use("/vnc-viewer.html", logViewerFetch);
|
|
14759
|
+
app39.use("/vnc-popout.html", logViewerFetch);
|
|
14760
|
+
app39.get("/vnc-popout.html", (c) => {
|
|
14579
14761
|
let html = htmlCache.get("vnc-popout.html");
|
|
14580
14762
|
if (!html) {
|
|
14581
14763
|
html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -14588,7 +14770,7 @@ app40.get("/vnc-popout.html", (c) => {
|
|
|
14588
14770
|
}
|
|
14589
14771
|
return c.html(html);
|
|
14590
14772
|
});
|
|
14591
|
-
|
|
14773
|
+
app39.post("/api/vnc/client-event", async (c) => {
|
|
14592
14774
|
let body;
|
|
14593
14775
|
try {
|
|
14594
14776
|
body = await c.req.json();
|
|
@@ -14609,25 +14791,25 @@ app40.post("/api/vnc/client-event", async (c) => {
|
|
|
14609
14791
|
});
|
|
14610
14792
|
return c.json({ ok: true });
|
|
14611
14793
|
});
|
|
14612
|
-
|
|
14794
|
+
app39.get("/g/:slug", (c) => {
|
|
14613
14795
|
return c.html(brandedPublicHtml());
|
|
14614
14796
|
});
|
|
14615
|
-
|
|
14797
|
+
app39.get("/graph", (c) => {
|
|
14616
14798
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14617
14799
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14618
14800
|
return c.html(cachedHtml("graph.html"));
|
|
14619
14801
|
});
|
|
14620
|
-
|
|
14802
|
+
app39.get("/sessions", (c) => {
|
|
14621
14803
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14622
14804
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14623
14805
|
return c.html(cachedHtml("sessions.html"));
|
|
14624
14806
|
});
|
|
14625
|
-
|
|
14807
|
+
app39.get("/data", (c) => {
|
|
14626
14808
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14627
14809
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14628
14810
|
return c.html(cachedHtml("data.html"));
|
|
14629
14811
|
});
|
|
14630
|
-
|
|
14812
|
+
app39.get("/:slug", async (c, next) => {
|
|
14631
14813
|
const slug = c.req.param("slug");
|
|
14632
14814
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14633
14815
|
const branding = loadBrandingCache(slug);
|
|
@@ -14637,15 +14819,15 @@ app40.get("/:slug", async (c, next) => {
|
|
|
14637
14819
|
await next();
|
|
14638
14820
|
});
|
|
14639
14821
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14640
|
-
|
|
14822
|
+
app39.get("/favicon.ico", (c) => {
|
|
14641
14823
|
c.header("Cache-Control", "public, max-age=300");
|
|
14642
14824
|
return c.redirect(brandFaviconPath, 302);
|
|
14643
14825
|
});
|
|
14644
14826
|
}
|
|
14645
|
-
|
|
14827
|
+
app39.use("/*", serveStatic({ root: "./public" }));
|
|
14646
14828
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14647
14829
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14648
|
-
var httpServer = serve({ fetch:
|
|
14830
|
+
var httpServer = serve({ fetch: app39.fetch, port, hostname });
|
|
14649
14831
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14650
14832
|
{
|
|
14651
14833
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14681,7 +14863,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14681
14863
|
}
|
|
14682
14864
|
try {
|
|
14683
14865
|
const registered = [];
|
|
14684
|
-
for (const r of
|
|
14866
|
+
for (const r of app39.routes ?? []) {
|
|
14685
14867
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14686
14868
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14687
14869
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14703,7 +14885,7 @@ try {
|
|
|
14703
14885
|
}
|
|
14704
14886
|
(async () => {
|
|
14705
14887
|
try {
|
|
14706
|
-
if (!
|
|
14888
|
+
if (!existsSync22(USERS_FILE)) return;
|
|
14707
14889
|
const usersRaw = readFileSync20(USERS_FILE, "utf-8").trim();
|
|
14708
14890
|
if (!usersRaw) return;
|
|
14709
14891
|
const users = JSON.parse(usersRaw);
|
|
@@ -14720,6 +14902,9 @@ try {
|
|
|
14720
14902
|
}
|
|
14721
14903
|
})();
|
|
14722
14904
|
startGraphHealthTimer();
|
|
14905
|
+
void startFileWatcher().catch((err) => {
|
|
14906
|
+
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
14907
|
+
});
|
|
14723
14908
|
try {
|
|
14724
14909
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
14725
14910
|
console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
|
|
@@ -14738,7 +14923,7 @@ try {
|
|
|
14738
14923
|
} catch (err) {
|
|
14739
14924
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
14740
14925
|
}
|
|
14741
|
-
var configDirForWhatsApp =
|
|
14926
|
+
var configDirForWhatsApp = basename6(MAXY_DIR) || ".maxy";
|
|
14742
14927
|
var bootAccount = resolveAccount();
|
|
14743
14928
|
var bootAccountConfig = bootAccount?.config;
|
|
14744
14929
|
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
|