@rubytech/create-maxy-code 0.1.191 → 0.1.193
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/projects-guide.md +21 -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.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +35 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/PLUGIN.md +2 -0
- package/payload/platform/plugins/work/skills/execute-task/SKILL.md +101 -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 +46 -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-BoJbnn6d.js +1 -0
- package/payload/server/public/assets/{Checkbox-g2WZRfCt.js → Checkbox-G-kyM1P1.js} +1 -1
- package/payload/server/public/assets/admin-B-GDNkoN.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-BGgdXdD2.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BpD-1G1V.js → blockDiagram-DXYQGD6D-DKWoL4Rp.js} +1 -1
- package/payload/server/public/assets/{brand-BGvv6AYI.js → brand-CYcGHhlS.js} +1 -1
- package/payload/server/public/assets/{brand-BQW2DYy_.css → brand-MbpD2Bhr.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CFl9Dr6U.js → c4Diagram-AHTNJAMY-Ca6rs6F4.js} +1 -1
- package/payload/server/public/assets/channel-BwsV7WTV.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-DcdMZImV.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-9FSP-c1z.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-CC1QpEvA.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-o1b70dEE.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-OTvNug7K.js → chunk-5PVQY5BW-C7VCYRz9.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-B8d5xj_4.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-BNllMoi_.js → chunk-ENJZ2VHE-SSbr4n2X.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-Cgj9YSpX.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-DNEEcCqI.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-DuaoK83q.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DF-6QHx4.js → chunk-X2U36JSP-CzMp0dpq.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-B2wBDwSa.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-B0ACvZCZ.js → chunk-ZZ45TVLE-DkyF7XKW.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CEWNfHVo.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BBjzRxux.js +1 -0
- package/payload/server/public/assets/clone-CXtSonnn.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-AGj1P0p4.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-D-Ux4uwL.js → dagre-KV5264BT-Cnrxcu6A.js} +1 -1
- package/payload/server/public/assets/data-Bg0Frxt3.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-D-MOMikl.js → diagram-5BDNPKRD-gyFYSx73.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DKdFcnhf.js → diagram-G4DWMVQ6-DFmZEv5C.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-ajamR766.js → diagram-MMDJMWI5-DA4qbuEW.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-D2Pbk2Kk.js → diagram-TYMM5635-D4n-8gig.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-v3o948pk.js → erDiagram-SMLLAGMA-CigRMjF1.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-ClS27acA.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-Dybzs-Sw.js → ganttDiagram-T4ZO3ILL-Dr1IulXe.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-lwLibdPs.js} +1 -1
- package/payload/server/public/assets/graph-CpozZ74I.js +51 -0
- package/payload/server/public/assets/graph-labels-C2y666R0.js +1 -0
- package/payload/server/public/assets/{graphlib-DvH_spaA.js → graphlib-DBvoJMrc.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-g3gYW7Qm.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-D4kReEIV.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-BnteQRQ0.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-ymMAQVdm.js → journeyDiagram-VCZTEJTY-CXu6hLyJ.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-_NX9hNK3.js → kanban-definition-6JOO6SKY-CGDW2jle.js} +1 -1
- package/payload/server/public/assets/{line-Dz7zKWX-.js → line-pdg5hxC3.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-o3lIIK3Z.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-gSoFkVoN.js → mermaid.core-DLR6Q3rV.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-QuIyK2bd.js → mindmap-definition-QFDTVHPH-CH4cB0Dn.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-Ba4voL_Y.js} +1 -1
- package/payload/server/public/assets/public-C8mil9h0.js +35 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wK1jwWo5.js → quadrantDiagram-34T5L4WZ-Cqn2xehe.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-DLfNx99l.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-nGAM-YLQ.js → sankeyDiagram-XADWPNL6-uck_V-cb.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-SMfUCwBH.js → sequenceDiagram-FGHM5R23-DmQalqud.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CYKXFirH.js → stateDiagram-FHFEXIEX-DUdWeVRa.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DNTpFwdy.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DethbNFa.js → timeline-definition-GMOUNBTQ-BgL1wM5n.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-BLpVlOgm.js +5 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BUlJTe9Z.js → vennDiagram-DHZGUBPP-7FHjIqPi.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-BHzo4V1J.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Cav10l-Z.js → xychartDiagram-5P7HB3ND-DtuWhqwh.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +478 -456
- package/payload/server/public/assets/admin-DFxXLXfg.js +0 -216
- package/payload/server/public/assets/architecture-YZFGNWBL-COhEvUpo.js +0 -1
- package/payload/server/public/assets/channel-BTEFjudQ.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CcIGcm29.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CWh_0JsP.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-ClkdniKF.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-kjJetfh2.js +0 -1
- package/payload/server/public/assets/clone-BllVm2iY.js +0 -1
- package/payload/server/public/assets/data-DtYcqL1G.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DeTNsAO0.js +0 -1
- package/payload/server/public/assets/graph-C-XPyGsO.js +0 -1
- package/payload/server/public/assets/graph-labels-CZin3myX.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DJJ9GlS6.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C2FeU8nE.js +0 -2
- package/payload/server/public/assets/lib-BEvO-mE0.js +0 -33
- package/payload/server/public/assets/packet-4T2RLAQJ-CGbvGkvF.js +0 -1
- package/payload/server/public/assets/page-CKlvbjKn.js +0 -1
- package/payload/server/public/assets/page-DSj21hpG.js +0 -51
- package/payload/server/public/assets/pie-ZZUOXDRM-BZy8rjFn.js +0 -1
- package/payload/server/public/assets/public-BnS9zREj.js +0 -7
- package/payload/server/public/assets/radar-PYXPWWZC-DcfWIVXr.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B9ZwM8kx.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-3WugwVdj.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cf5mDLlu.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-Bv4md4b3.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
- /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
- /package/payload/server/public/assets/{dist-Bd4S37oi.js → dist-BzAsli7o.js} +0 -0
- /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
- /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
- /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-DKRO8IF-.js → rough.esm-DRO6hWPh.js} +0 -0
- /package/payload/server/public/assets/{src-B6XdH6xq.js → src-CWiyyVfn.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -815,8 +815,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
815
815
|
};
|
|
816
816
|
|
|
817
817
|
// server/index.ts
|
|
818
|
-
import { readFileSync as readFileSync20, existsSync as
|
|
819
|
-
import { resolve as
|
|
818
|
+
import { readFileSync as readFileSync20, existsSync as existsSync21, watchFile } from "fs";
|
|
819
|
+
import { resolve as resolve23, join as join15, basename as basename6 } from "path";
|
|
820
820
|
import { homedir as homedir2 } from "os";
|
|
821
821
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
822
822
|
|
|
@@ -1274,7 +1274,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1274
1274
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1275
1275
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1276
1276
|
const timer2 = new Promise(
|
|
1277
|
-
(
|
|
1277
|
+
(resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
|
|
1278
1278
|
);
|
|
1279
1279
|
const result = await Promise.race([
|
|
1280
1280
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1402,11 +1402,11 @@ async function createWaSocket(opts) {
|
|
|
1402
1402
|
return sock;
|
|
1403
1403
|
}
|
|
1404
1404
|
async function waitForConnection(sock) {
|
|
1405
|
-
return new Promise((
|
|
1405
|
+
return new Promise((resolve24, reject) => {
|
|
1406
1406
|
const handler = (update) => {
|
|
1407
1407
|
if (update.connection === "open") {
|
|
1408
1408
|
sock.ev.off("connection.update", handler);
|
|
1409
|
-
|
|
1409
|
+
resolve24();
|
|
1410
1410
|
}
|
|
1411
1411
|
if (update.connection === "close") {
|
|
1412
1412
|
sock.ev.off("connection.update", handler);
|
|
@@ -1520,14 +1520,14 @@ ${inspected}`;
|
|
|
1520
1520
|
return inspect2(err, INSPECT_OPTS2);
|
|
1521
1521
|
}
|
|
1522
1522
|
function withTimeout(label, promise, timeoutMs) {
|
|
1523
|
-
return new Promise((
|
|
1523
|
+
return new Promise((resolve24, reject) => {
|
|
1524
1524
|
const timer2 = setTimeout(() => {
|
|
1525
1525
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1526
1526
|
}, timeoutMs);
|
|
1527
1527
|
promise.then(
|
|
1528
1528
|
(value) => {
|
|
1529
1529
|
clearTimeout(timer2);
|
|
1530
|
-
|
|
1530
|
+
resolve24(value);
|
|
1531
1531
|
},
|
|
1532
1532
|
(err) => {
|
|
1533
1533
|
clearTimeout(timer2);
|
|
@@ -2062,8 +2062,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2062
2062
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2063
2063
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2064
2064
|
let release;
|
|
2065
|
-
const mine = new Promise((
|
|
2066
|
-
release =
|
|
2065
|
+
const mine = new Promise((resolve24) => {
|
|
2066
|
+
release = resolve24;
|
|
2067
2067
|
});
|
|
2068
2068
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2069
2069
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3099,11 +3099,11 @@ async function connectWithReconnect(conn) {
|
|
|
3099
3099
|
console.error(
|
|
3100
3100
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3101
3101
|
);
|
|
3102
|
-
await new Promise((
|
|
3103
|
-
const timer2 = setTimeout(
|
|
3102
|
+
await new Promise((resolve24) => {
|
|
3103
|
+
const timer2 = setTimeout(resolve24, delay);
|
|
3104
3104
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3105
3105
|
clearTimeout(timer2);
|
|
3106
|
-
|
|
3106
|
+
resolve24();
|
|
3107
3107
|
}, { once: true });
|
|
3108
3108
|
});
|
|
3109
3109
|
}
|
|
@@ -3111,16 +3111,16 @@ async function connectWithReconnect(conn) {
|
|
|
3111
3111
|
}
|
|
3112
3112
|
}
|
|
3113
3113
|
function waitForDisconnectEvent(conn) {
|
|
3114
|
-
return new Promise((
|
|
3114
|
+
return new Promise((resolve24) => {
|
|
3115
3115
|
if (!conn.sock) {
|
|
3116
|
-
|
|
3116
|
+
resolve24();
|
|
3117
3117
|
return;
|
|
3118
3118
|
}
|
|
3119
3119
|
const sock = conn.sock;
|
|
3120
3120
|
const handler = (update) => {
|
|
3121
3121
|
if (update.connection === "close") {
|
|
3122
3122
|
sock.ev.off("connection.update", handler);
|
|
3123
|
-
|
|
3123
|
+
resolve24();
|
|
3124
3124
|
}
|
|
3125
3125
|
};
|
|
3126
3126
|
sock.ev.on("connection.update", handler);
|
|
@@ -3382,8 +3382,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3382
3382
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3383
3383
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3384
3384
|
let resolvePending;
|
|
3385
|
-
const sttPending = new Promise((
|
|
3386
|
-
resolvePending =
|
|
3385
|
+
const sttPending = new Promise((resolve24) => {
|
|
3386
|
+
resolvePending = resolve24;
|
|
3387
3387
|
});
|
|
3388
3388
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3389
3389
|
try {
|
|
@@ -3787,20 +3787,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
3787
3787
|
|
|
3788
3788
|
// server/routes/health.ts
|
|
3789
3789
|
function checkPort(port2, timeoutMs = 500) {
|
|
3790
|
-
return new Promise((
|
|
3790
|
+
return new Promise((resolve24) => {
|
|
3791
3791
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
3792
3792
|
socket.setTimeout(timeoutMs);
|
|
3793
3793
|
socket.once("connect", () => {
|
|
3794
3794
|
socket.destroy();
|
|
3795
|
-
|
|
3795
|
+
resolve24(true);
|
|
3796
3796
|
});
|
|
3797
3797
|
socket.once("error", () => {
|
|
3798
3798
|
socket.destroy();
|
|
3799
|
-
|
|
3799
|
+
resolve24(false);
|
|
3800
3800
|
});
|
|
3801
3801
|
socket.once("timeout", () => {
|
|
3802
3802
|
socket.destroy();
|
|
3803
|
-
|
|
3803
|
+
resolve24(false);
|
|
3804
3804
|
});
|
|
3805
3805
|
});
|
|
3806
3806
|
}
|
|
@@ -4536,12 +4536,12 @@ async function dispatchOnce(input) {
|
|
|
4536
4536
|
});
|
|
4537
4537
|
if (!entry) return { error: "spawn-failed" };
|
|
4538
4538
|
entry.lastInboundAt = Date.now();
|
|
4539
|
-
let
|
|
4539
|
+
let resolve24;
|
|
4540
4540
|
const turnPromise = new Promise((r) => {
|
|
4541
|
-
|
|
4541
|
+
resolve24 = r;
|
|
4542
4542
|
});
|
|
4543
4543
|
const listener = (text) => {
|
|
4544
|
-
|
|
4544
|
+
resolve24(text);
|
|
4545
4545
|
};
|
|
4546
4546
|
entry.subscribers.add(listener);
|
|
4547
4547
|
const writeOk = await writeInput(entry, input.text);
|
|
@@ -4983,8 +4983,8 @@ async function startLogin(opts) {
|
|
|
4983
4983
|
resetActiveLogin(accountId);
|
|
4984
4984
|
let resolveQr = null;
|
|
4985
4985
|
let rejectQr = null;
|
|
4986
|
-
const qrPromise = new Promise((
|
|
4987
|
-
resolveQr =
|
|
4986
|
+
const qrPromise = new Promise((resolve24, reject) => {
|
|
4987
|
+
resolveQr = resolve24;
|
|
4988
4988
|
rejectQr = reject;
|
|
4989
4989
|
});
|
|
4990
4990
|
const qrTimer = setTimeout(
|
|
@@ -7245,24 +7245,6 @@ function openResumeStreamLog(accountId, sessionId) {
|
|
|
7245
7245
|
}
|
|
7246
7246
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
7247
7247
|
}
|
|
7248
|
-
var healPending = /* @__PURE__ */ new Map();
|
|
7249
|
-
function markHealPending(accountId, attachmentId) {
|
|
7250
|
-
let set = healPending.get(accountId);
|
|
7251
|
-
if (!set) {
|
|
7252
|
-
set = /* @__PURE__ */ new Set();
|
|
7253
|
-
healPending.set(accountId, set);
|
|
7254
|
-
}
|
|
7255
|
-
set.add(attachmentId);
|
|
7256
|
-
}
|
|
7257
|
-
function clearHealPending(accountId, attachmentId) {
|
|
7258
|
-
const set = healPending.get(accountId);
|
|
7259
|
-
if (!set) return;
|
|
7260
|
-
set.delete(attachmentId);
|
|
7261
|
-
if (set.size === 0) healPending.delete(accountId);
|
|
7262
|
-
}
|
|
7263
|
-
function isHealPending(accountId, attachmentId) {
|
|
7264
|
-
return healPending.get(accountId)?.has(attachmentId) ?? false;
|
|
7265
|
-
}
|
|
7266
7248
|
function validateAndShapeAttachments(raws, conversationAccountId, sessionId, messageId, streamLogPath) {
|
|
7267
7249
|
const chips = [];
|
|
7268
7250
|
let valid = 0;
|
|
@@ -7640,17 +7622,14 @@ app11.post("/:id/resume", async (c) => {
|
|
|
7640
7622
|
textOffset: c2.textOffset
|
|
7641
7623
|
};
|
|
7642
7624
|
if (!c2.artefactAttachmentId || !c2.artefactMimeType || !c2.artefactTitle) return base;
|
|
7643
|
-
markHealPending(accountId, c2.artefactAttachmentId);
|
|
7644
7625
|
try {
|
|
7645
7626
|
const dataObj = JSON.parse(c2.data);
|
|
7646
7627
|
const bytesPick = pickComponentBytes(dataObj);
|
|
7647
7628
|
if (!bytesPick) {
|
|
7648
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7649
7629
|
return base;
|
|
7650
7630
|
}
|
|
7651
7631
|
const filename = bytesPick.mimeType === "text/html" ? `${c2.artefactTitle}.html` : `${c2.artefactTitle}.md`;
|
|
7652
7632
|
await storeComponentArtefact(accountId, c2.artefactAttachmentId, bytesPick.mimeType, bytesPick.content, filename);
|
|
7653
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7654
7633
|
streamLogPath.write(
|
|
7655
7634
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} outcome=ok
|
|
7656
7635
|
`
|
|
@@ -7662,7 +7641,6 @@ app11.post("/:id/resume", async (c) => {
|
|
|
7662
7641
|
artefactTitle: c2.artefactTitle
|
|
7663
7642
|
};
|
|
7664
7643
|
} catch (writeErr) {
|
|
7665
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7666
7644
|
const reason2 = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
7667
7645
|
streamLogPath.write(
|
|
7668
7646
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} outcome=disk-fail reason=${JSON.stringify(reason2.slice(0, 200))}
|
|
@@ -8769,11 +8747,23 @@ async function cascadeDeleteDocument(params) {
|
|
|
8769
8747
|
// app/lib/file-index.ts
|
|
8770
8748
|
import * as fsp from "fs/promises";
|
|
8771
8749
|
import { resolve as resolve13, relative as relative2, join as join11, basename as basename3, extname as extname2, sep as sep3 } from "path";
|
|
8750
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
8772
8751
|
import { execFile as execFile2 } from "child_process";
|
|
8773
8752
|
import { promisify as promisify2 } from "util";
|
|
8774
8753
|
var execFileAsync2 = promisify2(execFile2);
|
|
8775
8754
|
var CONTENT_CAP = 1e5;
|
|
8776
|
-
var
|
|
8755
|
+
var OCR_TIMEOUT_MS = 3e4;
|
|
8756
|
+
var OCR_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8757
|
+
".png",
|
|
8758
|
+
".jpg",
|
|
8759
|
+
".jpeg",
|
|
8760
|
+
".gif",
|
|
8761
|
+
".webp",
|
|
8762
|
+
".tiff",
|
|
8763
|
+
".tif",
|
|
8764
|
+
".bmp"
|
|
8765
|
+
]);
|
|
8766
|
+
var RECONCILE_DEBOUNCE_MS = 5 * 60 * 1e3;
|
|
8777
8767
|
var lastReconcileAt = /* @__PURE__ */ new Map();
|
|
8778
8768
|
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8779
8769
|
".txt",
|
|
@@ -8826,26 +8816,60 @@ async function extractPdf(absolute) {
|
|
|
8826
8816
|
});
|
|
8827
8817
|
return stdout.trim();
|
|
8828
8818
|
}
|
|
8819
|
+
async function ocrPdf(absolute) {
|
|
8820
|
+
const outPdf = join11(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
8821
|
+
try {
|
|
8822
|
+
await execFileAsync2(
|
|
8823
|
+
"ocrmypdf",
|
|
8824
|
+
["--skip-text", "--quiet", "--output-type", "pdf", absolute, outPdf],
|
|
8825
|
+
{ maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
|
|
8826
|
+
);
|
|
8827
|
+
const { stdout } = await execFileAsync2("pdftotext", [outPdf, "-"], {
|
|
8828
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
8829
|
+
timeout: OCR_TIMEOUT_MS
|
|
8830
|
+
});
|
|
8831
|
+
return stdout.trim();
|
|
8832
|
+
} finally {
|
|
8833
|
+
await fsp.rm(outPdf, { force: true });
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
async function ocrImage(absolute) {
|
|
8837
|
+
const { stdout } = await execFileAsync2(
|
|
8838
|
+
"tesseract",
|
|
8839
|
+
[absolute, "-", "-l", "eng", "--psm", "3"],
|
|
8840
|
+
{ maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
|
|
8841
|
+
);
|
|
8842
|
+
return stdout.trim();
|
|
8843
|
+
}
|
|
8829
8844
|
function stripHtml(html) {
|
|
8830
8845
|
return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8831
8846
|
}
|
|
8832
8847
|
async function extractFileContent(absolute) {
|
|
8833
8848
|
const ext = extname2(absolute).toLowerCase();
|
|
8834
8849
|
try {
|
|
8835
|
-
if (ext === ".pdf")
|
|
8850
|
+
if (ext === ".pdf") {
|
|
8851
|
+
const text = (await extractPdf(absolute)).slice(0, CONTENT_CAP);
|
|
8852
|
+
if (text.length > 0) return { content: text, route: "pdftotext" };
|
|
8853
|
+
const ocred = (await ocrPdf(absolute)).slice(0, CONTENT_CAP);
|
|
8854
|
+
return ocred.length > 0 ? { content: ocred, route: "ocr-pdf" } : { content: "", route: "name-only" };
|
|
8855
|
+
}
|
|
8836
8856
|
if (HTML_EXTENSIONS.has(ext)) {
|
|
8837
8857
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8838
|
-
return stripHtml(raw).slice(0, CONTENT_CAP);
|
|
8858
|
+
return { content: stripHtml(raw).slice(0, CONTENT_CAP), route: "html" };
|
|
8839
8859
|
}
|
|
8840
8860
|
if (TEXT_EXTENSIONS.has(ext)) {
|
|
8841
8861
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8842
|
-
return raw.slice(0, CONTENT_CAP);
|
|
8862
|
+
return { content: raw.slice(0, CONTENT_CAP), route: "text" };
|
|
8843
8863
|
}
|
|
8844
|
-
|
|
8864
|
+
if (OCR_IMAGE_EXTENSIONS.has(ext)) {
|
|
8865
|
+
const ocred = (await ocrImage(absolute)).slice(0, CONTENT_CAP);
|
|
8866
|
+
return ocred.length > 0 ? { content: ocred, route: "ocr-image" } : { content: "", route: "name-only" };
|
|
8867
|
+
}
|
|
8868
|
+
return { content: "", route: "name-only" };
|
|
8845
8869
|
} catch (err) {
|
|
8846
8870
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8847
8871
|
console.error(`[file-index] extract-failed path="${relative2(DATA_ROOT, absolute)}" err="${msg}"`);
|
|
8848
|
-
return "";
|
|
8872
|
+
return { content: "", route: "name-only" };
|
|
8849
8873
|
}
|
|
8850
8874
|
}
|
|
8851
8875
|
async function readDisplayName(absolute) {
|
|
@@ -8909,9 +8933,86 @@ async function upsertFileArtifact(session, f) {
|
|
|
8909
8933
|
f
|
|
8910
8934
|
);
|
|
8911
8935
|
}
|
|
8936
|
+
async function linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolutePath) {
|
|
8937
|
+
const res = await session.run(
|
|
8938
|
+
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
8939
|
+
OPTIONAL MATCH (d:KnowledgeDocument {accountId: $accountId, sourcePath: $absolutePath})
|
|
8940
|
+
WHERE NOT d:Trashed
|
|
8941
|
+
FOREACH (_ IN CASE WHEN d IS NULL THEN [] ELSE [1] END |
|
|
8942
|
+
MERGE (f)-[:INGESTED_AS]->(d))
|
|
8943
|
+
RETURN elementId(d) AS docId`,
|
|
8944
|
+
{ accountId, relativePath, absolutePath }
|
|
8945
|
+
);
|
|
8946
|
+
const docId = res.records[0]?.get("docId");
|
|
8947
|
+
if (docId) {
|
|
8948
|
+
console.error(
|
|
8949
|
+
`[file-index] linked-kd account=${accountId} relativePath="${relativePath}" docId=${docId.slice(0, 12)}`
|
|
8950
|
+
);
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
async function findLinkedKnowledgeDocs(session, accountId, relativePaths) {
|
|
8954
|
+
if (relativePaths.length === 0) return [];
|
|
8955
|
+
const res = await session.run(
|
|
8956
|
+
`MATCH (f:FileArtifact {accountId: $accountId})-[:INGESTED_AS]->(d:KnowledgeDocument)
|
|
8957
|
+
WHERE f.relativePath IN $relativePaths AND NOT d:Trashed
|
|
8958
|
+
OPTIONAL MATCH (d)-[:HAS_SECTION]->(s:Section)
|
|
8959
|
+
OPTIONAL MATCH (s)-[:HAS_CHUNK]->(c:Chunk)
|
|
8960
|
+
WITH d, collect(DISTINCT s) AS ss, collect(DISTINCT c) AS cc
|
|
8961
|
+
RETURN elementId(d) AS docId,
|
|
8962
|
+
[x IN ss WHERE x IS NOT NULL | elementId(x)] AS sectionIds,
|
|
8963
|
+
[x IN cc WHERE x IS NOT NULL | elementId(x)] AS chunkIds`,
|
|
8964
|
+
{ accountId, relativePaths }
|
|
8965
|
+
);
|
|
8966
|
+
return res.records.map((rec) => ({
|
|
8967
|
+
docId: rec.get("docId"),
|
|
8968
|
+
sectionIds: rec.get("sectionIds") ?? [],
|
|
8969
|
+
chunkIds: rec.get("chunkIds") ?? []
|
|
8970
|
+
}));
|
|
8971
|
+
}
|
|
8972
|
+
async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths) {
|
|
8973
|
+
const linked = await findLinkedKnowledgeDocs(session, accountId, relativePaths);
|
|
8974
|
+
let kds = 0, sections = 0, chunks = 0;
|
|
8975
|
+
for (const { docId, sectionIds, chunkIds } of linked) {
|
|
8976
|
+
try {
|
|
8977
|
+
await trashNode({
|
|
8978
|
+
session,
|
|
8979
|
+
accountId,
|
|
8980
|
+
elementId: docId,
|
|
8981
|
+
by: "file-index:cascade",
|
|
8982
|
+
reason: "physical file removed from FileArtifact index"
|
|
8983
|
+
});
|
|
8984
|
+
kds++;
|
|
8985
|
+
for (const sid of sectionIds) {
|
|
8986
|
+
await trashNode({
|
|
8987
|
+
session,
|
|
8988
|
+
accountId,
|
|
8989
|
+
elementId: sid,
|
|
8990
|
+
by: `file-index:cascade:from-${docId}`,
|
|
8991
|
+
reason: `cascade from KnowledgeDocument ${docId}`
|
|
8992
|
+
});
|
|
8993
|
+
sections++;
|
|
8994
|
+
}
|
|
8995
|
+
for (const cid of chunkIds) {
|
|
8996
|
+
await trashNode({
|
|
8997
|
+
session,
|
|
8998
|
+
accountId,
|
|
8999
|
+
elementId: cid,
|
|
9000
|
+
by: `file-index:cascade:from-${docId}`,
|
|
9001
|
+
reason: `cascade from KnowledgeDocument ${docId}`
|
|
9002
|
+
});
|
|
9003
|
+
chunks++;
|
|
9004
|
+
}
|
|
9005
|
+
} catch (err) {
|
|
9006
|
+
console.error(
|
|
9007
|
+
`[file-index] cascade-trash-failed account=${accountId} docId=${docId.slice(0, 12)} err="${err.message}"`
|
|
9008
|
+
);
|
|
9009
|
+
}
|
|
9010
|
+
}
|
|
9011
|
+
return { kds, sections, chunks };
|
|
9012
|
+
}
|
|
8912
9013
|
async function buildArtifact(accountId, wf, embed2) {
|
|
8913
9014
|
const name = basename3(wf.absolute);
|
|
8914
|
-
const content = await extractFileContent(wf.absolute);
|
|
9015
|
+
const { content, route } = await extractFileContent(wf.absolute);
|
|
8915
9016
|
const displayName = await readDisplayName(wf.absolute);
|
|
8916
9017
|
const embedInput = `${name}
|
|
8917
9018
|
${content}`.slice(0, CONTENT_CAP);
|
|
@@ -8923,7 +9024,7 @@ ${content}`.slice(0, CONTENT_CAP);
|
|
|
8923
9024
|
console.error(`[file-index] embed-failed path="${wf.relativePath}" err="${err.message}"`);
|
|
8924
9025
|
}
|
|
8925
9026
|
console.error(
|
|
8926
|
-
`[file-index] index-file account=${accountId} path="${wf.relativePath}" chars=${content.length} embed-ms=${Date.now() - embedStart}`
|
|
9027
|
+
`[file-index] index-file account=${accountId} path="${wf.relativePath}" extractor=${route} chars=${content.length} embed-ms=${Date.now() - embedStart}`
|
|
8927
9028
|
);
|
|
8928
9029
|
return {
|
|
8929
9030
|
accountId,
|
|
@@ -8982,14 +9083,29 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
8982
9083
|
const unchanged = prior && prior.sizeBytes === wf.sizeBytes && prior.modifiedAt === wf.modifiedAt && prior.hasEmbedding;
|
|
8983
9084
|
if (unchanged) {
|
|
8984
9085
|
skipped++;
|
|
8985
|
-
|
|
9086
|
+
} else {
|
|
9087
|
+
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9088
|
+
upserted++;
|
|
8986
9089
|
}
|
|
8987
|
-
await
|
|
8988
|
-
upserted++;
|
|
9090
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, wf.relativePath, wf.absolute);
|
|
8989
9091
|
}
|
|
8990
9092
|
let pruned = 0;
|
|
9093
|
+
let cascadeKds = 0, cascadeSections = 0, cascadeChunks = 0;
|
|
8991
9094
|
if (clean) {
|
|
8992
9095
|
const foundPaths = walked.map((w) => w.relativePath);
|
|
9096
|
+
const goneRes = await session.run(
|
|
9097
|
+
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
9098
|
+
WHERE NOT f.relativePath IN $foundPaths
|
|
9099
|
+
RETURN f.relativePath AS rp`,
|
|
9100
|
+
{ accountId, foundPaths }
|
|
9101
|
+
);
|
|
9102
|
+
const gonePaths = goneRes.records.map((r) => r.get("rp"));
|
|
9103
|
+
if (gonePaths.length > 0) {
|
|
9104
|
+
const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, gonePaths);
|
|
9105
|
+
cascadeKds = cascade.kds;
|
|
9106
|
+
cascadeSections = cascade.sections;
|
|
9107
|
+
cascadeChunks = cascade.chunks;
|
|
9108
|
+
}
|
|
8993
9109
|
const pruneRes = await session.run(
|
|
8994
9110
|
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
8995
9111
|
WHERE NOT f.relativePath IN $foundPaths
|
|
@@ -9001,7 +9117,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
9001
9117
|
pruned = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9002
9118
|
}
|
|
9003
9119
|
console.error(
|
|
9004
|
-
`[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} clean=${clean} ms=${Date.now() - t0}`
|
|
9120
|
+
`[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} cascade-kds=${cascadeKds} cascade-sections=${cascadeSections} cascade-chunks=${cascadeChunks} clean=${clean} ms=${Date.now() - t0}`
|
|
9005
9121
|
);
|
|
9006
9122
|
return { walked: walked.length, upserted, skipped, pruned };
|
|
9007
9123
|
});
|
|
@@ -9030,10 +9146,12 @@ async function indexFile(accountId, relativePath, opts) {
|
|
|
9030
9146
|
modifiedAt: st.mtime.toISOString()
|
|
9031
9147
|
};
|
|
9032
9148
|
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9149
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolute);
|
|
9033
9150
|
});
|
|
9034
9151
|
}
|
|
9035
9152
|
async function dropFileIndex(accountId, relativePath, opts) {
|
|
9036
9153
|
await withSession(opts, async (session) => {
|
|
9154
|
+
const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, [relativePath]);
|
|
9037
9155
|
const res = await session.run(
|
|
9038
9156
|
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
9039
9157
|
DETACH DELETE f
|
|
@@ -9042,7 +9160,9 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
9042
9160
|
);
|
|
9043
9161
|
const c = res.records[0]?.get("dropped");
|
|
9044
9162
|
const dropped = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9045
|
-
console.error(
|
|
9163
|
+
console.error(
|
|
9164
|
+
`[file-index] drop account=${accountId} path="${relativePath}" dropped=${dropped} cascade-kds=${cascade.kds} cascade-sections=${cascade.sections} cascade-chunks=${cascade.chunks}`
|
|
9165
|
+
);
|
|
9046
9166
|
});
|
|
9047
9167
|
}
|
|
9048
9168
|
|
|
@@ -9139,7 +9259,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
9139
9259
|
var app15 = new Hono();
|
|
9140
9260
|
app15.get("/", requireAdminSession, async (c) => {
|
|
9141
9261
|
const cacheKey = c.var.cacheKey;
|
|
9142
|
-
|
|
9262
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9263
|
+
if (!accountId) {
|
|
9143
9264
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
9144
9265
|
return c.json({ error: "Account not found for session" }, 401);
|
|
9145
9266
|
}
|
|
@@ -9152,17 +9273,26 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9152
9273
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9153
9274
|
}
|
|
9154
9275
|
const { absolute, relative: relPath2 } = resolution;
|
|
9276
|
+
if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9277
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9278
|
+
return c.json({ error: "Not found" }, 404);
|
|
9279
|
+
}
|
|
9155
9280
|
try {
|
|
9156
9281
|
const info = await stat4(absolute);
|
|
9157
9282
|
if (!info.isDirectory()) {
|
|
9158
9283
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
9159
9284
|
}
|
|
9160
9285
|
const names = await readdir3(absolute);
|
|
9286
|
+
const segs = relPath2.split("/").filter(Boolean);
|
|
9287
|
+
const isAccountParent = segs.length === 1 && (segs[0] === "accounts" || segs[0] === "uploads");
|
|
9161
9288
|
const entries = [];
|
|
9162
9289
|
for (const name of names) {
|
|
9163
9290
|
if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
9164
9291
|
continue;
|
|
9165
9292
|
}
|
|
9293
|
+
if (isAccountParent && UUID_RE3.test(name) && name !== accountId) {
|
|
9294
|
+
continue;
|
|
9295
|
+
}
|
|
9166
9296
|
try {
|
|
9167
9297
|
const entryPath = join12(absolute, name);
|
|
9168
9298
|
const s = await stat4(entryPath);
|
|
@@ -9340,6 +9470,10 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9340
9470
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9341
9471
|
}
|
|
9342
9472
|
const { absolute, relative: relPath2 } = resolution;
|
|
9473
|
+
if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9474
|
+
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9475
|
+
return c.json({ error: "Not found" }, 404);
|
|
9476
|
+
}
|
|
9343
9477
|
const base = basename4(absolute);
|
|
9344
9478
|
const segments = relPath2.split("/").filter(Boolean);
|
|
9345
9479
|
if (base === "account.json" || segments.includes(".git")) {
|
|
@@ -11397,126 +11531,14 @@ var WRITE_CYPHER = `
|
|
|
11397
11531
|
var graph_default_view_default = app21;
|
|
11398
11532
|
|
|
11399
11533
|
// server/routes/admin/sidebar-artefacts.ts
|
|
11400
|
-
import
|
|
11401
|
-
import {
|
|
11402
|
-
import { resolve as resolve16, relative as relative4, isAbsolute, sep as sep6 } from "path";
|
|
11534
|
+
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
11535
|
+
import { resolve as resolve15, relative as relative3, isAbsolute, sep as sep5, basename as basename5 } from "path";
|
|
11403
11536
|
import { existsSync as existsSync16 } from "fs";
|
|
11404
|
-
|
|
11405
|
-
// app/lib/doc-source-resolve.ts
|
|
11406
|
-
import { readdirSync as readdirSync8, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
11407
|
-
import { relative as relative3, resolve as resolve15, sep as sep5 } from "path";
|
|
11408
|
-
function containedFile(absPath, root) {
|
|
11409
|
-
try {
|
|
11410
|
-
const real = realpathSync5(absPath);
|
|
11411
|
-
const rootReal = realpathSync5(root);
|
|
11412
|
-
if (real !== rootReal && !real.startsWith(rootReal + sep5)) return null;
|
|
11413
|
-
return statSync7(real).isFile() ? real : null;
|
|
11414
|
-
} catch {
|
|
11415
|
-
return null;
|
|
11416
|
-
}
|
|
11417
|
-
}
|
|
11418
|
-
function dataFileInDir(dir) {
|
|
11419
|
-
let entries;
|
|
11420
|
-
try {
|
|
11421
|
-
entries = readdirSync8(dir, { withFileTypes: true }).flatMap((e) => e.isFile() ? [e.name] : []);
|
|
11422
|
-
} catch {
|
|
11423
|
-
return null;
|
|
11424
|
-
}
|
|
11425
|
-
const file = entries.find((e) => !e.endsWith(".meta.json"));
|
|
11426
|
-
return file ? resolve15(dir, file) : null;
|
|
11427
|
-
}
|
|
11428
|
-
function mapToDownloadRoot(absPath, roots) {
|
|
11429
|
-
const underData = containedFile(absPath, roots.dataRoot);
|
|
11430
|
-
if (underData) {
|
|
11431
|
-
return { root: "data", relPath: relative3(realpathSync5(roots.dataRoot), underData), absReal: underData };
|
|
11432
|
-
}
|
|
11433
|
-
if (roots.claudeUploadsRoot) {
|
|
11434
|
-
const underClaude = containedFile(absPath, roots.claudeUploadsRoot);
|
|
11435
|
-
if (underClaude) {
|
|
11436
|
-
return {
|
|
11437
|
-
root: "claude-uploads",
|
|
11438
|
-
relPath: relative3(realpathSync5(roots.claudeUploadsRoot), underClaude),
|
|
11439
|
-
absReal: underClaude
|
|
11440
|
-
};
|
|
11441
|
-
}
|
|
11442
|
-
}
|
|
11443
|
-
return null;
|
|
11444
|
-
}
|
|
11445
|
-
function resolveDocDownload(input, roots) {
|
|
11446
|
-
const { accountId, attachmentId, name, sourcePath, sourceType } = input;
|
|
11447
|
-
if (sourcePath) {
|
|
11448
|
-
const mapped = mapToDownloadRoot(sourcePath, roots);
|
|
11449
|
-
if (mapped) {
|
|
11450
|
-
return { ok: true, absPath: mapped.absReal, root: mapped.root, relPath: mapped.relPath, via: "stored" };
|
|
11451
|
-
}
|
|
11452
|
-
}
|
|
11453
|
-
if (attachmentId) {
|
|
11454
|
-
const uploadsDir = resolve15(roots.attachmentsRoot, accountId, attachmentId);
|
|
11455
|
-
const file = dataFileInDir(uploadsDir);
|
|
11456
|
-
if (file) {
|
|
11457
|
-
const real = containedFile(file, roots.dataRoot);
|
|
11458
|
-
if (real) {
|
|
11459
|
-
return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "uploads" };
|
|
11460
|
-
}
|
|
11461
|
-
}
|
|
11462
|
-
}
|
|
11463
|
-
if (attachmentId && roots.claudeUploadsRoot) {
|
|
11464
|
-
const claudeDir = resolve15(roots.claudeUploadsRoot, attachmentId);
|
|
11465
|
-
const file = dataFileInDir(claudeDir);
|
|
11466
|
-
if (file) {
|
|
11467
|
-
const real = containedFile(file, roots.claudeUploadsRoot);
|
|
11468
|
-
if (real) {
|
|
11469
|
-
return {
|
|
11470
|
-
ok: true,
|
|
11471
|
-
absPath: real,
|
|
11472
|
-
root: "claude-uploads",
|
|
11473
|
-
relPath: relative3(realpathSync5(roots.claudeUploadsRoot), real),
|
|
11474
|
-
via: "claude-uploads"
|
|
11475
|
-
};
|
|
11476
|
-
}
|
|
11477
|
-
}
|
|
11478
|
-
}
|
|
11479
|
-
if (name) {
|
|
11480
|
-
const outputFile = resolve15(roots.accountsDir, accountId, "output", name);
|
|
11481
|
-
const real = containedFile(outputFile, roots.dataRoot);
|
|
11482
|
-
if (real) {
|
|
11483
|
-
return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "output" };
|
|
11484
|
-
}
|
|
11485
|
-
}
|
|
11486
|
-
return { ok: false, reason: sourceType === "web" ? "no-persisted-file" : "unresolved" };
|
|
11487
|
-
}
|
|
11488
|
-
|
|
11489
|
-
// server/routes/admin/sidebar-artefacts.ts
|
|
11490
11537
|
var LIMIT = 50;
|
|
11491
|
-
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
11492
11538
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
11493
11539
|
function toDataRootRelPath(absPath) {
|
|
11494
|
-
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT +
|
|
11495
|
-
return
|
|
11496
|
-
}
|
|
11497
|
-
function resolveDocDownloadRow(meta) {
|
|
11498
|
-
const result = resolveDocDownload(
|
|
11499
|
-
{
|
|
11500
|
-
accountId: meta.accountId,
|
|
11501
|
-
attachmentId: meta.attachmentId,
|
|
11502
|
-
name: meta.name,
|
|
11503
|
-
sourcePath: meta.sourcePath,
|
|
11504
|
-
sourceType: meta.sourceType
|
|
11505
|
-
},
|
|
11506
|
-
{
|
|
11507
|
-
dataRoot: DATA_ROOT,
|
|
11508
|
-
attachmentsRoot: ATTACHMENTS_ROOT,
|
|
11509
|
-
accountsDir: ACCOUNTS_DIR,
|
|
11510
|
-
claudeUploadsRoot: CLAUDE_UPLOADS_ROOT
|
|
11511
|
-
}
|
|
11512
|
-
);
|
|
11513
|
-
const aid = meta.attachmentId ? meta.attachmentId.slice(0, 8) : "none";
|
|
11514
|
-
if (result.ok) {
|
|
11515
|
-
console.log(`[admin/sidebar-artefacts] download-resolved id=${aid} via=${result.via} root=${result.root}`);
|
|
11516
|
-
return { downloadPath: result.relPath, downloadRoot: result.root };
|
|
11517
|
-
}
|
|
11518
|
-
console.log(`[admin/sidebar-artefacts] not-downloadable id=${aid} reason=${result.reason}`);
|
|
11519
|
-
return { downloadPath: null, downloadRoot: null };
|
|
11540
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep5)) return null;
|
|
11541
|
+
return relative3(DATA_ROOT, absPath);
|
|
11520
11542
|
}
|
|
11521
11543
|
var app22 = new Hono();
|
|
11522
11544
|
app22.get("/", requireAdminSession, async (c) => {
|
|
@@ -11526,118 +11548,64 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
11526
11548
|
return c.json({ error: "Account not found for session" }, 401);
|
|
11527
11549
|
}
|
|
11528
11550
|
const start = Date.now();
|
|
11529
|
-
const
|
|
11530
|
-
if (
|
|
11551
|
+
const outputs = await fetchOutputArtefacts(accountId);
|
|
11552
|
+
if (outputs === null) {
|
|
11531
11553
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
11532
11554
|
}
|
|
11533
|
-
const accountDir =
|
|
11555
|
+
const accountDir = resolve15(ACCOUNTS_DIR, accountId);
|
|
11534
11556
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
11535
|
-
const artefacts = [...
|
|
11557
|
+
const artefacts = [...outputs, ...agents].sort(
|
|
11536
11558
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
11537
11559
|
).slice(0, LIMIT);
|
|
11538
11560
|
const ms = Date.now() - start;
|
|
11539
11561
|
console.log(
|
|
11540
|
-
`[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length}
|
|
11562
|
+
`[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} outputs=${outputs.length} agents=${agents.length} ms=${ms}`
|
|
11541
11563
|
);
|
|
11542
11564
|
return c.json({ artefacts });
|
|
11543
11565
|
});
|
|
11544
|
-
async function
|
|
11566
|
+
async function fetchOutputArtefacts(accountId) {
|
|
11545
11567
|
const session = getSession();
|
|
11546
|
-
let metas = [];
|
|
11547
11568
|
try {
|
|
11548
11569
|
const result = await session.run(
|
|
11549
|
-
`MATCH (
|
|
11550
|
-
WHERE
|
|
11551
|
-
RETURN
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11570
|
+
`MATCH (f:FileArtifact { accountId: $accountId })
|
|
11571
|
+
WHERE f.relativePath CONTAINS '/output/'
|
|
11572
|
+
RETURN f.relativePath AS relativePath,
|
|
11573
|
+
f.displayName AS displayName,
|
|
11574
|
+
f.mimeType AS mimeType,
|
|
11575
|
+
f.modifiedAt AS modifiedAt
|
|
11576
|
+
ORDER BY f.modifiedAt DESC
|
|
11577
|
+
LIMIT 50`,
|
|
11578
|
+
{ accountId }
|
|
11579
|
+
);
|
|
11580
|
+
return result.records.map((r) => {
|
|
11581
|
+
const relativePath = r.get("relativePath");
|
|
11582
|
+
const displayName = r.get("displayName") ?? null;
|
|
11583
|
+
const mimeType = r.get("mimeType") ?? "";
|
|
11584
|
+
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
11585
|
+
return {
|
|
11586
|
+
id: `output-file:${relativePath}`,
|
|
11587
|
+
name: displayName ?? basename5(relativePath),
|
|
11588
|
+
kind: "output-file",
|
|
11589
|
+
updatedAt: modifiedAt,
|
|
11590
|
+
editable: false,
|
|
11591
|
+
mimeType,
|
|
11592
|
+
downloadPath: relativePath,
|
|
11593
|
+
downloadRoot: "data"
|
|
11594
|
+
};
|
|
11595
|
+
});
|
|
11567
11596
|
} catch (err) {
|
|
11568
11597
|
const message = err instanceof Error ? err.message : String(err);
|
|
11569
11598
|
console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
|
|
11570
|
-
await session.close();
|
|
11571
11599
|
return null;
|
|
11572
11600
|
} finally {
|
|
11573
11601
|
await session.close();
|
|
11574
11602
|
}
|
|
11575
|
-
return Promise.all(metas.map(async (m) => {
|
|
11576
|
-
const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
|
|
11577
|
-
const { downloadPath, downloadRoot } = resolveDocDownloadRow({
|
|
11578
|
-
accountId,
|
|
11579
|
-
attachmentId: m.attachmentId,
|
|
11580
|
-
name: m.name,
|
|
11581
|
-
sourcePath: m.sourcePath,
|
|
11582
|
-
sourceType: m.sourceType
|
|
11583
|
-
});
|
|
11584
|
-
return {
|
|
11585
|
-
id: m.id,
|
|
11586
|
-
name: m.name,
|
|
11587
|
-
kind: "knowledge-doc",
|
|
11588
|
-
updatedAt: m.updatedAt,
|
|
11589
|
-
content,
|
|
11590
|
-
editable: skipReason === null,
|
|
11591
|
-
mimeType: m.mimeType,
|
|
11592
|
-
skipReason,
|
|
11593
|
-
downloadPath,
|
|
11594
|
-
downloadRoot
|
|
11595
|
-
};
|
|
11596
|
-
}));
|
|
11597
|
-
}
|
|
11598
|
-
async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
|
|
11599
|
-
if (!attachmentId) {
|
|
11600
|
-
logSkip(displayName, "null-attachmentId", mimeType);
|
|
11601
|
-
return { content: "", skipReason: "null-attachmentId" };
|
|
11602
|
-
}
|
|
11603
|
-
const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
|
|
11604
|
-
if (!isText) {
|
|
11605
|
-
logSkip(displayName, "non-text-mime", mimeType);
|
|
11606
|
-
return { content: "", skipReason: "non-text-mime" };
|
|
11607
|
-
}
|
|
11608
|
-
const accountDir = resolve16(ATTACHMENTS_ROOT, accountId);
|
|
11609
|
-
const dir = resolve16(accountDir, attachmentId);
|
|
11610
|
-
try {
|
|
11611
|
-
validateFilePathInAccount(dir, accountDir);
|
|
11612
|
-
} catch {
|
|
11613
|
-
logSkip(displayName, "containment-rejected", mimeType);
|
|
11614
|
-
return { content: "", skipReason: "containment-rejected" };
|
|
11615
|
-
}
|
|
11616
|
-
try {
|
|
11617
|
-
const entries = await readdir4(dir);
|
|
11618
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11619
|
-
if (!dataFile) {
|
|
11620
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11621
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11622
|
-
}
|
|
11623
|
-
return { content: await readFile5(resolve16(dir, dataFile), "utf-8"), skipReason: null };
|
|
11624
|
-
} catch (err) {
|
|
11625
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
11626
|
-
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
11627
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11628
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11629
|
-
}
|
|
11630
|
-
}
|
|
11631
|
-
function logSkip(name, reason, mimeType) {
|
|
11632
|
-
console.log(
|
|
11633
|
-
`[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
|
|
11634
|
-
);
|
|
11635
11603
|
}
|
|
11636
11604
|
async function fetchAgentTemplateRows(accountDir) {
|
|
11637
11605
|
const rows = [];
|
|
11638
11606
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
11639
|
-
const overridePath =
|
|
11640
|
-
const bundledPath =
|
|
11607
|
+
const overridePath = resolve15(accountDir, "agents", "admin", filename);
|
|
11608
|
+
const bundledPath = resolve15(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
11641
11609
|
const labelStem = filename.replace(/\.md$/, "");
|
|
11642
11610
|
const row = await readAgentTemplateRow({
|
|
11643
11611
|
id: `agent-template:admin:${filename}`,
|
|
@@ -11651,12 +11619,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11651
11619
|
});
|
|
11652
11620
|
if (row) rows.push(row);
|
|
11653
11621
|
}
|
|
11654
|
-
const overrideDir =
|
|
11655
|
-
const bundledDir =
|
|
11622
|
+
const overrideDir = resolve15(accountDir, "specialists", "agents");
|
|
11623
|
+
const bundledDir = resolve15(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
11656
11624
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
11657
11625
|
for (const filename of specialistNames) {
|
|
11658
|
-
const overridePath =
|
|
11659
|
-
const bundledPath =
|
|
11626
|
+
const overridePath = resolve15(overrideDir, filename);
|
|
11627
|
+
const bundledPath = resolve15(bundledDir, filename);
|
|
11660
11628
|
const row = await readAgentTemplateRow({
|
|
11661
11629
|
id: `agent-template:specialist:${filename}`,
|
|
11662
11630
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -11711,20 +11679,15 @@ async function readAgentTemplateRow(inp) {
|
|
|
11711
11679
|
}
|
|
11712
11680
|
if (!chosenPath) return null;
|
|
11713
11681
|
try {
|
|
11714
|
-
const
|
|
11715
|
-
readFile5(chosenPath, "utf-8"),
|
|
11716
|
-
stat5(chosenPath)
|
|
11717
|
-
]);
|
|
11682
|
+
const st = await stat5(chosenPath);
|
|
11718
11683
|
const dlPath = toDataRootRelPath(chosenPath);
|
|
11719
11684
|
return {
|
|
11720
11685
|
id: inp.id,
|
|
11721
11686
|
name: inp.displayName,
|
|
11722
11687
|
kind: "agent-template",
|
|
11723
11688
|
updatedAt: st.mtime.toISOString(),
|
|
11724
|
-
content,
|
|
11725
11689
|
editable: inp.editable,
|
|
11726
11690
|
mimeType: "text/markdown",
|
|
11727
|
-
skipReason: null,
|
|
11728
11691
|
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
11729
11692
|
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
11730
11693
|
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
@@ -11742,17 +11705,15 @@ async function readAgentTemplateRow(inp) {
|
|
|
11742
11705
|
}
|
|
11743
11706
|
}
|
|
11744
11707
|
function isWithin(target, root) {
|
|
11745
|
-
const rel =
|
|
11708
|
+
const rel = relative3(root, target);
|
|
11746
11709
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
11747
11710
|
}
|
|
11748
11711
|
var sidebar_artefacts_default = app22;
|
|
11749
11712
|
|
|
11750
11713
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
11751
|
-
import { mkdir as mkdir4,
|
|
11752
|
-
import { resolve as
|
|
11753
|
-
import { existsSync as existsSync17 } from "fs";
|
|
11714
|
+
import { mkdir as mkdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11715
|
+
import { resolve as resolve16 } from "path";
|
|
11754
11716
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11755
|
-
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11756
11717
|
var app23 = new Hono();
|
|
11757
11718
|
app23.post("/", requireAdminSession, async (c) => {
|
|
11758
11719
|
const cacheKey = c.var.cacheKey;
|
|
@@ -11762,12 +11723,8 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
11762
11723
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
11763
11724
|
return c.json({ error: "id and content required" }, 400);
|
|
11764
11725
|
}
|
|
11765
|
-
const accountDir =
|
|
11766
|
-
const resolved = await resolveSavePath(body.id,
|
|
11767
|
-
if (resolved.kind === "heal-race") {
|
|
11768
|
-
c.header("Retry-After", "2");
|
|
11769
|
-
return c.json({ error: "heal-race", reason: resolved.reason }, 503);
|
|
11770
|
-
}
|
|
11726
|
+
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
11727
|
+
const resolved = await resolveSavePath(body.id, accountDir);
|
|
11771
11728
|
if (resolved.kind === "reject") {
|
|
11772
11729
|
console.error(
|
|
11773
11730
|
`[admin/sidebar-artefact-save] auth-rejected reason=${resolved.reason} path=${body.id}`
|
|
@@ -11796,129 +11753,88 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
11796
11753
|
);
|
|
11797
11754
|
return c.json({ updatedAt });
|
|
11798
11755
|
});
|
|
11799
|
-
async function resolveSavePath(id,
|
|
11800
|
-
if (id.startsWith("agent-template:")) {
|
|
11801
|
-
|
|
11802
|
-
if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11803
|
-
const [, role, filename] = parts;
|
|
11804
|
-
if (role === "specialist") {
|
|
11805
|
-
return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
|
|
11806
|
-
}
|
|
11807
|
-
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11808
|
-
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11809
|
-
}
|
|
11810
|
-
const parent = resolve17(accountDir, "agents", "admin");
|
|
11811
|
-
await mkdir4(parent, { recursive: true });
|
|
11812
|
-
try {
|
|
11813
|
-
validateFilePathInAccount(parent, accountDir);
|
|
11814
|
-
} catch {
|
|
11815
|
-
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11816
|
-
}
|
|
11817
|
-
return { kind: "admin-template", path: resolve17(parent, filename) };
|
|
11756
|
+
async function resolveSavePath(id, accountDir) {
|
|
11757
|
+
if (!id.startsWith("agent-template:")) {
|
|
11758
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11818
11759
|
}
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
const cnt = result.records[0]?.get("cnt")?.toNumber?.() ?? 0;
|
|
11835
|
-
if (cnt > 0) {
|
|
11836
|
-
console.error(`[admin/sidebar-artefact-save] heal-race attachmentId=${attShort} outcome=503-retry source=neo4j-row`);
|
|
11837
|
-
return { kind: "heal-race", reason: "dir-pending" };
|
|
11838
|
-
}
|
|
11839
|
-
console.error(`[admin/sidebar-artefact-save] heal-race attachmentId=${attShort} outcome=400-terminal`);
|
|
11840
|
-
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11841
|
-
} catch (neoErr) {
|
|
11842
|
-
const reason = neoErr instanceof Error ? neoErr.message.slice(0, 120) : String(neoErr).slice(0, 120);
|
|
11843
|
-
console.error(`[admin/sidebar-artefact-save] heal-race attachmentId=${attShort} outcome=neo4j-fail reason="${reason}"`);
|
|
11844
|
-
return { kind: "heal-race", reason: "neo4j-fail" };
|
|
11845
|
-
} finally {
|
|
11846
|
-
try {
|
|
11847
|
-
await session.close();
|
|
11848
|
-
} catch {
|
|
11849
|
-
}
|
|
11850
|
-
}
|
|
11851
|
-
}
|
|
11852
|
-
try {
|
|
11853
|
-
validateFilePathInAccount(dir, resolve17(ATTACHMENTS_ROOT, accountId));
|
|
11854
|
-
} catch {
|
|
11855
|
-
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11856
|
-
}
|
|
11857
|
-
const entries = await readdir5(dir);
|
|
11858
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11859
|
-
if (!dataFile) {
|
|
11860
|
-
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11861
|
-
}
|
|
11862
|
-
return { kind: "knowledge-doc", path: resolve17(dir, dataFile) };
|
|
11760
|
+
const parts = id.split(":");
|
|
11761
|
+
if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11762
|
+
const [, role, filename] = parts;
|
|
11763
|
+
if (role === "specialist") {
|
|
11764
|
+
return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
|
|
11765
|
+
}
|
|
11766
|
+
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11767
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11768
|
+
}
|
|
11769
|
+
const parent = resolve16(accountDir, "agents", "admin");
|
|
11770
|
+
await mkdir4(parent, { recursive: true });
|
|
11771
|
+
try {
|
|
11772
|
+
validateFilePathInAccount(parent, accountDir);
|
|
11773
|
+
} catch {
|
|
11774
|
+
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11863
11775
|
}
|
|
11864
|
-
return { kind: "
|
|
11776
|
+
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
11865
11777
|
}
|
|
11866
11778
|
function relPath(absPath, root) {
|
|
11867
11779
|
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
11868
11780
|
}
|
|
11869
11781
|
var sidebar_artefact_save_default = app23;
|
|
11870
11782
|
|
|
11871
|
-
// server/routes/admin/sidebar-
|
|
11872
|
-
import { readFile as readFile6, readdir as readdir6 } from "fs/promises";
|
|
11873
|
-
import { existsSync as existsSync18 } from "fs";
|
|
11874
|
-
import { resolve as resolve18 } from "path";
|
|
11875
|
-
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11783
|
+
// server/routes/admin/sidebar-sessions.ts
|
|
11876
11784
|
var app24 = new Hono();
|
|
11877
11785
|
app24.get("/", requireAdminSession, async (c) => {
|
|
11878
11786
|
const cacheKey = c.var.cacheKey;
|
|
11879
11787
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11880
|
-
if (!accountId)
|
|
11881
|
-
|
|
11882
|
-
if (!UUID_RE5.test(id)) {
|
|
11883
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11884
|
-
return new Response("Not found", { status: 404 });
|
|
11788
|
+
if (!accountId) {
|
|
11789
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
11885
11790
|
}
|
|
11886
|
-
const
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11791
|
+
const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "admin-sessions-list" });
|
|
11792
|
+
const url = `http://127.0.0.1:${port2}/list?senderId=${encodeURIComponent(accountId)}`;
|
|
11793
|
+
let upstream = null;
|
|
11794
|
+
try {
|
|
11795
|
+
upstream = await fetch(url);
|
|
11796
|
+
} catch (err) {
|
|
11797
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11798
|
+
console.error(`[admin-sessions-list] account=${accountId} fetch-failed error="${message}"`);
|
|
11799
|
+
return c.json({ error: "session-manager-unreachable" }, 503);
|
|
11890
11800
|
}
|
|
11891
|
-
|
|
11801
|
+
if (!upstream.ok) {
|
|
11802
|
+
console.error(`[admin-sessions-list] account=${accountId} upstream-status=${upstream.status}`);
|
|
11803
|
+
return c.json({ error: "session-manager-error", status: upstream.status }, 502);
|
|
11804
|
+
}
|
|
11805
|
+
let payloads;
|
|
11892
11806
|
try {
|
|
11893
|
-
|
|
11894
|
-
} catch {
|
|
11895
|
-
|
|
11896
|
-
|
|
11807
|
+
payloads = await upstream.json();
|
|
11808
|
+
} catch (err) {
|
|
11809
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11810
|
+
console.error(`[admin-sessions-list] account=${accountId} parse-failed error="${message}"`);
|
|
11811
|
+
return c.json({ error: "session-manager-bad-body" }, 502);
|
|
11897
11812
|
}
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11902
|
-
return new Response("Not found", { status: 404 });
|
|
11813
|
+
if (!Array.isArray(payloads)) {
|
|
11814
|
+
console.error(`[admin-sessions-list] account=${accountId} bad-shape=not-array`);
|
|
11815
|
+
return c.json({ error: "session-manager-bad-body" }, 502);
|
|
11903
11816
|
}
|
|
11904
|
-
const
|
|
11905
|
-
const
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11817
|
+
const rows = [];
|
|
11818
|
+
for (const p of payloads) {
|
|
11819
|
+
const sessionId = typeof p.sessionId === "string" ? p.sessionId : null;
|
|
11820
|
+
const capturedUrl = typeof p.url === "string" ? p.url : null;
|
|
11821
|
+
const startedAt = typeof p.startedAt === "string" ? p.startedAt : null;
|
|
11822
|
+
if (!sessionId || !capturedUrl || !startedAt) continue;
|
|
11823
|
+
const displayName = typeof p.displayName === "string" && p.displayName.length > 0 ? p.displayName : sessionId.slice(0, 8);
|
|
11824
|
+
rows.push({
|
|
11825
|
+
sessionId,
|
|
11826
|
+
title: displayName,
|
|
11827
|
+
url: capturedUrl,
|
|
11828
|
+
capturedAt: startedAt
|
|
11829
|
+
});
|
|
11830
|
+
}
|
|
11831
|
+
console.log(`[admin-sessions-list] account=${accountId} rows=${rows.length}`);
|
|
11832
|
+
return c.json({ sessions: rows });
|
|
11917
11833
|
});
|
|
11918
|
-
var
|
|
11834
|
+
var sidebar_sessions_default = app24;
|
|
11919
11835
|
|
|
11920
11836
|
// server/routes/admin/system-stats.ts
|
|
11921
|
-
import { readFile as
|
|
11837
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
11922
11838
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
11923
11839
|
function parseCpuStat(blob) {
|
|
11924
11840
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
@@ -11962,11 +11878,11 @@ function parseMeminfo(blob) {
|
|
|
11962
11878
|
}
|
|
11963
11879
|
var SAMPLE_DELAY_MS = 100;
|
|
11964
11880
|
async function sampleLinux() {
|
|
11965
|
-
const a = parseCpuStat(await
|
|
11881
|
+
const a = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
|
|
11966
11882
|
await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
|
|
11967
|
-
const b = parseCpuStat(await
|
|
11968
|
-
const meminfo = parseMeminfo(await
|
|
11969
|
-
const loadavgRaw = (await
|
|
11883
|
+
const b = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
|
|
11884
|
+
const meminfo = parseMeminfo(await readFile5("/proc/meminfo", "utf-8"));
|
|
11885
|
+
const loadavgRaw = (await readFile5("/proc/loadavg", "utf-8")).trim();
|
|
11970
11886
|
const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
|
|
11971
11887
|
if (![l1, l5, l15].every(Number.isFinite)) {
|
|
11972
11888
|
throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
|
|
@@ -12039,23 +11955,23 @@ app25.get("/", async (c) => {
|
|
|
12039
11955
|
var system_stats_default = app25;
|
|
12040
11956
|
|
|
12041
11957
|
// server/routes/admin/health.ts
|
|
12042
|
-
import { existsSync as
|
|
12043
|
-
import { resolve as
|
|
12044
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
11958
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
|
|
11959
|
+
import { resolve as resolve17, join as join13 } from "path";
|
|
11960
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
12045
11961
|
var brandHostname = "maxy";
|
|
12046
11962
|
var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
|
|
12047
|
-
if (
|
|
11963
|
+
if (existsSync17(brandJsonPath)) {
|
|
12048
11964
|
try {
|
|
12049
11965
|
const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
|
|
12050
11966
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
12051
11967
|
} catch {
|
|
12052
11968
|
}
|
|
12053
11969
|
}
|
|
12054
|
-
var VERSION_FILE =
|
|
11970
|
+
var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
12055
11971
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12056
11972
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12057
11973
|
function readVersion() {
|
|
12058
|
-
if (!
|
|
11974
|
+
if (!existsSync17(VERSION_FILE)) return "unknown";
|
|
12059
11975
|
return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12060
11976
|
}
|
|
12061
11977
|
async function probeConversationDb() {
|
|
@@ -12258,7 +12174,7 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
12258
12174
|
var linkedin_ingest_default = app27;
|
|
12259
12175
|
|
|
12260
12176
|
// server/routes/admin/post-turn-context.ts
|
|
12261
|
-
import
|
|
12177
|
+
import neo4j2 from "neo4j-driver";
|
|
12262
12178
|
var TAG21 = "[post-turn-context]";
|
|
12263
12179
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
12264
12180
|
"embedding",
|
|
@@ -12271,10 +12187,10 @@ function isLoopbackAddr2(addr) {
|
|
|
12271
12187
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12272
12188
|
}
|
|
12273
12189
|
function convertValue(value) {
|
|
12274
|
-
if (
|
|
12190
|
+
if (neo4j2.isDateTime(value) || neo4j2.isDate(value) || neo4j2.isLocalDateTime(value) || neo4j2.isLocalTime(value) || neo4j2.isTime(value) || neo4j2.isDuration(value)) {
|
|
12275
12191
|
return value.toString();
|
|
12276
12192
|
}
|
|
12277
|
-
if (
|
|
12193
|
+
if (neo4j2.isInt(value)) {
|
|
12278
12194
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12279
12195
|
}
|
|
12280
12196
|
if (Array.isArray(value)) {
|
|
@@ -12361,7 +12277,7 @@ app28.get("/", async (c) => {
|
|
|
12361
12277
|
var post_turn_context_default = app28;
|
|
12362
12278
|
|
|
12363
12279
|
// server/routes/admin/public-session-context.ts
|
|
12364
|
-
import
|
|
12280
|
+
import neo4j3 from "neo4j-driver";
|
|
12365
12281
|
var TAG22 = "[public-session-context]";
|
|
12366
12282
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
12367
12283
|
"embedding",
|
|
@@ -12374,10 +12290,10 @@ function isLoopbackAddr3(addr) {
|
|
|
12374
12290
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12375
12291
|
}
|
|
12376
12292
|
function convertValue2(value) {
|
|
12377
|
-
if (
|
|
12293
|
+
if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
|
|
12378
12294
|
return value.toString();
|
|
12379
12295
|
}
|
|
12380
|
-
if (
|
|
12296
|
+
if (neo4j3.isInt(value)) {
|
|
12381
12297
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12382
12298
|
}
|
|
12383
12299
|
if (Array.isArray(value)) {
|
|
@@ -12553,7 +12469,7 @@ app32.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
|
12553
12469
|
app32.route("/graph-default-view", graph_default_view_default);
|
|
12554
12470
|
app32.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12555
12471
|
app32.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12556
|
-
app32.route("/sidebar-
|
|
12472
|
+
app32.route("/sidebar-sessions", sidebar_sessions_default);
|
|
12557
12473
|
app32.route("/system-stats", system_stats_default);
|
|
12558
12474
|
app32.route("/health-brand", health_default2);
|
|
12559
12475
|
app32.route("/linkedin-ingest", linkedin_ingest_default);
|
|
@@ -12564,15 +12480,15 @@ app32.route("/access-session-evict", access_session_evict_default);
|
|
|
12564
12480
|
var admin_default = app32;
|
|
12565
12481
|
|
|
12566
12482
|
// app/lib/access-gate.ts
|
|
12567
|
-
import
|
|
12483
|
+
import neo4j4 from "neo4j-driver";
|
|
12568
12484
|
import { readFileSync as readFileSync15 } from "fs";
|
|
12569
|
-
import { resolve as
|
|
12485
|
+
import { resolve as resolve18 } from "path";
|
|
12570
12486
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12571
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12487
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
12572
12488
|
var driver = null;
|
|
12573
12489
|
function readPassword() {
|
|
12574
12490
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12575
|
-
const passwordFile =
|
|
12491
|
+
const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12576
12492
|
try {
|
|
12577
12493
|
return readFileSync15(passwordFile, "utf-8").trim();
|
|
12578
12494
|
} catch {
|
|
@@ -12592,7 +12508,7 @@ function getDriver() {
|
|
|
12592
12508
|
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
12593
12509
|
const password = readPassword();
|
|
12594
12510
|
console.error(`[ui/access-gate] resolved neo4j_uri=${uri}`);
|
|
12595
|
-
driver =
|
|
12511
|
+
driver = neo4j4.driver(uri, neo4j4.auth.basic(user, password), {
|
|
12596
12512
|
maxConnectionPoolSize: 5
|
|
12597
12513
|
});
|
|
12598
12514
|
}
|
|
@@ -12862,9 +12778,9 @@ var verify_token_default = app33;
|
|
|
12862
12778
|
|
|
12863
12779
|
// app/lib/access-email.ts
|
|
12864
12780
|
import { spawn as spawn2 } from "child_process";
|
|
12865
|
-
import { resolve as
|
|
12866
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12867
|
-
var SEND_SCRIPT =
|
|
12781
|
+
import { resolve as resolve19 } from "path";
|
|
12782
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
12783
|
+
var SEND_SCRIPT = resolve19(
|
|
12868
12784
|
PLATFORM_ROOT8,
|
|
12869
12785
|
"plugins",
|
|
12870
12786
|
"email",
|
|
@@ -13006,8 +12922,8 @@ app35.route("/request-magic-link", request_magic_link_default);
|
|
|
13006
12922
|
var access_default = app35;
|
|
13007
12923
|
|
|
13008
12924
|
// server/routes/sites.ts
|
|
13009
|
-
import { existsSync as
|
|
13010
|
-
import { resolve as
|
|
12925
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
12926
|
+
import { resolve as resolve20 } from "path";
|
|
13011
12927
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13012
12928
|
var MIME = {
|
|
13013
12929
|
".html": "text/html; charset=utf-8",
|
|
@@ -13064,19 +12980,19 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13064
12980
|
}
|
|
13065
12981
|
segments.push(seg);
|
|
13066
12982
|
}
|
|
13067
|
-
const rootDir =
|
|
13068
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
12983
|
+
const rootDir = resolve20(account.accountDir, "sites");
|
|
12984
|
+
let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
|
|
13069
12985
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
13070
12986
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13071
12987
|
return c.text("Forbidden", 403);
|
|
13072
12988
|
}
|
|
13073
|
-
let
|
|
12989
|
+
let stat8;
|
|
13074
12990
|
try {
|
|
13075
|
-
|
|
12991
|
+
stat8 = existsSync18(filePath) ? statSync7(filePath) : null;
|
|
13076
12992
|
} catch {
|
|
13077
|
-
|
|
12993
|
+
stat8 = null;
|
|
13078
12994
|
}
|
|
13079
|
-
if (
|
|
12995
|
+
if (stat8?.isDirectory() && !reqPath.endsWith("/")) {
|
|
13080
12996
|
const search = new URL(c.req.url).search;
|
|
13081
12997
|
const target = `${reqPath}/${search}`;
|
|
13082
12998
|
console.log(
|
|
@@ -13084,22 +13000,22 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13084
13000
|
);
|
|
13085
13001
|
return c.redirect(target, 301);
|
|
13086
13002
|
}
|
|
13087
|
-
if (
|
|
13088
|
-
filePath =
|
|
13003
|
+
if (stat8?.isDirectory()) {
|
|
13004
|
+
filePath = resolve20(filePath, "index.html");
|
|
13089
13005
|
}
|
|
13090
13006
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
13091
13007
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13092
13008
|
return c.text("Forbidden", 403);
|
|
13093
13009
|
}
|
|
13094
|
-
if (!
|
|
13010
|
+
if (!existsSync18(filePath)) {
|
|
13095
13011
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13096
13012
|
return c.text("Not found", 404);
|
|
13097
13013
|
}
|
|
13098
13014
|
let realPath;
|
|
13099
13015
|
let realRoot;
|
|
13100
13016
|
try {
|
|
13101
|
-
realPath =
|
|
13102
|
-
realRoot =
|
|
13017
|
+
realPath = realpathSync5(filePath);
|
|
13018
|
+
realRoot = realpathSync5(rootDir);
|
|
13103
13019
|
} catch {
|
|
13104
13020
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13105
13021
|
return c.text("Not found", 404);
|
|
@@ -13222,7 +13138,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13222
13138
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13223
13139
|
|
|
13224
13140
|
// app/lib/brand-config.ts
|
|
13225
|
-
import { existsSync as
|
|
13141
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
|
|
13226
13142
|
import { join as join14 } from "path";
|
|
13227
13143
|
var cached2 = null;
|
|
13228
13144
|
var cachedAttempted = false;
|
|
@@ -13232,7 +13148,7 @@ function readBrandConfig() {
|
|
|
13232
13148
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13233
13149
|
if (!platformRoot) return null;
|
|
13234
13150
|
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
13235
|
-
if (!
|
|
13151
|
+
if (!existsSync19(brandPath)) return null;
|
|
13236
13152
|
try {
|
|
13237
13153
|
cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
13238
13154
|
return cached2;
|
|
@@ -13802,6 +13718,109 @@ function startGraphHealthTimer() {
|
|
|
13802
13718
|
if (typeof timer.unref === "function") timer.unref();
|
|
13803
13719
|
}
|
|
13804
13720
|
|
|
13721
|
+
// app/lib/file-watcher.ts
|
|
13722
|
+
import * as fsp2 from "fs/promises";
|
|
13723
|
+
import { resolve as resolve21, sep as sep6 } from "path";
|
|
13724
|
+
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;
|
|
13725
|
+
var DEFAULT_COALESCE_MS = 500;
|
|
13726
|
+
var ROOTS = ["uploads", "accounts"];
|
|
13727
|
+
function _routeEvent(rootName, filename) {
|
|
13728
|
+
if (!filename) return null;
|
|
13729
|
+
const segs = filename.split(sep6).filter(Boolean);
|
|
13730
|
+
if (segs.length < 2) return null;
|
|
13731
|
+
const accountId = segs[0];
|
|
13732
|
+
if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
|
|
13733
|
+
return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
|
|
13734
|
+
}
|
|
13735
|
+
async function startFileWatcher(opts = {}) {
|
|
13736
|
+
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
13737
|
+
const coalesceMs = opts.coalesceMs ?? DEFAULT_COALESCE_MS;
|
|
13738
|
+
const indexFn = opts.index ?? indexFile;
|
|
13739
|
+
const dropFn = opts.drop ?? dropFileIndex;
|
|
13740
|
+
for (const r of ROOTS) {
|
|
13741
|
+
try {
|
|
13742
|
+
await fsp2.mkdir(resolve21(dataRoot, r), { recursive: true });
|
|
13743
|
+
} catch (err) {
|
|
13744
|
+
console.error(
|
|
13745
|
+
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
13746
|
+
);
|
|
13747
|
+
return { stop: async () => {
|
|
13748
|
+
} };
|
|
13749
|
+
}
|
|
13750
|
+
}
|
|
13751
|
+
const controller = new AbortController();
|
|
13752
|
+
const timers = /* @__PURE__ */ new Map();
|
|
13753
|
+
function schedule(relativePath, accountId) {
|
|
13754
|
+
const existing = timers.get(relativePath);
|
|
13755
|
+
if (existing) clearTimeout(existing);
|
|
13756
|
+
const t = setTimeout(() => {
|
|
13757
|
+
timers.delete(relativePath);
|
|
13758
|
+
void runHook(relativePath, accountId);
|
|
13759
|
+
}, coalesceMs);
|
|
13760
|
+
timers.set(relativePath, t);
|
|
13761
|
+
}
|
|
13762
|
+
async function runHook(relativePath, accountId) {
|
|
13763
|
+
const absolute = resolve21(dataRoot, relativePath);
|
|
13764
|
+
let exists = false;
|
|
13765
|
+
try {
|
|
13766
|
+
const st = await fsp2.stat(absolute);
|
|
13767
|
+
exists = st.isFile();
|
|
13768
|
+
} catch (err) {
|
|
13769
|
+
const code = err.code;
|
|
13770
|
+
if (code !== "ENOENT") {
|
|
13771
|
+
console.error(`[file-watcher] stat-error path="${relativePath}" err="${err.message}"`);
|
|
13772
|
+
}
|
|
13773
|
+
}
|
|
13774
|
+
try {
|
|
13775
|
+
if (exists) {
|
|
13776
|
+
await indexFn(accountId, relativePath);
|
|
13777
|
+
} else {
|
|
13778
|
+
await dropFn(accountId, relativePath);
|
|
13779
|
+
}
|
|
13780
|
+
} catch (err) {
|
|
13781
|
+
console.error(`[file-watcher] hook-failed path="${relativePath}" err="${err.message}"`);
|
|
13782
|
+
} finally {
|
|
13783
|
+
opts.onSettled?.(relativePath);
|
|
13784
|
+
}
|
|
13785
|
+
}
|
|
13786
|
+
async function watchRoot(rootName) {
|
|
13787
|
+
const absRoot = resolve21(dataRoot, rootName);
|
|
13788
|
+
try {
|
|
13789
|
+
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
13790
|
+
for await (const event of iter) {
|
|
13791
|
+
const routed = _routeEvent(rootName, event.filename);
|
|
13792
|
+
if (!routed) continue;
|
|
13793
|
+
schedule(routed.relativePath, routed.accountId);
|
|
13794
|
+
}
|
|
13795
|
+
} catch (err) {
|
|
13796
|
+
const code = err.code;
|
|
13797
|
+
const name = err.name;
|
|
13798
|
+
if (code === "ABORT_ERR" || name === "AbortError") return;
|
|
13799
|
+
console.error(`[file-watcher] loop-error root="${rootName}" err="${err.message}"`);
|
|
13800
|
+
}
|
|
13801
|
+
}
|
|
13802
|
+
for (const r of ROOTS) void watchRoot(r);
|
|
13803
|
+
const sigHandler = () => {
|
|
13804
|
+
void stop();
|
|
13805
|
+
};
|
|
13806
|
+
process.once("SIGTERM", sigHandler);
|
|
13807
|
+
process.once("SIGINT", sigHandler);
|
|
13808
|
+
let stopped = false;
|
|
13809
|
+
async function stop() {
|
|
13810
|
+
if (stopped) return;
|
|
13811
|
+
stopped = true;
|
|
13812
|
+
process.off("SIGTERM", sigHandler);
|
|
13813
|
+
process.off("SIGINT", sigHandler);
|
|
13814
|
+
controller.abort();
|
|
13815
|
+
for (const t of timers.values()) clearTimeout(t);
|
|
13816
|
+
timers.clear();
|
|
13817
|
+
}
|
|
13818
|
+
console.error(
|
|
13819
|
+
`[file-watcher] started roots=${ROOTS.join(",")} dataRoot="${dataRoot}" coalesce-ms=${coalesceMs}`
|
|
13820
|
+
);
|
|
13821
|
+
return { stop };
|
|
13822
|
+
}
|
|
13823
|
+
|
|
13805
13824
|
// app/lib/whatsapp/inbound/claude-bridge.ts
|
|
13806
13825
|
var TAG27 = "[whatsapp-adaptor]";
|
|
13807
13826
|
function whatsappTurnTimeoutMs() {
|
|
@@ -13863,8 +13882,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
13863
13882
|
|
|
13864
13883
|
// ../lib/entitlement/src/index.ts
|
|
13865
13884
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13866
|
-
import { existsSync as
|
|
13867
|
-
import { resolve as
|
|
13885
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
|
|
13886
|
+
import { resolve as resolve22 } from "path";
|
|
13868
13887
|
|
|
13869
13888
|
// ../lib/entitlement/src/canonicalize.ts
|
|
13870
13889
|
function canonicalize(value) {
|
|
@@ -13899,7 +13918,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
13899
13918
|
var GRACE_DAYS = 7;
|
|
13900
13919
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
13901
13920
|
function pubkeyPath(brand) {
|
|
13902
|
-
return
|
|
13921
|
+
return resolve22(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
13903
13922
|
}
|
|
13904
13923
|
var memo = null;
|
|
13905
13924
|
function memoKey(mtimeMs, account) {
|
|
@@ -13911,12 +13930,12 @@ function resolveEntitlement(brand, account) {
|
|
|
13911
13930
|
if (brand.commercialMode !== true) {
|
|
13912
13931
|
return logResolved(implicitTrust(account), null);
|
|
13913
13932
|
}
|
|
13914
|
-
const entitlementPath =
|
|
13915
|
-
if (!
|
|
13933
|
+
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
13934
|
+
if (!existsSync20(entitlementPath)) {
|
|
13916
13935
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13917
13936
|
}
|
|
13918
|
-
const
|
|
13919
|
-
const key = memoKey(
|
|
13937
|
+
const stat8 = statSync8(entitlementPath);
|
|
13938
|
+
const key = memoKey(stat8.mtimeMs, account);
|
|
13920
13939
|
if (memo && memo.key === key) {
|
|
13921
13940
|
return memo.result;
|
|
13922
13941
|
}
|
|
@@ -14104,10 +14123,10 @@ function clientFrom(c) {
|
|
|
14104
14123
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
14105
14124
|
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
14106
14125
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
14107
|
-
if (BRAND_JSON_PATH && !
|
|
14126
|
+
if (BRAND_JSON_PATH && !existsSync21(BRAND_JSON_PATH)) {
|
|
14108
14127
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
14109
14128
|
}
|
|
14110
|
-
if (BRAND_JSON_PATH &&
|
|
14129
|
+
if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
|
|
14111
14130
|
try {
|
|
14112
14131
|
const parsed = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
14113
14132
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -14131,7 +14150,7 @@ var brandLoginOpts = {
|
|
|
14131
14150
|
var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
14132
14151
|
function loadAliasDomains() {
|
|
14133
14152
|
try {
|
|
14134
|
-
if (!
|
|
14153
|
+
if (!existsSync21(ALIAS_DOMAINS_PATH)) return null;
|
|
14135
14154
|
const parsed = JSON.parse(readFileSync20(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
14136
14155
|
if (!Array.isArray(parsed)) {
|
|
14137
14156
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -14496,13 +14515,13 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14496
14515
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
14497
14516
|
return c.text("Not found", 404);
|
|
14498
14517
|
}
|
|
14499
|
-
const filePath =
|
|
14500
|
-
const expectedDir =
|
|
14518
|
+
const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
|
|
14519
|
+
const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
|
|
14501
14520
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14502
14521
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14503
14522
|
return c.text("Forbidden", 403);
|
|
14504
14523
|
}
|
|
14505
|
-
if (!
|
|
14524
|
+
if (!existsSync21(filePath)) {
|
|
14506
14525
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14507
14526
|
return c.text("Not found", 404);
|
|
14508
14527
|
}
|
|
@@ -14526,13 +14545,13 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14526
14545
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14527
14546
|
return c.text("Not found", 404);
|
|
14528
14547
|
}
|
|
14529
|
-
const filePath =
|
|
14530
|
-
const expectedDir =
|
|
14548
|
+
const filePath = resolve23(account.accountDir, "generated", filename);
|
|
14549
|
+
const expectedDir = resolve23(account.accountDir, "generated");
|
|
14531
14550
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14532
14551
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14533
14552
|
return c.text("Forbidden", 403);
|
|
14534
14553
|
}
|
|
14535
|
-
if (!
|
|
14554
|
+
if (!existsSync21(filePath)) {
|
|
14536
14555
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14537
14556
|
return c.text("Not found", 404);
|
|
14538
14557
|
}
|
|
@@ -14552,7 +14571,7 @@ app40.route("/v", visitor_consent_default);
|
|
|
14552
14571
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14553
14572
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14554
14573
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14555
|
-
if (BRAND_JSON_PATH &&
|
|
14574
|
+
if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
|
|
14556
14575
|
try {
|
|
14557
14576
|
const fullBrand = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
14558
14577
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -14572,7 +14591,7 @@ function readInstalledVersion() {
|
|
|
14572
14591
|
try {
|
|
14573
14592
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14574
14593
|
const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14575
|
-
if (!
|
|
14594
|
+
if (!existsSync21(versionFile)) return "unknown";
|
|
14576
14595
|
const content = readFileSync20(versionFile, "utf-8").trim();
|
|
14577
14596
|
return content || "unknown";
|
|
14578
14597
|
} catch {
|
|
@@ -14614,7 +14633,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14614
14633
|
function cachedHtml(file) {
|
|
14615
14634
|
let html = htmlCache.get(file);
|
|
14616
14635
|
if (!html) {
|
|
14617
|
-
html = readFileSync20(
|
|
14636
|
+
html = readFileSync20(resolve23(process.cwd(), "public", file), "utf-8");
|
|
14618
14637
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14619
14638
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14620
14639
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14633,12 +14652,12 @@ function loadBrandingCache(agentSlug) {
|
|
|
14633
14652
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14634
14653
|
try {
|
|
14635
14654
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14636
|
-
if (!
|
|
14655
|
+
if (!existsSync21(accountJsonPath)) return null;
|
|
14637
14656
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14638
14657
|
const accountId = account.accountId;
|
|
14639
14658
|
if (!accountId) return null;
|
|
14640
14659
|
const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14641
|
-
if (!
|
|
14660
|
+
if (!existsSync21(cachePath)) return null;
|
|
14642
14661
|
return JSON.parse(readFileSync20(cachePath, "utf-8"));
|
|
14643
14662
|
} catch {
|
|
14644
14663
|
return null;
|
|
@@ -14648,7 +14667,7 @@ function resolveDefaultSlug() {
|
|
|
14648
14667
|
try {
|
|
14649
14668
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14650
14669
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14651
|
-
if (!
|
|
14670
|
+
if (!existsSync21(accountJsonPath)) return null;
|
|
14652
14671
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14653
14672
|
return account.defaultAgent || null;
|
|
14654
14673
|
} catch {
|
|
@@ -14722,7 +14741,7 @@ app40.use("/vnc-popout.html", logViewerFetch);
|
|
|
14722
14741
|
app40.get("/vnc-popout.html", (c) => {
|
|
14723
14742
|
let html = htmlCache.get("vnc-popout.html");
|
|
14724
14743
|
if (!html) {
|
|
14725
|
-
html = readFileSync20(
|
|
14744
|
+
html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14726
14745
|
const name = escapeHtml(BRAND.productName);
|
|
14727
14746
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14728
14747
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14847,7 +14866,7 @@ try {
|
|
|
14847
14866
|
}
|
|
14848
14867
|
(async () => {
|
|
14849
14868
|
try {
|
|
14850
|
-
if (!
|
|
14869
|
+
if (!existsSync21(USERS_FILE)) return;
|
|
14851
14870
|
const usersRaw = readFileSync20(USERS_FILE, "utf-8").trim();
|
|
14852
14871
|
if (!usersRaw) return;
|
|
14853
14872
|
const users = JSON.parse(usersRaw);
|
|
@@ -14864,6 +14883,9 @@ try {
|
|
|
14864
14883
|
}
|
|
14865
14884
|
})();
|
|
14866
14885
|
startGraphHealthTimer();
|
|
14886
|
+
void startFileWatcher().catch((err) => {
|
|
14887
|
+
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
14888
|
+
});
|
|
14867
14889
|
try {
|
|
14868
14890
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
14869
14891
|
console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
|
|
@@ -14882,7 +14904,7 @@ try {
|
|
|
14882
14904
|
} catch (err) {
|
|
14883
14905
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
14884
14906
|
}
|
|
14885
|
-
var configDirForWhatsApp =
|
|
14907
|
+
var configDirForWhatsApp = basename6(MAXY_DIR) || ".maxy";
|
|
14886
14908
|
var bootAccount = resolveAccount();
|
|
14887
14909
|
var bootAccountConfig = bootAccount?.config;
|
|
14888
14910
|
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
|
|
@@ -14940,7 +14962,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14940
14962
|
}
|
|
14941
14963
|
init({
|
|
14942
14964
|
configDir: configDirForWhatsApp,
|
|
14943
|
-
platformRoot:
|
|
14965
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
|
|
14944
14966
|
accountConfig: bootAccountConfig,
|
|
14945
14967
|
onMessage: async (msg) => {
|
|
14946
14968
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|