@rubytech/create-maxy-code 0.1.277 → 0.1.279
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/plugins/admin/skills/plainly/SKILL.md +33 -16
- package/payload/platform/plugins/admin/skills/plainly/references/worked-examples.md +51 -238
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -1
- package/payload/platform/plugins/business-assistant/PLUGIN.md +4 -0
- package/payload/platform/plugins/business-assistant/references/crm.md +6 -0
- package/payload/platform/plugins/business-assistant/references/e-sign.md +302 -0
- package/payload/platform/plugins/business-assistant/references/site-lead-intake.md +52 -0
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -0
- package/payload/platform/plugins/cloudflare/references/api.md +17 -3
- package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +10 -0
- package/payload/platform/plugins/cloudflare/references/web-analytics.md +64 -0
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +1 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +7 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +22 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -2
- package/payload/premium-plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/premium-plugins/management-consulting/.claude-plugin/plugin.json +8 -0
- package/payload/premium-plugins/management-consulting/PLUGIN.md +92 -0
- package/payload/premium-plugins/management-consulting/skills/assumption-audit/SKILL.md +54 -0
- package/payload/premium-plugins/management-consulting/skills/business-case-builder/SKILL.md +56 -0
- package/payload/premium-plugins/management-consulting/skills/competitive-intel/SKILL.md +51 -0
- package/payload/premium-plugins/management-consulting/skills/customer-segmentation/SKILL.md +50 -0
- package/payload/premium-plugins/management-consulting/skills/decision-memo/SKILL.md +53 -0
- package/payload/premium-plugins/management-consulting/skills/growth-barriers/SKILL.md +54 -0
- package/payload/premium-plugins/management-consulting/skills/initiative-prioritizer/SKILL.md +51 -0
- package/payload/premium-plugins/management-consulting/skills/kpi-architect/SKILL.md +53 -0
- package/payload/premium-plugins/management-consulting/skills/market-mapping/SKILL.md +56 -0
- package/payload/premium-plugins/management-consulting/skills/narrative-builder/SKILL.md +53 -0
- package/payload/premium-plugins/management-consulting/skills/operating-model-design/SKILL.md +54 -0
- package/payload/premium-plugins/management-consulting/skills/portfolio-review/SKILL.md +52 -0
- package/payload/premium-plugins/management-consulting/skills/pricing-strategy/SKILL.md +55 -0
- package/payload/premium-plugins/management-consulting/skills/profit-pool-analysis/SKILL.md +52 -0
- package/payload/premium-plugins/management-consulting/skills/risk-and-mitigation/SKILL.md +49 -0
- package/payload/premium-plugins/management-consulting/skills/situation-assessment/SKILL.md +55 -0
- package/payload/premium-plugins/management-consulting/skills/stakeholder-alignment/SKILL.md +51 -0
- package/payload/premium-plugins/management-consulting/skills/strategic-options/SKILL.md +53 -0
- package/payload/premium-plugins/management-consulting/skills/transformation-roadmap/SKILL.md +53 -0
- package/payload/premium-plugins/management-consulting/skills/value-realization/SKILL.md +50 -0
- package/payload/premium-plugins/management-consulting/skills/war-gaming/SKILL.md +51 -0
- package/payload/server/public/assets/AdminShell-DnH3kou-.js +1 -0
- package/payload/server/public/assets/{Checkbox-BY2lndUH.js → Checkbox-2reCESkb.js} +1 -1
- package/payload/server/public/assets/{admin-C364q_-g.js → admin-xRCXEFNW.js} +1 -1
- package/payload/server/public/assets/{arc-BW1WhwmV.js → arc-BgelqC_3.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-YM-TtgPY.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CLhiy6Rc.js → architectureDiagram-Q4EWVU46-BabnAZJm.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-ue7Vkc-Q.js → blockDiagram-DXYQGD6D-BJzZqNsy.js} +1 -1
- package/payload/server/public/assets/{browser-D66JrDpx.js → browser-DT2XfRpL.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-dVjuUU_p.js → c4Diagram-AHTNJAMY-By-xuh9F.js} +1 -1
- package/payload/server/public/assets/channel-BRPH0atd.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CKn-bEkI.js → chunk-2KRD3SAO-Gj2dSpBl.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DLBJaAyL.js → chunk-336JU56O-2PXVPCUA.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-QhauxjvK.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-B2mSmC97.js → chunk-4BX2VUAB-9XIBlnC2.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-DPHoq8nE.js → chunk-4TB4RGXK-Cr3mXPnI.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-JLT9m7Hd.js → chunk-55IACEB6-Ccg46J3A.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DjxdZ8WO.js → chunk-5FUZZQ4R-Cz9MvPKc.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BujJUZqf.js → chunk-5PVQY5BW-BleOdlgO.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-CCdP3Pdx.js → chunk-67CJDMHE-CyCYCQWy.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-bXgVzdM9.js → chunk-7N4EOEYR-KpT3uHzH.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CYeDvY8B.js → chunk-AA7GKIK3-BfOzbuxq.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-U0Fi-Ers.js → chunk-BSJP7CBP-Bq0M3wlv.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C8QrV6Gg.js → chunk-CIAEETIT-CR-2dNaL.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DF2EBXie.js → chunk-EDXVE4YY-egUGMTOS.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CoTooXpM.js → chunk-ENJZ2VHE-CQohBEFw.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-DxAQS3UB.js → chunk-FMBD7UC4-DIxBUbLP.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-CyIK3zeY.js → chunk-FOC6F5B3-C2694Zoq.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-D8F-S9Bk.js → chunk-ICPOFSXX-DpXZKHyn.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-7GcDzjyJ.js → chunk-K5T4RW27-CUicG0Rp.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-B7pAr9hf.js → chunk-KGLVRYIC-B5mPJhOr.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DEoU2jrz.js → chunk-LIHQZDEY-q81QhuMs.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-BwMFuN24.js → chunk-ORNJ4GCN-DgurdFZs.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C15Ps-tC.js → chunk-OYMX7WX6-CxqMRu2d.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BDAQvtxz.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BBPMxdAI.js → chunk-U2HBQHQK-BSLctJC9.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-xwRszlfe.js → chunk-X2U36JSP--0AUeeFl.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-BA0a8Ygs.js → chunk-XPW4576I-D-hf9Bcn.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-C4liAf7D.js → chunk-YZCP3GAM-PvOhSwI9.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Cy3If_Rl.js → chunk-ZZ45TVLE-1zPUlNWz.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BJv89PB6.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNUszH5M.js +1 -0
- package/payload/server/public/assets/clone-CREg9jLM.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Df_JmB8E.js → cose-bilkent-S5V4N54A-Cvo-gkBd.js} +1 -1
- package/payload/server/public/assets/{dagre-DKCdgCLD.js → dagre-CMHsNfjP.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-DHZ3rA0O.js → dagre-KV5264BT-CM1DSx4E.js} +1 -1
- package/payload/server/public/assets/{data-uiOcPh8T.js → data-Dr7XUvAx.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-XAci8Krv.js → diagram-5BDNPKRD-VDHiHwEI.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DI6g5YJH.js → diagram-G4DWMVQ6-OKdufoeW.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-D94oS42o.js → diagram-MMDJMWI5-Yg6QdCA1.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-D_j5_oj_.js → diagram-TYMM5635-CpEMZQDu.js} +1 -1
- package/payload/server/public/assets/{dist-BmvZ8OaX.js → dist-811BIK0R.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DPx8cHxF.js → erDiagram-SMLLAGMA-Dw5gAkFM.js} +1 -1
- package/payload/server/public/assets/{flatten-Bo6YRmWl.js → flatten-BsWEYbBB.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Cdfxz2_5.js → flowDiagram-DWJPFMVM-Cy_R1XHz.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-oregwFNl.js → ganttDiagram-T4ZO3ILL-BYARP_eH.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CtOPqykB.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BZI26T0o.js → gitGraphDiagram-UUTBAWPF-BGOe0unY.js} +1 -1
- package/payload/server/public/assets/{graph-BSHyF267.js → graph-DOEjjQHD.js} +2 -2
- package/payload/server/public/assets/{graph-labels-D5ecmK-Z.js → graph-labels-eOrWYy0R.js} +1 -1
- package/payload/server/public/assets/{graphlib-BuiXJGQr.js → graphlib-DaefxCga.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-Jba5enA8.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-Df9BlkPA.js +2 -0
- package/payload/server/public/assets/{isEmpty-D6Kr-M1M.js → isEmpty-BWl67LAZ.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DnBy6cze.js → ishikawaDiagram-UXIWVN3A-YrGuzpiI.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DeYkJsvd.js → journeyDiagram-VCZTEJTY-EIykOcqg.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BHuZmXiA.js → kanban-definition-6JOO6SKY-BR0TC6Je.js} +1 -1
- package/payload/server/public/assets/{line-BAjS0lyG.js → line-DPGcT5IM.js} +1 -1
- package/payload/server/public/assets/{linear-COm19-p7.js → linear-CPN03uSh.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Cg06vNXY.js → mermaid-parser.core-D7Iu4c9M.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-DkUCZA6N.js → mermaid.core-krXRpXn9.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-Gbaa7NRj.js → mindmap-definition-QFDTVHPH-HwiCtPzN.js} +1 -1
- package/payload/server/public/assets/{ordinal-BDi6f4xk.js → ordinal-krseTxxN.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-D_eWzeAP.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BDiy1Ob2.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-v7yUgLoq.js → pieDiagram-DEJITSTG-xodxyWLe.js} +1 -1
- package/payload/server/public/assets/{public-CTkj6UYK.js → public-xVaPcg6i.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BpVlNbru.js → quadrantDiagram-34T5L4WZ-DuYYY4ZZ.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-C5mlfmtg.js +1 -0
- package/payload/server/public/assets/{reduce-CGi9ik8i.js → reduce-tk-xY6Fv.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-QrSZzaxF.js → requirementDiagram-MS252O5E-D0ta3kru.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-IVgJCKl1.js → sankeyDiagram-XADWPNL6-KdHdlzvT.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DsN4J_nq.js → sequenceDiagram-FGHM5R23-DoSFUTQZ.js} +1 -1
- package/payload/server/public/assets/{src-DLEIsjER.js → src-Cpl1JzME.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DN0-8ZrI.js → stateDiagram-FHFEXIEX-BLW0KiSA.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5zlCV4X.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BLYu380r.js → timeline-definition-GMOUNBTQ-8QAzhYz1.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CM-9m-cS.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DDHPB-Xh.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-98jrB9kD.css → useSelectionMode-BnRcJeg2.css} +1 -1
- package/payload/server/public/assets/{useSelectionMode-80iYuGPa.js → useSelectionMode-DlJsX-_X.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Tfn8qVAB.js → vennDiagram-DHZGUBPP-BKvfScOi.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-CUb3Br4q.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CeQNnKpT.js → wardleyDiagram-NUSXRM2D-DaMfDpJ3.js} +1 -1
- package/payload/server/public/assets/whatsapp-cDxgZkbM.js +1 -0
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-H-IatOB_.js → xychartDiagram-5P7HB3ND-BIkNQlLa.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/data.html +6 -6
- package/payload/server/public/graph.html +7 -7
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/public/whatsapp.html +18 -0
- package/payload/server/server.js +1022 -800
- package/payload/server/public/assets/AdminShell-BcHJy_Y2.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +0 -1
- package/payload/server/public/assets/channel-1FBBBcz1.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CfdaOTNb.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q--mLJq--t.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C8TJtMFc.js +0 -1
- package/payload/server/public/assets/clone-UUs4PDQ1.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C9cKcMg3.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DGDGYxGd.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +0 -1
- /package/payload/server/public/assets/{_baseFor-Cam2PbSt.js → _baseFor-BHtDrjIo.js} +0 -0
- /package/payload/server/public/assets/{array-DYRGGQae.js → array-DetWRiSa.js} +0 -0
- /package/payload/server/public/assets/{chunk-CnGqDkHZ.js → chunk-CWOGyPgy.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-nWsJMTNI.js → cytoscape.esm-C9yNhe1u.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-Du1XY3Dp.js → defaultLocale-_WRwicXn.js} +0 -0
- /package/payload/server/public/assets/{init-B5BXBRcm.js → init-sTEcj9YX.js} +0 -0
- /package/payload/server/public/assets/{katex-HOUACuRw.js → katex-s61Rgv6l.js} +0 -0
- /package/payload/server/public/assets/{path-CNO468J-.js → path-B0Ik7Tu9.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-DRO6hWPh.js → rough.esm-DKRO8IF-.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1201,8 +1201,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1201
1201
|
};
|
|
1202
1202
|
|
|
1203
1203
|
// server/index.ts
|
|
1204
|
-
import { readFileSync as
|
|
1205
|
-
import { resolve as
|
|
1204
|
+
import { readFileSync as readFileSync24, existsSync as existsSync24, watchFile } from "fs";
|
|
1205
|
+
import { resolve as resolve27, join as join19, basename as basename7 } from "path";
|
|
1206
1206
|
import { homedir as homedir2 } from "os";
|
|
1207
1207
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1208
1208
|
|
|
@@ -1763,7 +1763,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1763
1763
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1764
1764
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1765
1765
|
const timer2 = new Promise(
|
|
1766
|
-
(
|
|
1766
|
+
(resolve28) => setTimeout(() => resolve28("timeout"), timeoutMs)
|
|
1767
1767
|
);
|
|
1768
1768
|
const result = await Promise.race([
|
|
1769
1769
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1891,11 +1891,11 @@ async function createWaSocket(opts) {
|
|
|
1891
1891
|
return sock;
|
|
1892
1892
|
}
|
|
1893
1893
|
async function waitForConnection(sock) {
|
|
1894
|
-
return new Promise((
|
|
1894
|
+
return new Promise((resolve28, reject) => {
|
|
1895
1895
|
const handler = (update) => {
|
|
1896
1896
|
if (update.connection === "open") {
|
|
1897
1897
|
sock.ev.off("connection.update", handler);
|
|
1898
|
-
|
|
1898
|
+
resolve28();
|
|
1899
1899
|
}
|
|
1900
1900
|
if (update.connection === "close") {
|
|
1901
1901
|
sock.ev.off("connection.update", handler);
|
|
@@ -2009,14 +2009,14 @@ ${inspected}`;
|
|
|
2009
2009
|
return inspect2(err, INSPECT_OPTS2);
|
|
2010
2010
|
}
|
|
2011
2011
|
function withTimeout(label, promise, timeoutMs) {
|
|
2012
|
-
return new Promise((
|
|
2012
|
+
return new Promise((resolve28, reject) => {
|
|
2013
2013
|
const timer2 = setTimeout(() => {
|
|
2014
2014
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2015
2015
|
}, timeoutMs);
|
|
2016
2016
|
promise.then(
|
|
2017
2017
|
(value) => {
|
|
2018
2018
|
clearTimeout(timer2);
|
|
2019
|
-
|
|
2019
|
+
resolve28(value);
|
|
2020
2020
|
},
|
|
2021
2021
|
(err) => {
|
|
2022
2022
|
clearTimeout(timer2);
|
|
@@ -2601,8 +2601,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2601
2601
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2602
2602
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2603
2603
|
let release;
|
|
2604
|
-
const mine = new Promise((
|
|
2605
|
-
release =
|
|
2604
|
+
const mine = new Promise((resolve28) => {
|
|
2605
|
+
release = resolve28;
|
|
2606
2606
|
});
|
|
2607
2607
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2608
2608
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3638,11 +3638,11 @@ async function connectWithReconnect(conn) {
|
|
|
3638
3638
|
console.error(
|
|
3639
3639
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3640
3640
|
);
|
|
3641
|
-
await new Promise((
|
|
3642
|
-
const timer2 = setTimeout(
|
|
3641
|
+
await new Promise((resolve28) => {
|
|
3642
|
+
const timer2 = setTimeout(resolve28, delay);
|
|
3643
3643
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3644
3644
|
clearTimeout(timer2);
|
|
3645
|
-
|
|
3645
|
+
resolve28();
|
|
3646
3646
|
}, { once: true });
|
|
3647
3647
|
});
|
|
3648
3648
|
}
|
|
@@ -3650,16 +3650,16 @@ async function connectWithReconnect(conn) {
|
|
|
3650
3650
|
}
|
|
3651
3651
|
}
|
|
3652
3652
|
function waitForDisconnectEvent(conn) {
|
|
3653
|
-
return new Promise((
|
|
3653
|
+
return new Promise((resolve28) => {
|
|
3654
3654
|
if (!conn.sock) {
|
|
3655
|
-
|
|
3655
|
+
resolve28();
|
|
3656
3656
|
return;
|
|
3657
3657
|
}
|
|
3658
3658
|
const sock = conn.sock;
|
|
3659
3659
|
const handler = (update) => {
|
|
3660
3660
|
if (update.connection === "close") {
|
|
3661
3661
|
sock.ev.off("connection.update", handler);
|
|
3662
|
-
|
|
3662
|
+
resolve28();
|
|
3663
3663
|
}
|
|
3664
3664
|
};
|
|
3665
3665
|
sock.ev.on("connection.update", handler);
|
|
@@ -3928,8 +3928,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3928
3928
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3929
3929
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3930
3930
|
let resolvePending;
|
|
3931
|
-
const sttPending = new Promise((
|
|
3932
|
-
resolvePending =
|
|
3931
|
+
const sttPending = new Promise((resolve28) => {
|
|
3932
|
+
resolvePending = resolve28;
|
|
3933
3933
|
});
|
|
3934
3934
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3935
3935
|
try {
|
|
@@ -4338,20 +4338,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4338
4338
|
|
|
4339
4339
|
// server/routes/health.ts
|
|
4340
4340
|
function checkPort(port2, timeoutMs = 500) {
|
|
4341
|
-
return new Promise((
|
|
4341
|
+
return new Promise((resolve28) => {
|
|
4342
4342
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4343
4343
|
socket.setTimeout(timeoutMs);
|
|
4344
4344
|
socket.once("connect", () => {
|
|
4345
4345
|
socket.destroy();
|
|
4346
|
-
|
|
4346
|
+
resolve28(true);
|
|
4347
4347
|
});
|
|
4348
4348
|
socket.once("error", () => {
|
|
4349
4349
|
socket.destroy();
|
|
4350
|
-
|
|
4350
|
+
resolve28(false);
|
|
4351
4351
|
});
|
|
4352
4352
|
socket.once("timeout", () => {
|
|
4353
4353
|
socket.destroy();
|
|
4354
|
-
|
|
4354
|
+
resolve28(false);
|
|
4355
4355
|
});
|
|
4356
4356
|
});
|
|
4357
4357
|
}
|
|
@@ -5426,12 +5426,12 @@ async function dispatchOnce(input) {
|
|
|
5426
5426
|
});
|
|
5427
5427
|
if (!entry) return { error: "spawn-failed" };
|
|
5428
5428
|
entry.lastInboundAt = Date.now();
|
|
5429
|
-
let
|
|
5429
|
+
let resolve28;
|
|
5430
5430
|
const turnPromise = new Promise((r) => {
|
|
5431
|
-
|
|
5431
|
+
resolve28 = r;
|
|
5432
5432
|
});
|
|
5433
5433
|
const listener = (text) => {
|
|
5434
|
-
|
|
5434
|
+
resolve28(text);
|
|
5435
5435
|
};
|
|
5436
5436
|
entry.subscribers.add(listener);
|
|
5437
5437
|
const writeAtMs = Date.now();
|
|
@@ -6269,8 +6269,8 @@ async function startLogin(opts) {
|
|
|
6269
6269
|
await clearAuth(authDir);
|
|
6270
6270
|
let resolveCode = null;
|
|
6271
6271
|
let rejectCode = null;
|
|
6272
|
-
const codePromise = new Promise((
|
|
6273
|
-
resolveCode =
|
|
6272
|
+
const codePromise = new Promise((resolve28, reject) => {
|
|
6273
|
+
resolveCode = resolve28;
|
|
6274
6274
|
rejectCode = reject;
|
|
6275
6275
|
});
|
|
6276
6276
|
const codeTimer = setTimeout(
|
|
@@ -6986,14 +6986,465 @@ app3.get("/group-info", async (c) => {
|
|
|
6986
6986
|
});
|
|
6987
6987
|
var whatsapp_default = app3;
|
|
6988
6988
|
|
|
6989
|
+
// server/routes/whatsapp-reader.ts
|
|
6990
|
+
import { readFileSync as readFileSync9, watch, statSync as statSync3, openSync, readSync, closeSync } from "fs";
|
|
6991
|
+
import { basename as basename2, dirname, join as join8, resolve as resolve9, sep as sep2 } from "path";
|
|
6992
|
+
|
|
6993
|
+
// server/routes/admin/sidebar-sessions.ts
|
|
6994
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
6995
|
+
import { join as join7, resolve as resolve8 } from "path";
|
|
6996
|
+
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
6997
|
+
var PID_FILE_RE = /^([0-9]+)\.json$/;
|
|
6998
|
+
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
6999
|
+
var PUBLIC_ROLE = "public";
|
|
7000
|
+
var WEBCHAT_CHANNEL = "webchat";
|
|
7001
|
+
var app4 = new Hono();
|
|
7002
|
+
function claudeConfigDir() {
|
|
7003
|
+
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
7004
|
+
}
|
|
7005
|
+
function enumerateJsonls(projectsRoot) {
|
|
7006
|
+
const out = [];
|
|
7007
|
+
let slugs;
|
|
7008
|
+
try {
|
|
7009
|
+
slugs = readdirSync4(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
7010
|
+
} catch (err) {
|
|
7011
|
+
if (err.code === "ENOENT") return out;
|
|
7012
|
+
throw err;
|
|
7013
|
+
}
|
|
7014
|
+
for (const slug of slugs) {
|
|
7015
|
+
const slugDir = join7(projectsRoot, slug);
|
|
7016
|
+
let entries;
|
|
7017
|
+
try {
|
|
7018
|
+
entries = readdirSync4(slugDir, { withFileTypes: true });
|
|
7019
|
+
} catch (err) {
|
|
7020
|
+
const code = err.code ?? "unknown";
|
|
7021
|
+
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
7022
|
+
continue;
|
|
7023
|
+
}
|
|
7024
|
+
for (const entry of entries) {
|
|
7025
|
+
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
7026
|
+
out.push({ path: join7(slugDir, entry.name), isSubagent: false });
|
|
7027
|
+
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
7028
|
+
const subDir = join7(slugDir, entry.name);
|
|
7029
|
+
let subEntries;
|
|
7030
|
+
try {
|
|
7031
|
+
subEntries = readdirSync4(subDir, { withFileTypes: true });
|
|
7032
|
+
} catch (err) {
|
|
7033
|
+
const code = err.code ?? "unknown";
|
|
7034
|
+
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
7035
|
+
continue;
|
|
7036
|
+
}
|
|
7037
|
+
for (const sub of subEntries) {
|
|
7038
|
+
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
7039
|
+
out.push({ path: join7(subDir, sub.name), isSubagent: true });
|
|
7040
|
+
}
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
return out;
|
|
7046
|
+
}
|
|
7047
|
+
function sessionIdToPidMap(configDir2) {
|
|
7048
|
+
const out = /* @__PURE__ */ new Map();
|
|
7049
|
+
const sessionsDir = join7(configDir2, "sessions");
|
|
7050
|
+
let entries;
|
|
7051
|
+
try {
|
|
7052
|
+
entries = readdirSync4(sessionsDir, { withFileTypes: true });
|
|
7053
|
+
} catch {
|
|
7054
|
+
return out;
|
|
7055
|
+
}
|
|
7056
|
+
for (const entry of entries) {
|
|
7057
|
+
if (!entry.isFile()) continue;
|
|
7058
|
+
const m = entry.name.match(PID_FILE_RE);
|
|
7059
|
+
if (!m) continue;
|
|
7060
|
+
const pid = Number(m[1]);
|
|
7061
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
7062
|
+
let body;
|
|
7063
|
+
try {
|
|
7064
|
+
body = readFileSync8(join7(sessionsDir, entry.name), "utf8");
|
|
7065
|
+
} catch {
|
|
7066
|
+
continue;
|
|
7067
|
+
}
|
|
7068
|
+
let parsed;
|
|
7069
|
+
try {
|
|
7070
|
+
parsed = JSON.parse(body);
|
|
7071
|
+
} catch {
|
|
7072
|
+
continue;
|
|
7073
|
+
}
|
|
7074
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
7075
|
+
const sid = parsed.sessionId;
|
|
7076
|
+
if (typeof sid === "string" && sid.length > 0) out.set(sid, pid);
|
|
7077
|
+
}
|
|
7078
|
+
return out;
|
|
7079
|
+
}
|
|
7080
|
+
function loadUserTitles(accountDir) {
|
|
7081
|
+
const out = /* @__PURE__ */ new Map();
|
|
7082
|
+
if (!accountDir) return out;
|
|
7083
|
+
const path2 = join7(accountDir, "session-titles.json");
|
|
7084
|
+
let raw;
|
|
7085
|
+
try {
|
|
7086
|
+
raw = readFileSync8(path2, "utf8");
|
|
7087
|
+
} catch {
|
|
7088
|
+
return out;
|
|
7089
|
+
}
|
|
7090
|
+
let parsed;
|
|
7091
|
+
try {
|
|
7092
|
+
parsed = JSON.parse(raw);
|
|
7093
|
+
} catch {
|
|
7094
|
+
return out;
|
|
7095
|
+
}
|
|
7096
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return out;
|
|
7097
|
+
for (const [sessionId, value] of Object.entries(parsed)) {
|
|
7098
|
+
if (!sessionId) continue;
|
|
7099
|
+
if (!value || typeof value !== "object") continue;
|
|
7100
|
+
const v = value;
|
|
7101
|
+
if (typeof v.title !== "string") continue;
|
|
7102
|
+
const trimmed = v.title.trim();
|
|
7103
|
+
if (!trimmed) continue;
|
|
7104
|
+
out.set(sessionId, trimmed);
|
|
7105
|
+
}
|
|
7106
|
+
return out;
|
|
7107
|
+
}
|
|
7108
|
+
function readSidecarMeta(metaPath) {
|
|
7109
|
+
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null };
|
|
7110
|
+
let raw;
|
|
7111
|
+
try {
|
|
7112
|
+
raw = readFileSync8(metaPath, "utf8");
|
|
7113
|
+
} catch {
|
|
7114
|
+
return empty;
|
|
7115
|
+
}
|
|
7116
|
+
let parsed;
|
|
7117
|
+
try {
|
|
7118
|
+
parsed = JSON.parse(raw);
|
|
7119
|
+
} catch {
|
|
7120
|
+
return empty;
|
|
7121
|
+
}
|
|
7122
|
+
if (!parsed || typeof parsed !== "object") return empty;
|
|
7123
|
+
const r = parsed;
|
|
7124
|
+
const bridgeIds = Array.isArray(r.bridgeIds) ? r.bridgeIds.filter((b) => typeof b === "string" && b.length > 0) : [];
|
|
7125
|
+
return {
|
|
7126
|
+
bridgeIds,
|
|
7127
|
+
role: typeof r.role === "string" ? r.role : null,
|
|
7128
|
+
channel: typeof r.channel === "string" ? r.channel : null,
|
|
7129
|
+
senderId: typeof r.senderId === "string" ? r.senderId : null,
|
|
7130
|
+
startedAt: typeof r.startedAt === "string" ? r.startedAt : null
|
|
7131
|
+
};
|
|
7132
|
+
}
|
|
7133
|
+
function startsWithCliMarker(s) {
|
|
7134
|
+
for (const p of CLI_MARKER_PREFIXES) if (s.startsWith(p)) return true;
|
|
7135
|
+
return false;
|
|
7136
|
+
}
|
|
7137
|
+
function trimToTitle(raw) {
|
|
7138
|
+
return raw.trim().replace(/\s+/g, " ");
|
|
7139
|
+
}
|
|
7140
|
+
function resolveTitle(body, sessionId, userTitles) {
|
|
7141
|
+
const userTitle = userTitles.get(sessionId);
|
|
7142
|
+
if (userTitle) return { title: trimToTitle(userTitle), source: "user" };
|
|
7143
|
+
let aiTitle = null;
|
|
7144
|
+
let firstUserMessage = null;
|
|
7145
|
+
for (const line of body.split("\n")) {
|
|
7146
|
+
if (!line || line[0] !== "{") continue;
|
|
7147
|
+
let parsed;
|
|
7148
|
+
try {
|
|
7149
|
+
parsed = JSON.parse(line);
|
|
7150
|
+
} catch {
|
|
7151
|
+
continue;
|
|
7152
|
+
}
|
|
7153
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
7154
|
+
const row = parsed;
|
|
7155
|
+
if (row.type === "ai-title" && typeof row.aiTitle === "string") {
|
|
7156
|
+
const t = row.aiTitle.trim();
|
|
7157
|
+
if (t) aiTitle = t;
|
|
7158
|
+
continue;
|
|
7159
|
+
}
|
|
7160
|
+
if (firstUserMessage === null && row.type === "user" && row.message && row.message.role === "user") {
|
|
7161
|
+
const content = row.message.content;
|
|
7162
|
+
if (typeof content !== "string") continue;
|
|
7163
|
+
const trimmed = content.trim();
|
|
7164
|
+
if (!trimmed) continue;
|
|
7165
|
+
if (startsWithCliMarker(trimmed)) continue;
|
|
7166
|
+
firstUserMessage = trimmed;
|
|
7167
|
+
}
|
|
7168
|
+
}
|
|
7169
|
+
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai" };
|
|
7170
|
+
if (firstUserMessage) return { title: trimToTitle(firstUserMessage), source: "first-message" };
|
|
7171
|
+
return { title: sessionId.slice(0, 8), source: "prefix" };
|
|
7172
|
+
}
|
|
7173
|
+
app4.get("/", requireAdminSession, async (c) => {
|
|
7174
|
+
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
7175
|
+
const configDir2 = claudeConfigDir();
|
|
7176
|
+
if (!configDir2) {
|
|
7177
|
+
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
7178
|
+
return c.json({ sessions: [], accountId });
|
|
7179
|
+
}
|
|
7180
|
+
const projectsRoot = join7(configDir2, "projects");
|
|
7181
|
+
const jsonls = enumerateJsonls(projectsRoot);
|
|
7182
|
+
const pidsBySession = sessionIdToPidMap(configDir2);
|
|
7183
|
+
const accountDir = accountId ? resolve8(ACCOUNTS_DIR, accountId) : null;
|
|
7184
|
+
const userTitles = loadUserTitles(accountDir);
|
|
7185
|
+
const rows = [];
|
|
7186
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
7187
|
+
let liveCount = 0;
|
|
7188
|
+
let subagentCount = 0;
|
|
7189
|
+
let nonResumableCount = 0;
|
|
7190
|
+
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
7191
|
+
for (const { path: path2, isSubagent } of jsonls) {
|
|
7192
|
+
const lastSlash = path2.lastIndexOf("/");
|
|
7193
|
+
const base = path2.slice(lastSlash + 1);
|
|
7194
|
+
const projectDir = path2.slice(0, lastSlash);
|
|
7195
|
+
const sessionId = base.slice(0, -".jsonl".length);
|
|
7196
|
+
if (seenIds.has(sessionId)) {
|
|
7197
|
+
console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path2}`);
|
|
7198
|
+
continue;
|
|
7199
|
+
}
|
|
7200
|
+
seenIds.add(sessionId);
|
|
7201
|
+
let body;
|
|
7202
|
+
let mtimeMs;
|
|
7203
|
+
try {
|
|
7204
|
+
body = readFileSync8(path2, "utf8");
|
|
7205
|
+
mtimeMs = statSync2(path2).mtimeMs;
|
|
7206
|
+
} catch {
|
|
7207
|
+
continue;
|
|
7208
|
+
}
|
|
7209
|
+
const pid = pidsBySession.get(sessionId) ?? null;
|
|
7210
|
+
const live = pid !== null;
|
|
7211
|
+
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
7212
|
+
titleSourceCounts[resolved.source] += 1;
|
|
7213
|
+
const metaPath = join7(projectDir, `${sessionId}.meta.json`);
|
|
7214
|
+
const { bridgeIds, role, channel } = readSidecarMeta(metaPath);
|
|
7215
|
+
const resumable = !(role === PUBLIC_ROLE && channel === WEBCHAT_CHANNEL);
|
|
7216
|
+
rows.push({
|
|
7217
|
+
sessionId,
|
|
7218
|
+
title: resolved.title,
|
|
7219
|
+
titleSource: resolved.source,
|
|
7220
|
+
startedAt: new Date(mtimeMs).toISOString(),
|
|
7221
|
+
live,
|
|
7222
|
+
isSubagent,
|
|
7223
|
+
pid,
|
|
7224
|
+
projectDir,
|
|
7225
|
+
bridgeIds,
|
|
7226
|
+
resumable
|
|
7227
|
+
});
|
|
7228
|
+
if (live) liveCount += 1;
|
|
7229
|
+
if (isSubagent) subagentCount += 1;
|
|
7230
|
+
if (!resumable) nonResumableCount += 1;
|
|
7231
|
+
}
|
|
7232
|
+
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
7233
|
+
console.log(
|
|
7234
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} nonResumable=${nonResumableCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
7235
|
+
);
|
|
7236
|
+
return c.json({ sessions: rows, accountId });
|
|
7237
|
+
});
|
|
7238
|
+
var sidebar_sessions_default = app4;
|
|
7239
|
+
|
|
7240
|
+
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7241
|
+
function selectAdminWhatsappSessions(rows) {
|
|
7242
|
+
return rows.filter((r) => r.role === "admin" && r.channel === "whatsapp").sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7243
|
+
sessionId: r.sessionId,
|
|
7244
|
+
projectDir: r.projectDir,
|
|
7245
|
+
title: r.title,
|
|
7246
|
+
senderId: r.senderId,
|
|
7247
|
+
startedAt: r.startedAt
|
|
7248
|
+
}));
|
|
7249
|
+
}
|
|
7250
|
+
|
|
7251
|
+
// app/lib/whatsapp-reader/parse-transcript.ts
|
|
7252
|
+
var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7253
|
+
var CHANNEL_WRAPPER = /^<channel\b[^>]*>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
7254
|
+
function asString(content) {
|
|
7255
|
+
return typeof content === "string" ? content : null;
|
|
7256
|
+
}
|
|
7257
|
+
function tsOf(row) {
|
|
7258
|
+
return typeof row.timestamp === "string" ? row.timestamp : null;
|
|
7259
|
+
}
|
|
7260
|
+
function assistantTurns(content, ts) {
|
|
7261
|
+
if (!Array.isArray(content)) return [];
|
|
7262
|
+
const out = [];
|
|
7263
|
+
for (const block of content) {
|
|
7264
|
+
if (!block || typeof block !== "object") continue;
|
|
7265
|
+
const b = block;
|
|
7266
|
+
if (b.type === "text" && typeof b.text === "string") {
|
|
7267
|
+
out.push({ kind: "agent-text", text: b.text, ts });
|
|
7268
|
+
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
7269
|
+
out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
|
|
7270
|
+
}
|
|
7271
|
+
}
|
|
7272
|
+
return out;
|
|
7273
|
+
}
|
|
7274
|
+
function toolResultTurns(content, ts) {
|
|
7275
|
+
if (!Array.isArray(content)) return [];
|
|
7276
|
+
const out = [];
|
|
7277
|
+
for (const block of content) {
|
|
7278
|
+
if (!block || typeof block !== "object") continue;
|
|
7279
|
+
const b = block;
|
|
7280
|
+
if (b.type !== "tool_result") continue;
|
|
7281
|
+
const text = typeof b.content === "string" ? b.content : Array.isArray(b.content) ? b.content.map(
|
|
7282
|
+
(c) => c && typeof c === "object" && typeof c.text === "string" ? c.text : ""
|
|
7283
|
+
).join("") : "";
|
|
7284
|
+
out.push({ kind: "tool-result", text, isError: b.is_error === true, ts });
|
|
7285
|
+
}
|
|
7286
|
+
return out;
|
|
7287
|
+
}
|
|
7288
|
+
function parseTranscript(lines) {
|
|
7289
|
+
const out = [];
|
|
7290
|
+
for (const line of lines) {
|
|
7291
|
+
if (!line || line[0] !== "{") continue;
|
|
7292
|
+
let row;
|
|
7293
|
+
try {
|
|
7294
|
+
const parsed = JSON.parse(line);
|
|
7295
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
7296
|
+
row = parsed;
|
|
7297
|
+
} catch {
|
|
7298
|
+
continue;
|
|
7299
|
+
}
|
|
7300
|
+
const ts = tsOf(row);
|
|
7301
|
+
const msg = row.message;
|
|
7302
|
+
if (row.type === "assistant") {
|
|
7303
|
+
out.push(...assistantTurns(msg?.content, ts));
|
|
7304
|
+
continue;
|
|
7305
|
+
}
|
|
7306
|
+
if (row.type !== "user" || !msg) continue;
|
|
7307
|
+
if (Array.isArray(msg.content)) {
|
|
7308
|
+
out.push(...toolResultTurns(msg.content, ts));
|
|
7309
|
+
continue;
|
|
7310
|
+
}
|
|
7311
|
+
const text = asString(msg.content);
|
|
7312
|
+
if (text === null) continue;
|
|
7313
|
+
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7314
|
+
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel";
|
|
7315
|
+
if (isChannel) {
|
|
7316
|
+
const m = text.match(CHANNEL_WRAPPER);
|
|
7317
|
+
out.push({ kind: "operator-inbound", text: m ? m[1] : text, ts });
|
|
7318
|
+
} else {
|
|
7319
|
+
out.push({ kind: "operator-typed", text, ts });
|
|
7320
|
+
}
|
|
7321
|
+
}
|
|
7322
|
+
return out;
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
// app/lib/whatsapp-reader/tail.ts
|
|
7326
|
+
function splitNewLines(buf, baseOffset) {
|
|
7327
|
+
const text = buf.toString("utf8");
|
|
7328
|
+
const lastNl = text.lastIndexOf("\n");
|
|
7329
|
+
if (lastNl === -1) return { lines: [], nextOffset: baseOffset };
|
|
7330
|
+
const complete = text.slice(0, lastNl);
|
|
7331
|
+
const consumedBytes = Buffer.byteLength(text.slice(0, lastNl + 1), "utf8");
|
|
7332
|
+
return {
|
|
7333
|
+
lines: complete.split("\n").filter((l) => l.length > 0),
|
|
7334
|
+
nextOffset: baseOffset + consumedBytes
|
|
7335
|
+
};
|
|
7336
|
+
}
|
|
7337
|
+
|
|
7338
|
+
// server/routes/whatsapp-reader.ts
|
|
7339
|
+
var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7340
|
+
var app5 = new Hono();
|
|
7341
|
+
app5.get("/conversations", requireAdminSession, async (c) => {
|
|
7342
|
+
const cfg = claudeConfigDir();
|
|
7343
|
+
if (!cfg) return c.json({ conversations: [] });
|
|
7344
|
+
const projectsRoot = join8(cfg, "projects");
|
|
7345
|
+
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7346
|
+
const rows = [];
|
|
7347
|
+
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7348
|
+
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7349
|
+
const projectDir = dirname(path2);
|
|
7350
|
+
const meta = readSidecarMeta(join8(projectDir, `${sessionId}.meta.json`));
|
|
7351
|
+
if (meta.role !== "admin" || meta.channel !== "whatsapp") continue;
|
|
7352
|
+
let body = "";
|
|
7353
|
+
try {
|
|
7354
|
+
body = readFileSync9(path2, "utf8");
|
|
7355
|
+
} catch {
|
|
7356
|
+
}
|
|
7357
|
+
const { title } = resolveTitle(body, sessionId, userTitles);
|
|
7358
|
+
rows.push({
|
|
7359
|
+
sessionId,
|
|
7360
|
+
projectDir,
|
|
7361
|
+
title,
|
|
7362
|
+
startedAt: meta.startedAt ?? "",
|
|
7363
|
+
role: meta.role,
|
|
7364
|
+
channel: meta.channel,
|
|
7365
|
+
senderId: meta.senderId
|
|
7366
|
+
});
|
|
7367
|
+
}
|
|
7368
|
+
return c.json({ conversations: selectAdminWhatsappSessions(rows) });
|
|
7369
|
+
});
|
|
7370
|
+
function readFrom(path2, from) {
|
|
7371
|
+
const end = statSync3(path2).size;
|
|
7372
|
+
if (end <= from) return { buf: Buffer.alloc(0), end: from };
|
|
7373
|
+
const fd = openSync(path2, "r");
|
|
7374
|
+
try {
|
|
7375
|
+
const buf = Buffer.alloc(end - from);
|
|
7376
|
+
readSync(fd, buf, 0, buf.length, from);
|
|
7377
|
+
return { buf, end };
|
|
7378
|
+
} finally {
|
|
7379
|
+
closeSync(fd);
|
|
7380
|
+
}
|
|
7381
|
+
}
|
|
7382
|
+
app5.get("/stream", requireAdminSession, (c) => {
|
|
7383
|
+
const sessionId = c.req.query("sessionId") ?? "";
|
|
7384
|
+
const projectDir = c.req.query("projectDir") ?? "";
|
|
7385
|
+
const cfg = claudeConfigDir();
|
|
7386
|
+
const projectsRoot = cfg ? resolve9(join8(cfg, "projects")) : null;
|
|
7387
|
+
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7388
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7389
|
+
}
|
|
7390
|
+
const jsonlPath = resolve9(join8(projectDir, `${sessionId}.jsonl`));
|
|
7391
|
+
if (!jsonlPath.startsWith(projectsRoot + sep2)) {
|
|
7392
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7393
|
+
}
|
|
7394
|
+
const encoder = new TextEncoder();
|
|
7395
|
+
const send = (controller, turn) => controller.enqueue(encoder.encode(`data: ${JSON.stringify(turn)}
|
|
7396
|
+
|
|
7397
|
+
`));
|
|
7398
|
+
const readable = new ReadableStream({
|
|
7399
|
+
start(controller) {
|
|
7400
|
+
let offset = 0;
|
|
7401
|
+
const drain = () => {
|
|
7402
|
+
try {
|
|
7403
|
+
const { buf, end } = readFrom(jsonlPath, offset);
|
|
7404
|
+
if (end <= offset) return;
|
|
7405
|
+
const { lines, nextOffset } = splitNewLines(buf, offset);
|
|
7406
|
+
offset = nextOffset;
|
|
7407
|
+
for (const turn of parseTranscript(lines)) send(controller, turn);
|
|
7408
|
+
} catch {
|
|
7409
|
+
}
|
|
7410
|
+
};
|
|
7411
|
+
try {
|
|
7412
|
+
const { buf, end } = readFrom(jsonlPath, 0);
|
|
7413
|
+
offset = end;
|
|
7414
|
+
for (const turn of parseTranscript(buf.toString("utf8").split("\n"))) send(controller, turn);
|
|
7415
|
+
} catch {
|
|
7416
|
+
controller.enqueue(encoder.encode('event: error\ndata: "read-failed"\n\n'));
|
|
7417
|
+
}
|
|
7418
|
+
let watcher = null;
|
|
7419
|
+
try {
|
|
7420
|
+
watcher = watch(jsonlPath, drain);
|
|
7421
|
+
} catch {
|
|
7422
|
+
}
|
|
7423
|
+
const poll = setInterval(drain, 1e3);
|
|
7424
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
7425
|
+
watcher?.close();
|
|
7426
|
+
clearInterval(poll);
|
|
7427
|
+
try {
|
|
7428
|
+
controller.close();
|
|
7429
|
+
} catch {
|
|
7430
|
+
}
|
|
7431
|
+
});
|
|
7432
|
+
}
|
|
7433
|
+
});
|
|
7434
|
+
return new Response(readable, {
|
|
7435
|
+
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
|
|
7436
|
+
});
|
|
7437
|
+
});
|
|
7438
|
+
var whatsapp_reader_default = app5;
|
|
7439
|
+
|
|
6989
7440
|
// server/routes/onboarding.ts
|
|
6990
7441
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
6991
|
-
import { openSync, closeSync, writeFileSync as writeFileSync6, writeSync, existsSync as existsSync7, readFileSync as
|
|
7442
|
+
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync6, writeSync, existsSync as existsSync7, readFileSync as readFileSync11, unlinkSync } from "fs";
|
|
6992
7443
|
import { createHash as createHash2, randomUUID as randomUUID7 } from "crypto";
|
|
6993
7444
|
|
|
6994
7445
|
// ../lib/admins-write/src/index.ts
|
|
6995
|
-
import { existsSync as existsSync6, readFileSync as
|
|
6996
|
-
import { dirname, join as
|
|
7446
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5, renameSync, mkdirSync as mkdirSync2, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
7447
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
6997
7448
|
function logLine(input, result) {
|
|
6998
7449
|
const userIdShort = input.userId.slice(0, 8);
|
|
6999
7450
|
console.error(
|
|
@@ -7001,7 +7452,7 @@ function logLine(input, result) {
|
|
|
7001
7452
|
);
|
|
7002
7453
|
}
|
|
7003
7454
|
function writeFileAtomic(filePath, contents, mode) {
|
|
7004
|
-
mkdirSync2(
|
|
7455
|
+
mkdirSync2(dirname2(filePath), { recursive: true });
|
|
7005
7456
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
7006
7457
|
writeFileSync5(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
7007
7458
|
renameSync(tempPath, filePath);
|
|
@@ -7011,7 +7462,7 @@ function writeAdminEntry(input) {
|
|
|
7011
7462
|
try {
|
|
7012
7463
|
let users = [];
|
|
7013
7464
|
if (existsSync6(input.usersFile)) {
|
|
7014
|
-
const raw =
|
|
7465
|
+
const raw = readFileSync10(input.usersFile, "utf-8").trim();
|
|
7015
7466
|
if (raw) {
|
|
7016
7467
|
const parsed = JSON.parse(raw);
|
|
7017
7468
|
if (!Array.isArray(parsed)) {
|
|
@@ -7035,11 +7486,11 @@ function writeAdminEntry(input) {
|
|
|
7035
7486
|
return result;
|
|
7036
7487
|
}
|
|
7037
7488
|
try {
|
|
7038
|
-
const accountJsonPath =
|
|
7489
|
+
const accountJsonPath = join9(input.accountDir, "account.json");
|
|
7039
7490
|
if (!existsSync6(accountJsonPath)) {
|
|
7040
7491
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
7041
7492
|
}
|
|
7042
|
-
const config = JSON.parse(
|
|
7493
|
+
const config = JSON.parse(readFileSync10(accountJsonPath, "utf-8"));
|
|
7043
7494
|
const admins = config.admins ?? [];
|
|
7044
7495
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
7045
7496
|
result.accountJsonResult = "noop";
|
|
@@ -7065,7 +7516,7 @@ function checkAdminAuthInvariant(input) {
|
|
|
7065
7516
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
7066
7517
|
if (existsSync6(input.usersFile)) {
|
|
7067
7518
|
try {
|
|
7068
|
-
const raw =
|
|
7519
|
+
const raw = readFileSync10(input.usersFile, "utf-8").trim();
|
|
7069
7520
|
if (raw) {
|
|
7070
7521
|
const users = JSON.parse(raw);
|
|
7071
7522
|
for (const u of users) {
|
|
@@ -7081,7 +7532,7 @@ function checkAdminAuthInvariant(input) {
|
|
|
7081
7532
|
if (existsSync6(input.accountsDir)) {
|
|
7082
7533
|
let entries;
|
|
7083
7534
|
try {
|
|
7084
|
-
entries =
|
|
7535
|
+
entries = readdirSync5(input.accountsDir);
|
|
7085
7536
|
} catch (err) {
|
|
7086
7537
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7087
7538
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -7090,17 +7541,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
7090
7541
|
}
|
|
7091
7542
|
for (const entry of entries) {
|
|
7092
7543
|
if (entry.startsWith(".")) continue;
|
|
7093
|
-
const accountDir =
|
|
7544
|
+
const accountDir = join9(input.accountsDir, entry);
|
|
7094
7545
|
try {
|
|
7095
|
-
if (!
|
|
7546
|
+
if (!statSync4(accountDir).isDirectory()) continue;
|
|
7096
7547
|
} catch {
|
|
7097
7548
|
continue;
|
|
7098
7549
|
}
|
|
7099
|
-
const accountJsonPath =
|
|
7550
|
+
const accountJsonPath = join9(accountDir, "account.json");
|
|
7100
7551
|
if (!existsSync6(accountJsonPath)) continue;
|
|
7101
7552
|
let admins = [];
|
|
7102
7553
|
try {
|
|
7103
|
-
const config = JSON.parse(
|
|
7554
|
+
const config = JSON.parse(readFileSync10(accountJsonPath, "utf-8"));
|
|
7104
7555
|
admins = config.admins ?? [];
|
|
7105
7556
|
} catch (err) {
|
|
7106
7557
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -7141,7 +7592,7 @@ function hashPin(pin) {
|
|
|
7141
7592
|
}
|
|
7142
7593
|
function readUsersFile() {
|
|
7143
7594
|
if (!existsSync7(USERS_FILE)) return null;
|
|
7144
|
-
const raw =
|
|
7595
|
+
const raw = readFileSync11(USERS_FILE, "utf-8").trim();
|
|
7145
7596
|
if (!raw) return [];
|
|
7146
7597
|
return JSON.parse(raw);
|
|
7147
7598
|
}
|
|
@@ -7171,11 +7622,11 @@ async function waitForAuthPage(timeoutMs = 2e4) {
|
|
|
7171
7622
|
}
|
|
7172
7623
|
return false;
|
|
7173
7624
|
}
|
|
7174
|
-
var
|
|
7175
|
-
|
|
7625
|
+
var app6 = new Hono();
|
|
7626
|
+
app6.get("/claude-auth", async (c) => {
|
|
7176
7627
|
return c.json({ authenticated: await checkAuthStatus() });
|
|
7177
7628
|
});
|
|
7178
|
-
|
|
7629
|
+
app6.post("/claude-auth", async (c) => {
|
|
7179
7630
|
let body = {};
|
|
7180
7631
|
try {
|
|
7181
7632
|
body = await c.req.json();
|
|
@@ -7207,7 +7658,7 @@ app4.post("/claude-auth", async (c) => {
|
|
|
7207
7658
|
}
|
|
7208
7659
|
ensureLogDir();
|
|
7209
7660
|
writeFileSync6(logPath("claude-auth"), "");
|
|
7210
|
-
const claudeAuthLogFd =
|
|
7661
|
+
const claudeAuthLogFd = openSync2(logPath("claude-auth"), "a");
|
|
7211
7662
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
7212
7663
|
if (process.platform === "darwin") {
|
|
7213
7664
|
vncLog("claude-auth", { action: "start", transport: "native", platform: "darwin" });
|
|
@@ -7217,7 +7668,7 @@ app4.post("/claude-auth", async (c) => {
|
|
|
7217
7668
|
claudeProc2.unref();
|
|
7218
7669
|
claudeProc2.stdout?.on("data", onClaudeOutput);
|
|
7219
7670
|
claudeProc2.stderr?.on("data", onClaudeOutput);
|
|
7220
|
-
claudeProc2.once("close", () =>
|
|
7671
|
+
claudeProc2.once("close", () => closeSync2(claudeAuthLogFd));
|
|
7221
7672
|
return c.json({ started: true, transport: "native" });
|
|
7222
7673
|
}
|
|
7223
7674
|
if (transport === "vnc") {
|
|
@@ -7235,11 +7686,11 @@ app4.post("/claude-auth", async (c) => {
|
|
|
7235
7686
|
claudeProc.unref();
|
|
7236
7687
|
claudeProc.stdout?.on("data", onClaudeOutput);
|
|
7237
7688
|
claudeProc.stderr?.on("data", onClaudeOutput);
|
|
7238
|
-
claudeProc.once("close", () =>
|
|
7689
|
+
claudeProc.once("close", () => closeSync2(claudeAuthLogFd));
|
|
7239
7690
|
await waitForAuthPage(2e4);
|
|
7240
7691
|
return c.json({ started: true, transport });
|
|
7241
7692
|
});
|
|
7242
|
-
|
|
7693
|
+
app6.post("/set-pin", async (c) => {
|
|
7243
7694
|
let existingUsers = null;
|
|
7244
7695
|
try {
|
|
7245
7696
|
existingUsers = readUsersFile();
|
|
@@ -7297,7 +7748,7 @@ app4.post("/set-pin", async (c) => {
|
|
|
7297
7748
|
let installOwner = null;
|
|
7298
7749
|
if (existsSync7(INSTALL_OWNER_FILE)) {
|
|
7299
7750
|
try {
|
|
7300
|
-
const raw =
|
|
7751
|
+
const raw = readFileSync11(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
7301
7752
|
if (raw.length > 0) installOwner = raw;
|
|
7302
7753
|
} catch (err) {
|
|
7303
7754
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7341,7 +7792,7 @@ ${body.pin}
|
|
|
7341
7792
|
}
|
|
7342
7793
|
return c.json({ ok: true });
|
|
7343
7794
|
});
|
|
7344
|
-
|
|
7795
|
+
app6.delete("/set-pin", async (c) => {
|
|
7345
7796
|
let users = null;
|
|
7346
7797
|
try {
|
|
7347
7798
|
users = readUsersFile();
|
|
@@ -7375,12 +7826,12 @@ app4.delete("/set-pin", async (c) => {
|
|
|
7375
7826
|
}
|
|
7376
7827
|
return c.json({ ok: true });
|
|
7377
7828
|
});
|
|
7378
|
-
var onboarding_default =
|
|
7829
|
+
var onboarding_default = app6;
|
|
7379
7830
|
|
|
7380
7831
|
// server/routes/client-error.ts
|
|
7381
|
-
import { appendFileSync, existsSync as existsSync8, renameSync as renameSync2, statSync as
|
|
7382
|
-
import { join as
|
|
7383
|
-
var CLIENT_ERRORS_LOG =
|
|
7832
|
+
import { appendFileSync, existsSync as existsSync8, renameSync as renameSync2, statSync as statSync5 } from "fs";
|
|
7833
|
+
import { join as join10 } from "path";
|
|
7834
|
+
var CLIENT_ERRORS_LOG = join10(LOG_DIR, "client-errors.log");
|
|
7384
7835
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
7385
7836
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
7386
7837
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -7424,15 +7875,15 @@ function stackHead(stack) {
|
|
|
7424
7875
|
function rotateIfNeeded() {
|
|
7425
7876
|
try {
|
|
7426
7877
|
if (!existsSync8(CLIENT_ERRORS_LOG)) return;
|
|
7427
|
-
const stats =
|
|
7878
|
+
const stats = statSync5(CLIENT_ERRORS_LOG);
|
|
7428
7879
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
7429
7880
|
renameSync2(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
7430
7881
|
} catch (err) {
|
|
7431
7882
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
7432
7883
|
}
|
|
7433
7884
|
}
|
|
7434
|
-
var
|
|
7435
|
-
|
|
7885
|
+
var app7 = new Hono();
|
|
7886
|
+
app7.post("/", async (c) => {
|
|
7436
7887
|
const client = resolveClientIp(
|
|
7437
7888
|
c.env?.incoming?.socket?.remoteAddress,
|
|
7438
7889
|
c.req.header("x-forwarded-for")
|
|
@@ -7534,21 +7985,21 @@ app5.post("/", async (c) => {
|
|
|
7534
7985
|
}
|
|
7535
7986
|
return c.json({ ok: true });
|
|
7536
7987
|
});
|
|
7537
|
-
var client_error_default =
|
|
7988
|
+
var client_error_default = app7;
|
|
7538
7989
|
|
|
7539
7990
|
// server/routes/admin/session.ts
|
|
7540
7991
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
7541
7992
|
|
|
7542
7993
|
// app/lib/admin-identity/pin-validator.ts
|
|
7543
7994
|
import { createHash as createHash3 } from "crypto";
|
|
7544
|
-
import { existsSync as existsSync9, readFileSync as
|
|
7545
|
-
import { join as
|
|
7995
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
|
|
7996
|
+
import { join as join11 } from "path";
|
|
7546
7997
|
function hashPin2(pin) {
|
|
7547
7998
|
return createHash3("sha256").update(pin).digest("hex");
|
|
7548
7999
|
}
|
|
7549
8000
|
function readUsersFile2(usersFilePath) {
|
|
7550
8001
|
if (!existsSync9(usersFilePath)) return null;
|
|
7551
|
-
const raw =
|
|
8002
|
+
const raw = readFileSync12(usersFilePath, "utf-8").trim();
|
|
7552
8003
|
if (!raw) return [];
|
|
7553
8004
|
return JSON.parse(raw);
|
|
7554
8005
|
}
|
|
@@ -7570,22 +8021,22 @@ function scanForOrphanedAccountAdmins(users, accountsDir) {
|
|
|
7570
8021
|
if (!existsSync9(accountsDir)) return orphans;
|
|
7571
8022
|
let entries;
|
|
7572
8023
|
try {
|
|
7573
|
-
entries =
|
|
8024
|
+
entries = readdirSync6(accountsDir);
|
|
7574
8025
|
} catch {
|
|
7575
8026
|
return orphans;
|
|
7576
8027
|
}
|
|
7577
8028
|
for (const entry of entries) {
|
|
7578
8029
|
if (entry.startsWith(".")) continue;
|
|
7579
|
-
const accountDir =
|
|
8030
|
+
const accountDir = join11(accountsDir, entry);
|
|
7580
8031
|
try {
|
|
7581
|
-
if (!
|
|
8032
|
+
if (!statSync6(accountDir).isDirectory()) continue;
|
|
7582
8033
|
} catch {
|
|
7583
8034
|
continue;
|
|
7584
8035
|
}
|
|
7585
|
-
const accountJsonPath =
|
|
8036
|
+
const accountJsonPath = join11(accountDir, "account.json");
|
|
7586
8037
|
if (!existsSync9(accountJsonPath)) continue;
|
|
7587
8038
|
try {
|
|
7588
|
-
const config = JSON.parse(
|
|
8039
|
+
const config = JSON.parse(readFileSync12(accountJsonPath, "utf-8"));
|
|
7589
8040
|
const admins = config.admins ?? [];
|
|
7590
8041
|
for (const a of admins) {
|
|
7591
8042
|
if (typeof a.userId === "string" && !known.has(a.userId)) orphans.push(a.userId);
|
|
@@ -7652,8 +8103,8 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
7652
8103
|
sessionId: initialSessionId
|
|
7653
8104
|
};
|
|
7654
8105
|
}
|
|
7655
|
-
var
|
|
7656
|
-
|
|
8106
|
+
var app8 = new Hono();
|
|
8107
|
+
app8.get("/", async (c) => {
|
|
7657
8108
|
const signedSessionToken = c.req.query("session_key");
|
|
7658
8109
|
if (!signedSessionToken) {
|
|
7659
8110
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
@@ -7699,7 +8150,7 @@ app6.get("/", async (c) => {
|
|
|
7699
8150
|
sessionId: getSessionIdForSession(cacheKey) ?? null
|
|
7700
8151
|
});
|
|
7701
8152
|
});
|
|
7702
|
-
|
|
8153
|
+
app8.post("/", async (c) => {
|
|
7703
8154
|
let body;
|
|
7704
8155
|
try {
|
|
7705
8156
|
body = await c.req.json();
|
|
@@ -7762,20 +8213,20 @@ app6.post("/", async (c) => {
|
|
|
7762
8213
|
const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
|
|
7763
8214
|
return c.json(payload);
|
|
7764
8215
|
});
|
|
7765
|
-
var session_default =
|
|
8216
|
+
var session_default = app8;
|
|
7766
8217
|
|
|
7767
8218
|
// server/routes/admin/logs.ts
|
|
7768
|
-
import { existsSync as existsSync11, readdirSync as
|
|
7769
|
-
import { resolve as
|
|
8219
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync7 } from "fs";
|
|
8220
|
+
import { resolve as resolve10, basename as basename3 } from "path";
|
|
7770
8221
|
|
|
7771
8222
|
// app/lib/logs-read-resolve.ts
|
|
7772
8223
|
import { existsSync as existsSync10 } from "fs";
|
|
7773
|
-
import { join as
|
|
8224
|
+
import { join as join12 } from "path";
|
|
7774
8225
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
7775
8226
|
const tried = [filename];
|
|
7776
8227
|
const hits = [];
|
|
7777
8228
|
for (const dir of logDirs) {
|
|
7778
|
-
const fullPath =
|
|
8229
|
+
const fullPath = join12(dir, filename);
|
|
7779
8230
|
if (existsSync10(fullPath)) {
|
|
7780
8231
|
hits.push({ path: fullPath, dir });
|
|
7781
8232
|
}
|
|
@@ -7785,27 +8236,27 @@ function resolveSessionLogPaths(filename, logDirs) {
|
|
|
7785
8236
|
|
|
7786
8237
|
// server/routes/admin/logs.ts
|
|
7787
8238
|
var TAIL_BYTES = 8192;
|
|
7788
|
-
var
|
|
7789
|
-
|
|
8239
|
+
var app9 = new Hono();
|
|
8240
|
+
app9.get("/", async (c) => {
|
|
7790
8241
|
const fileParam = c.req.query("file");
|
|
7791
8242
|
const typeParam = c.req.query("type");
|
|
7792
8243
|
const sessionIdParam = c.req.query("sessionId");
|
|
7793
8244
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
7794
8245
|
const download = c.req.query("download") === "1";
|
|
7795
8246
|
const account = resolveAccount();
|
|
7796
|
-
const accountLogDir = account ?
|
|
8247
|
+
const accountLogDir = account ? resolve10(account.accountDir, "logs") : null;
|
|
7797
8248
|
const logDirs = [];
|
|
7798
8249
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
7799
8250
|
logDirs.push(LOG_DIR);
|
|
7800
8251
|
if (fileParam) {
|
|
7801
|
-
const safe =
|
|
8252
|
+
const safe = basename3(fileParam);
|
|
7802
8253
|
const searched = [];
|
|
7803
8254
|
for (const dir of logDirs) {
|
|
7804
|
-
const filePath =
|
|
8255
|
+
const filePath = resolve10(dir, safe);
|
|
7805
8256
|
searched.push(filePath);
|
|
7806
8257
|
try {
|
|
7807
|
-
const buffer =
|
|
7808
|
-
const onDiskBytes =
|
|
8258
|
+
const buffer = readFileSync13(filePath);
|
|
8259
|
+
const onDiskBytes = statSync7(filePath).size;
|
|
7809
8260
|
const headers = {
|
|
7810
8261
|
"Content-Type": "text/plain; charset=utf-8",
|
|
7811
8262
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -7868,9 +8319,9 @@ app7.get("/", async (c) => {
|
|
|
7868
8319
|
if (hit) {
|
|
7869
8320
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
7870
8321
|
try {
|
|
7871
|
-
const filename =
|
|
7872
|
-
const buffer =
|
|
7873
|
-
const onDiskBytes =
|
|
8322
|
+
const filename = basename3(hit.path);
|
|
8323
|
+
const buffer = readFileSync13(hit.path);
|
|
8324
|
+
const onDiskBytes = statSync7(hit.path).size;
|
|
7874
8325
|
const headers = {
|
|
7875
8326
|
"Content-Type": "text/plain; charset=utf-8",
|
|
7876
8327
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -7907,16 +8358,16 @@ app7.get("/", async (c) => {
|
|
|
7907
8358
|
if (!existsSync11(dir)) continue;
|
|
7908
8359
|
let files;
|
|
7909
8360
|
try {
|
|
7910
|
-
files =
|
|
8361
|
+
files = readdirSync7(dir).filter((f) => f.endsWith(".log"));
|
|
7911
8362
|
} catch (err) {
|
|
7912
8363
|
const reason = err instanceof Error ? err.message : String(err);
|
|
7913
8364
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
7914
8365
|
continue;
|
|
7915
8366
|
}
|
|
7916
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime:
|
|
8367
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve10(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
7917
8368
|
seen.add(name);
|
|
7918
8369
|
try {
|
|
7919
|
-
const content =
|
|
8370
|
+
const content = readFileSync13(resolve10(dir, name));
|
|
7920
8371
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
7921
8372
|
logs[name] = tail.trim() || "(empty)";
|
|
7922
8373
|
} catch (err) {
|
|
@@ -7928,12 +8379,12 @@ app7.get("/", async (c) => {
|
|
|
7928
8379
|
}
|
|
7929
8380
|
return c.json({ logs });
|
|
7930
8381
|
});
|
|
7931
|
-
var logs_default =
|
|
8382
|
+
var logs_default = app9;
|
|
7932
8383
|
|
|
7933
8384
|
// server/routes/admin/claude-info.ts
|
|
7934
8385
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7935
|
-
var
|
|
7936
|
-
|
|
8386
|
+
var app10 = new Hono();
|
|
8387
|
+
app10.get("/", (c) => {
|
|
7937
8388
|
let version = "unknown";
|
|
7938
8389
|
try {
|
|
7939
8390
|
const raw = execFileSync3("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
@@ -7951,14 +8402,14 @@ app8.get("/", (c) => {
|
|
|
7951
8402
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
7952
8403
|
return c.json({ version, account, model, thinkingView });
|
|
7953
8404
|
});
|
|
7954
|
-
var claude_info_default =
|
|
8405
|
+
var claude_info_default = app10;
|
|
7955
8406
|
|
|
7956
8407
|
// server/routes/admin/attachment.ts
|
|
7957
8408
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
7958
8409
|
import { existsSync as existsSync12 } from "fs";
|
|
7959
|
-
import { resolve as
|
|
7960
|
-
var
|
|
7961
|
-
|
|
8410
|
+
import { resolve as resolve11 } from "path";
|
|
8411
|
+
var app11 = new Hono();
|
|
8412
|
+
app11.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
7962
8413
|
const attachmentId = c.req.param("attachmentId");
|
|
7963
8414
|
const cacheKey = c.var.cacheKey;
|
|
7964
8415
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -7968,11 +8419,11 @@ app9.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
7968
8419
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
7969
8420
|
return new Response("Not found", { status: 404 });
|
|
7970
8421
|
}
|
|
7971
|
-
const dir =
|
|
8422
|
+
const dir = resolve11(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
7972
8423
|
if (!existsSync12(dir)) {
|
|
7973
8424
|
return new Response("Not found", { status: 404 });
|
|
7974
8425
|
}
|
|
7975
|
-
const metaPath =
|
|
8426
|
+
const metaPath = resolve11(dir, `${attachmentId}.meta.json`);
|
|
7976
8427
|
if (!existsSync12(metaPath)) {
|
|
7977
8428
|
return new Response("Not found", { status: 404 });
|
|
7978
8429
|
}
|
|
@@ -7987,7 +8438,7 @@ app9.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
7987
8438
|
if (!dataFile) {
|
|
7988
8439
|
return new Response("Not found", { status: 404 });
|
|
7989
8440
|
}
|
|
7990
|
-
const filePath =
|
|
8441
|
+
const filePath = resolve11(dir, dataFile);
|
|
7991
8442
|
const buffer = await readFile2(filePath);
|
|
7992
8443
|
return new Response(new Uint8Array(buffer), {
|
|
7993
8444
|
headers: {
|
|
@@ -7997,27 +8448,27 @@ app9.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
7997
8448
|
}
|
|
7998
8449
|
});
|
|
7999
8450
|
});
|
|
8000
|
-
var attachment_default =
|
|
8451
|
+
var attachment_default = app11;
|
|
8001
8452
|
|
|
8002
8453
|
// server/routes/admin/agents.ts
|
|
8003
|
-
import { resolve as
|
|
8004
|
-
import { readdirSync as
|
|
8005
|
-
var
|
|
8006
|
-
|
|
8454
|
+
import { resolve as resolve12 } from "path";
|
|
8455
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, existsSync as existsSync13, rmSync } from "fs";
|
|
8456
|
+
var app12 = new Hono();
|
|
8457
|
+
app12.get("/", (c) => {
|
|
8007
8458
|
const account = resolveAccount();
|
|
8008
8459
|
if (!account) return c.json({ agents: [] });
|
|
8009
|
-
const agentsDir =
|
|
8460
|
+
const agentsDir = resolve12(account.accountDir, "agents");
|
|
8010
8461
|
if (!existsSync13(agentsDir)) return c.json({ agents: [] });
|
|
8011
8462
|
const agents = [];
|
|
8012
8463
|
try {
|
|
8013
|
-
const entries =
|
|
8464
|
+
const entries = readdirSync8(agentsDir, { withFileTypes: true });
|
|
8014
8465
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
8015
8466
|
if (!entry.isDirectory()) continue;
|
|
8016
8467
|
if (entry.name === "admin") continue;
|
|
8017
|
-
const configPath2 =
|
|
8468
|
+
const configPath2 = resolve12(agentsDir, entry.name, "config.json");
|
|
8018
8469
|
if (!existsSync13(configPath2)) continue;
|
|
8019
8470
|
try {
|
|
8020
|
-
const config = JSON.parse(
|
|
8471
|
+
const config = JSON.parse(readFileSync14(configPath2, "utf-8"));
|
|
8021
8472
|
agents.push({
|
|
8022
8473
|
slug: entry.name,
|
|
8023
8474
|
displayName: config.displayName ?? entry.name,
|
|
@@ -8033,7 +8484,7 @@ app10.get("/", (c) => {
|
|
|
8033
8484
|
}
|
|
8034
8485
|
return c.json({ agents });
|
|
8035
8486
|
});
|
|
8036
|
-
|
|
8487
|
+
app12.delete("/:slug", async (c) => {
|
|
8037
8488
|
const slug = c.req.param("slug");
|
|
8038
8489
|
const account = resolveAccount();
|
|
8039
8490
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -8043,7 +8494,7 @@ app10.delete("/:slug", async (c) => {
|
|
|
8043
8494
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
8044
8495
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8045
8496
|
}
|
|
8046
|
-
const agentDir =
|
|
8497
|
+
const agentDir = resolve12(account.accountDir, "agents", slug);
|
|
8047
8498
|
if (!existsSync13(agentDir)) {
|
|
8048
8499
|
return c.json({ error: "Agent not found" }, 404);
|
|
8049
8500
|
}
|
|
@@ -8063,7 +8514,7 @@ app10.delete("/:slug", async (c) => {
|
|
|
8063
8514
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
8064
8515
|
}
|
|
8065
8516
|
});
|
|
8066
|
-
|
|
8517
|
+
app12.post("/:slug/project", async (c) => {
|
|
8067
8518
|
const slug = c.req.param("slug");
|
|
8068
8519
|
const account = resolveAccount();
|
|
8069
8520
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -8073,7 +8524,7 @@ app10.post("/:slug/project", async (c) => {
|
|
|
8073
8524
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
8074
8525
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8075
8526
|
}
|
|
8076
|
-
const agentDir =
|
|
8527
|
+
const agentDir = resolve12(account.accountDir, "agents", slug);
|
|
8077
8528
|
if (!existsSync13(agentDir)) {
|
|
8078
8529
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
8079
8530
|
}
|
|
@@ -8085,7 +8536,7 @@ app10.post("/:slug/project", async (c) => {
|
|
|
8085
8536
|
return c.json({ error: `Projection failed: ${msg}` }, 500);
|
|
8086
8537
|
}
|
|
8087
8538
|
});
|
|
8088
|
-
var agents_default =
|
|
8539
|
+
var agents_default = app12;
|
|
8089
8540
|
|
|
8090
8541
|
// server/routes/admin/sessions.ts
|
|
8091
8542
|
import crypto2 from "crypto";
|
|
@@ -8357,8 +8808,8 @@ function formatAge(updatedAtStr) {
|
|
|
8357
8808
|
return "unknown";
|
|
8358
8809
|
}
|
|
8359
8810
|
}
|
|
8360
|
-
var
|
|
8361
|
-
|
|
8811
|
+
var app13 = new Hono();
|
|
8812
|
+
app13.get("/", requireAdminSession, async (c) => {
|
|
8362
8813
|
const cacheKey = c.var.cacheKey;
|
|
8363
8814
|
const accountId = getAccountIdForSession(cacheKey);
|
|
8364
8815
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -8388,7 +8839,7 @@ app11.get("/", requireAdminSession, async (c) => {
|
|
|
8388
8839
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
8389
8840
|
}
|
|
8390
8841
|
});
|
|
8391
|
-
|
|
8842
|
+
app13.post("/new", requireAdminSession, async (c) => {
|
|
8392
8843
|
const oldCacheKey = c.var.cacheKey;
|
|
8393
8844
|
console.log(`[admin-chat] new-conversation outcome=ingress cacheKey=${oldCacheKey.slice(0, 8)}`);
|
|
8394
8845
|
const accountId = getAccountIdForSession(oldCacheKey);
|
|
@@ -8405,7 +8856,7 @@ app11.post("/new", requireAdminSession, async (c) => {
|
|
|
8405
8856
|
console.log(`[admin-chat] new-conversation outcome=ok oldKey=${oldCacheKey.slice(0, 8)} newKey=${newCacheKey.slice(0, 8)}`);
|
|
8406
8857
|
return c.json({ session_key: newSignedSessionToken, sessionId: null });
|
|
8407
8858
|
});
|
|
8408
|
-
|
|
8859
|
+
app13.post("/switch", requireAdminSession, async (c) => {
|
|
8409
8860
|
const cacheKey = c.var.cacheKey;
|
|
8410
8861
|
const accountId = getAccountIdForSession(cacheKey);
|
|
8411
8862
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -8433,7 +8884,7 @@ app11.post("/switch", requireAdminSession, async (c) => {
|
|
|
8433
8884
|
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetSessionId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
8434
8885
|
return c.json({ session_key: targetSignedSessionToken, sessionId: targetSessionId });
|
|
8435
8886
|
});
|
|
8436
|
-
|
|
8887
|
+
app13.delete("/:id", requireAdminSession, async (c) => {
|
|
8437
8888
|
const sessionId = c.req.param("id");
|
|
8438
8889
|
const cacheKey = c.var.cacheKey;
|
|
8439
8890
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -8479,7 +8930,7 @@ app11.delete("/:id", requireAdminSession, async (c) => {
|
|
|
8479
8930
|
500
|
|
8480
8931
|
);
|
|
8481
8932
|
});
|
|
8482
|
-
|
|
8933
|
+
app13.post("/:id/resume", async (c) => {
|
|
8483
8934
|
const sessionId = c.req.param("id");
|
|
8484
8935
|
const t0 = Date.now();
|
|
8485
8936
|
const signedSessionToken = c.req.query("session_key") ?? "";
|
|
@@ -8748,7 +9199,7 @@ app11.post("/:id/resume", async (c) => {
|
|
|
8748
9199
|
}
|
|
8749
9200
|
});
|
|
8750
9201
|
});
|
|
8751
|
-
|
|
9202
|
+
app13.put("/:id/label", requireAdminSession, async (c) => {
|
|
8752
9203
|
const sessionId = c.req.param("id");
|
|
8753
9204
|
const cacheKey = c.var.cacheKey;
|
|
8754
9205
|
let body;
|
|
@@ -8774,11 +9225,11 @@ app11.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
8774
9225
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
8775
9226
|
}
|
|
8776
9227
|
});
|
|
8777
|
-
var sessions_default =
|
|
9228
|
+
var sessions_default = app13;
|
|
8778
9229
|
|
|
8779
9230
|
// app/lib/claude-agent/spawn-context.ts
|
|
8780
|
-
import { existsSync as existsSync15, readFileSync as
|
|
8781
|
-
import { dirname as
|
|
9231
|
+
import { existsSync as existsSync15, readFileSync as readFileSync15, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
|
|
9232
|
+
import { dirname as dirname3, resolve as resolve13, join as join13 } from "path";
|
|
8782
9233
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
8783
9234
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
8784
9235
|
try {
|
|
@@ -8807,14 +9258,14 @@ function frontmatterField(manifest, field) {
|
|
|
8807
9258
|
function extractPluginToolDescriptions(pluginDir) {
|
|
8808
9259
|
const out = /* @__PURE__ */ new Map();
|
|
8809
9260
|
const candidates = [
|
|
8810
|
-
|
|
8811
|
-
|
|
9261
|
+
join13(pluginDir, "mcp/dist/index.js"),
|
|
9262
|
+
join13(pluginDir, "mcp/src/index.ts")
|
|
8812
9263
|
];
|
|
8813
9264
|
let raw = null;
|
|
8814
9265
|
for (const path2 of candidates) {
|
|
8815
9266
|
if (!existsSync15(path2)) continue;
|
|
8816
9267
|
try {
|
|
8817
|
-
raw =
|
|
9268
|
+
raw = readFileSync15(path2, "utf-8");
|
|
8818
9269
|
break;
|
|
8819
9270
|
} catch {
|
|
8820
9271
|
}
|
|
@@ -8863,26 +9314,26 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
8863
9314
|
}
|
|
8864
9315
|
function listPluginDirs() {
|
|
8865
9316
|
const out = /* @__PURE__ */ new Map();
|
|
8866
|
-
const platformPlugins =
|
|
9317
|
+
const platformPlugins = resolve13(PLATFORM_ROOT, "plugins");
|
|
8867
9318
|
if (existsSync15(platformPlugins)) {
|
|
8868
|
-
for (const name of
|
|
8869
|
-
const dir =
|
|
9319
|
+
for (const name of readdirSync9(platformPlugins)) {
|
|
9320
|
+
const dir = join13(platformPlugins, name);
|
|
8870
9321
|
try {
|
|
8871
|
-
if (
|
|
9322
|
+
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
8872
9323
|
} catch {
|
|
8873
9324
|
}
|
|
8874
9325
|
}
|
|
8875
9326
|
}
|
|
8876
|
-
const premiumRoot =
|
|
9327
|
+
const premiumRoot = resolve13(dirname3(PLATFORM_ROOT), "premium-plugins");
|
|
8877
9328
|
if (existsSync15(premiumRoot)) {
|
|
8878
|
-
for (const bundle of
|
|
8879
|
-
const bundlePlugins =
|
|
9329
|
+
for (const bundle of readdirSync9(premiumRoot)) {
|
|
9330
|
+
const bundlePlugins = join13(premiumRoot, bundle, "plugins");
|
|
8880
9331
|
if (!existsSync15(bundlePlugins)) continue;
|
|
8881
9332
|
try {
|
|
8882
|
-
for (const name of
|
|
8883
|
-
const dir =
|
|
9333
|
+
for (const name of readdirSync9(bundlePlugins)) {
|
|
9334
|
+
const dir = join13(bundlePlugins, name);
|
|
8884
9335
|
try {
|
|
8885
|
-
if (
|
|
9336
|
+
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
8886
9337
|
} catch {
|
|
8887
9338
|
}
|
|
8888
9339
|
}
|
|
@@ -8893,10 +9344,10 @@ function listPluginDirs() {
|
|
|
8893
9344
|
return out;
|
|
8894
9345
|
}
|
|
8895
9346
|
function readEnabledPlugins(accountId) {
|
|
8896
|
-
const accountFile =
|
|
9347
|
+
const accountFile = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
8897
9348
|
if (!existsSync15(accountFile)) return /* @__PURE__ */ new Set();
|
|
8898
9349
|
try {
|
|
8899
|
-
const parsed = JSON.parse(
|
|
9350
|
+
const parsed = JSON.parse(readFileSync15(accountFile, "utf-8"));
|
|
8900
9351
|
return new Set(
|
|
8901
9352
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
8902
9353
|
);
|
|
@@ -8908,7 +9359,7 @@ function readFrontmatter(path2) {
|
|
|
8908
9359
|
if (!existsSync15(path2)) return null;
|
|
8909
9360
|
let raw;
|
|
8910
9361
|
try {
|
|
8911
|
-
raw =
|
|
9362
|
+
raw = readFileSync15(path2, "utf-8");
|
|
8912
9363
|
} catch {
|
|
8913
9364
|
return null;
|
|
8914
9365
|
}
|
|
@@ -8923,7 +9374,7 @@ function computeActivePlugins(accountId) {
|
|
|
8923
9374
|
for (const name of Array.from(enabled).sort()) {
|
|
8924
9375
|
const dir = pluginDirs.get(name);
|
|
8925
9376
|
if (!dir) continue;
|
|
8926
|
-
const fm = readFrontmatter(
|
|
9377
|
+
const fm = readFrontmatter(join13(dir, "PLUGIN.md"));
|
|
8927
9378
|
if (!fm) continue;
|
|
8928
9379
|
const description = frontmatterField(`---
|
|
8929
9380
|
${fm}
|
|
@@ -8940,7 +9391,7 @@ ${fm}
|
|
|
8940
9391
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
8941
9392
|
);
|
|
8942
9393
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
8943
|
-
const hasSource = existsSync15(
|
|
9394
|
+
const hasSource = existsSync15(join13(dir, "mcp/dist/index.js")) || existsSync15(join13(dir, "mcp/src/index.ts"));
|
|
8944
9395
|
if (hasSource) {
|
|
8945
9396
|
console.warn(
|
|
8946
9397
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -8950,7 +9401,7 @@ ${fm}
|
|
|
8950
9401
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
8951
9402
|
const skills = [];
|
|
8952
9403
|
for (const relPath of skillPaths) {
|
|
8953
|
-
const skillPath =
|
|
9404
|
+
const skillPath = join13(dir, relPath);
|
|
8954
9405
|
const skillFm = readFrontmatter(skillPath);
|
|
8955
9406
|
if (!skillFm) continue;
|
|
8956
9407
|
const skillName = frontmatterField(`---
|
|
@@ -8966,11 +9417,11 @@ ${skillFm}
|
|
|
8966
9417
|
return out;
|
|
8967
9418
|
}
|
|
8968
9419
|
function computeSpecialistDomains(accountId) {
|
|
8969
|
-
const specialistsDir =
|
|
9420
|
+
const specialistsDir = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
8970
9421
|
if (!existsSync15(specialistsDir)) return [];
|
|
8971
9422
|
let entries;
|
|
8972
9423
|
try {
|
|
8973
|
-
entries =
|
|
9424
|
+
entries = readdirSync9(specialistsDir);
|
|
8974
9425
|
} catch {
|
|
8975
9426
|
return [];
|
|
8976
9427
|
}
|
|
@@ -8979,10 +9430,10 @@ function computeSpecialistDomains(accountId) {
|
|
|
8979
9430
|
const resolveDesc = (qualified) => {
|
|
8980
9431
|
if (!qualified.startsWith("mcp__")) return void 0;
|
|
8981
9432
|
const rest = qualified.slice(5);
|
|
8982
|
-
const
|
|
8983
|
-
if (
|
|
8984
|
-
const plugin = rest.slice(0,
|
|
8985
|
-
const tool = rest.slice(
|
|
9433
|
+
const sep8 = rest.indexOf("__");
|
|
9434
|
+
if (sep8 < 0) return void 0;
|
|
9435
|
+
const plugin = rest.slice(0, sep8);
|
|
9436
|
+
const tool = rest.slice(sep8 + 2);
|
|
8986
9437
|
let map = descByPlugin.get(plugin);
|
|
8987
9438
|
if (!map) {
|
|
8988
9439
|
const dir = pluginDirs.get(plugin);
|
|
@@ -8994,7 +9445,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
8994
9445
|
const out = [];
|
|
8995
9446
|
for (const file of entries.sort()) {
|
|
8996
9447
|
if (!file.endsWith(".md")) continue;
|
|
8997
|
-
const fm = readFrontmatter(
|
|
9448
|
+
const fm = readFrontmatter(join13(specialistsDir, file));
|
|
8998
9449
|
if (!fm) continue;
|
|
8999
9450
|
const wrapped = `---
|
|
9000
9451
|
${fm}
|
|
@@ -9012,11 +9463,11 @@ ${fm}
|
|
|
9012
9463
|
return out;
|
|
9013
9464
|
}
|
|
9014
9465
|
function computeDormantPlugins(accountId) {
|
|
9015
|
-
const accountFile =
|
|
9466
|
+
const accountFile = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
9016
9467
|
if (!existsSync15(accountFile)) return [];
|
|
9017
9468
|
let enabled;
|
|
9018
9469
|
try {
|
|
9019
|
-
const raw =
|
|
9470
|
+
const raw = readFileSync15(accountFile, "utf-8");
|
|
9020
9471
|
const parsed = JSON.parse(raw);
|
|
9021
9472
|
enabled = new Set(
|
|
9022
9473
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -9027,22 +9478,22 @@ function computeDormantPlugins(accountId) {
|
|
|
9027
9478
|
);
|
|
9028
9479
|
return [];
|
|
9029
9480
|
}
|
|
9030
|
-
const pluginsDir =
|
|
9481
|
+
const pluginsDir = resolve13(PLATFORM_ROOT, "plugins");
|
|
9031
9482
|
if (!existsSync15(pluginsDir)) return [];
|
|
9032
9483
|
let entries;
|
|
9033
9484
|
try {
|
|
9034
|
-
entries =
|
|
9485
|
+
entries = readdirSync9(pluginsDir);
|
|
9035
9486
|
} catch {
|
|
9036
9487
|
return [];
|
|
9037
9488
|
}
|
|
9038
9489
|
const out = [];
|
|
9039
9490
|
for (const name of entries) {
|
|
9040
9491
|
if (enabled.has(name)) continue;
|
|
9041
|
-
const manifestPath =
|
|
9492
|
+
const manifestPath = resolve13(pluginsDir, name, "PLUGIN.md");
|
|
9042
9493
|
if (!existsSync15(manifestPath)) continue;
|
|
9043
9494
|
let manifest;
|
|
9044
9495
|
try {
|
|
9045
|
-
manifest =
|
|
9496
|
+
manifest = readFileSync15(manifestPath, "utf-8");
|
|
9046
9497
|
} catch {
|
|
9047
9498
|
continue;
|
|
9048
9499
|
}
|
|
@@ -9056,13 +9507,13 @@ function computeDormantPlugins(accountId) {
|
|
|
9056
9507
|
}
|
|
9057
9508
|
|
|
9058
9509
|
// server/routes/admin/claude-sessions.ts
|
|
9059
|
-
import { existsSync as existsSync16, readFileSync as
|
|
9060
|
-
import { resolve as
|
|
9510
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
|
|
9511
|
+
import { resolve as resolve14 } from "path";
|
|
9061
9512
|
function readTunnelState(brandConfigDir) {
|
|
9062
9513
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
9063
9514
|
if (!existsSync16(statePath)) return null;
|
|
9064
9515
|
try {
|
|
9065
|
-
const parsed = JSON.parse(
|
|
9516
|
+
const parsed = JSON.parse(readFileSync16(statePath, "utf-8"));
|
|
9066
9517
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
9067
9518
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
9068
9519
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -9073,10 +9524,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
9073
9524
|
}
|
|
9074
9525
|
}
|
|
9075
9526
|
function resolveTunnelUrl() {
|
|
9076
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
9527
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
9077
9528
|
let brand;
|
|
9078
9529
|
try {
|
|
9079
|
-
brand = JSON.parse(
|
|
9530
|
+
brand = JSON.parse(readFileSync16(resolve14(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
9080
9531
|
} catch {
|
|
9081
9532
|
return null;
|
|
9082
9533
|
}
|
|
@@ -9103,7 +9554,7 @@ function managerBase3() {
|
|
|
9103
9554
|
const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "claude-session-manager:wrapper" });
|
|
9104
9555
|
return `http://127.0.0.1:${port2}`;
|
|
9105
9556
|
}
|
|
9106
|
-
var
|
|
9557
|
+
var app14 = new Hono();
|
|
9107
9558
|
async function performSpawnWithInitialMessage(args) {
|
|
9108
9559
|
const ownerStart = Date.now();
|
|
9109
9560
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
@@ -9180,8 +9631,8 @@ function mintTranscriptEdge(sessionId, claudeSessionId, accountId) {
|
|
|
9180
9631
|
if (!sessionId || !claudeSessionId) return;
|
|
9181
9632
|
void linkConversationTranscript(sessionId, claudeSessionId, accountId);
|
|
9182
9633
|
}
|
|
9183
|
-
|
|
9184
|
-
|
|
9634
|
+
app14.use("*", requireAdminSession);
|
|
9635
|
+
app14.post("/", async (c) => {
|
|
9185
9636
|
const routeStart = Date.now();
|
|
9186
9637
|
const cacheKey = c.get("cacheKey") ?? "";
|
|
9187
9638
|
let body = {};
|
|
@@ -9224,18 +9675,18 @@ app12.post("/", async (c) => {
|
|
|
9224
9675
|
console.log(`${TAG21} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
9225
9676
|
return response;
|
|
9226
9677
|
});
|
|
9227
|
-
var claude_sessions_default =
|
|
9678
|
+
var claude_sessions_default = app14;
|
|
9228
9679
|
|
|
9229
9680
|
// server/routes/admin/log-ingest.ts
|
|
9230
9681
|
var TAG22 = "[log-ingest]";
|
|
9231
9682
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
9232
9683
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
9233
9684
|
var MAX_LINE_BYTES = 4096;
|
|
9234
|
-
var
|
|
9685
|
+
var app15 = new Hono();
|
|
9235
9686
|
function isLoopbackAddr(addr) {
|
|
9236
9687
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
9237
9688
|
}
|
|
9238
|
-
|
|
9689
|
+
app15.post("/", async (c) => {
|
|
9239
9690
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
9240
9691
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
9241
9692
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -9278,7 +9729,7 @@ app13.post("/", async (c) => {
|
|
|
9278
9729
|
else console.log(formatted);
|
|
9279
9730
|
return c.json({ ok: true }, 200);
|
|
9280
9731
|
});
|
|
9281
|
-
var log_ingest_default =
|
|
9732
|
+
var log_ingest_default = app15;
|
|
9282
9733
|
|
|
9283
9734
|
// server/routes/admin/events.ts
|
|
9284
9735
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -9287,8 +9738,8 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
9287
9738
|
"device-url:vnc-surface-shown",
|
|
9288
9739
|
"device-url:malformed"
|
|
9289
9740
|
]);
|
|
9290
|
-
var
|
|
9291
|
-
|
|
9741
|
+
var app16 = new Hono();
|
|
9742
|
+
app16.post("/", async (c) => {
|
|
9292
9743
|
const TAG30 = "[admin:events]";
|
|
9293
9744
|
let body;
|
|
9294
9745
|
try {
|
|
@@ -9319,21 +9770,21 @@ app14.post("/", async (c) => {
|
|
|
9319
9770
|
console.error(`[${event}] ${formatted}`);
|
|
9320
9771
|
return c.json({ ok: true });
|
|
9321
9772
|
});
|
|
9322
|
-
var events_default =
|
|
9773
|
+
var events_default = app16;
|
|
9323
9774
|
|
|
9324
9775
|
// server/routes/admin/files.ts
|
|
9325
9776
|
import { createReadStream as createReadStream2 } from "fs";
|
|
9326
9777
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
9327
9778
|
import { realpathSync as realpathSync4 } from "fs";
|
|
9328
|
-
import { basename as
|
|
9779
|
+
import { basename as basename5, dirname as dirname4, join as join15, resolve as resolve17, sep as sep5 } from "path";
|
|
9329
9780
|
import { Readable as Readable2 } from "stream";
|
|
9330
9781
|
|
|
9331
9782
|
// app/lib/data-path.ts
|
|
9332
9783
|
import { realpathSync as realpathSync3 } from "fs";
|
|
9333
|
-
import { resolve as
|
|
9334
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
9335
|
-
var DATA_ROOT =
|
|
9336
|
-
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ?
|
|
9784
|
+
import { resolve as resolve15, normalize, sep as sep3, relative } from "path";
|
|
9785
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "../platform");
|
|
9786
|
+
var DATA_ROOT = resolve15(PLATFORM_ROOT5, "..", "data");
|
|
9787
|
+
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve15(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
9337
9788
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
9338
9789
|
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9339
9790
|
function crossesForeignAccountPartition(relPath, accountId) {
|
|
@@ -9346,7 +9797,7 @@ function crossesForeignAccountPartition(relPath, accountId) {
|
|
|
9346
9797
|
}
|
|
9347
9798
|
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
9348
9799
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
9349
|
-
const absolute =
|
|
9800
|
+
const absolute = resolve15(rootAbs, cleaned);
|
|
9350
9801
|
let rootReal;
|
|
9351
9802
|
try {
|
|
9352
9803
|
rootReal = realpathSync3(rootAbs);
|
|
@@ -9363,7 +9814,7 @@ function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
|
9363
9814
|
} catch (err) {
|
|
9364
9815
|
const code = err.code;
|
|
9365
9816
|
if (code === "ENOENT") {
|
|
9366
|
-
if (absolute !== rootReal && !absolute.startsWith(rootReal +
|
|
9817
|
+
if (absolute !== rootReal && !absolute.startsWith(rootReal + sep3)) {
|
|
9367
9818
|
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
|
|
9368
9819
|
}
|
|
9369
9820
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -9374,7 +9825,7 @@ function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
|
9374
9825
|
error: err instanceof Error ? err.message : String(err)
|
|
9375
9826
|
};
|
|
9376
9827
|
}
|
|
9377
|
-
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal +
|
|
9828
|
+
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep3)) {
|
|
9378
9829
|
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
|
|
9379
9830
|
}
|
|
9380
9831
|
const relPath = relative(rootReal, resolvedReal) || ".";
|
|
@@ -9705,7 +10156,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
9705
10156
|
|
|
9706
10157
|
// app/lib/file-index.ts
|
|
9707
10158
|
import * as fsp from "fs/promises";
|
|
9708
|
-
import { resolve as
|
|
10159
|
+
import { resolve as resolve16, relative as relative2, join as join14, basename as basename4, extname as extname2, sep as sep4 } from "path";
|
|
9709
10160
|
import { tmpdir as tmpdir2 } from "os";
|
|
9710
10161
|
import { execFile as execFile2 } from "child_process";
|
|
9711
10162
|
import { promisify as promisify2 } from "util";
|
|
@@ -9776,7 +10227,7 @@ async function extractPdf(absolute) {
|
|
|
9776
10227
|
return stdout.trim();
|
|
9777
10228
|
}
|
|
9778
10229
|
async function ocrPdf(absolute) {
|
|
9779
|
-
const outPdf =
|
|
10230
|
+
const outPdf = join14(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
9780
10231
|
try {
|
|
9781
10232
|
await execFileAsync2(
|
|
9782
10233
|
"ocrmypdf",
|
|
@@ -9832,13 +10283,13 @@ async function extractFileContent(absolute) {
|
|
|
9832
10283
|
}
|
|
9833
10284
|
}
|
|
9834
10285
|
async function readDisplayName(absolute) {
|
|
9835
|
-
const dir = absolute.slice(0, absolute.length -
|
|
9836
|
-
const base =
|
|
10286
|
+
const dir = absolute.slice(0, absolute.length - basename4(absolute).length);
|
|
10287
|
+
const base = basename4(absolute);
|
|
9837
10288
|
const dot = base.lastIndexOf(".");
|
|
9838
10289
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
9839
10290
|
if (base === `${stem}.meta.json`) return null;
|
|
9840
10291
|
try {
|
|
9841
|
-
const raw = await fsp.readFile(
|
|
10292
|
+
const raw = await fsp.readFile(join14(dir, `${stem}.meta.json`), "utf-8");
|
|
9842
10293
|
const meta = JSON.parse(raw);
|
|
9843
10294
|
const dn = meta.displayName ?? meta.filename;
|
|
9844
10295
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -9858,7 +10309,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
9858
10309
|
let clean = true;
|
|
9859
10310
|
for (const entry of entries) {
|
|
9860
10311
|
if (entry.isSymbolicLink()) continue;
|
|
9861
|
-
const abs =
|
|
10312
|
+
const abs = join14(root, entry.name);
|
|
9862
10313
|
if (entry.isDirectory()) {
|
|
9863
10314
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
9864
10315
|
if (!sub.clean) clean = false;
|
|
@@ -9867,7 +10318,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
9867
10318
|
const st = await fsp.stat(abs);
|
|
9868
10319
|
out.push({
|
|
9869
10320
|
absolute: abs,
|
|
9870
|
-
relativePath: relative2(dataRoot, abs).split(
|
|
10321
|
+
relativePath: relative2(dataRoot, abs).split(sep4).join("/"),
|
|
9871
10322
|
sizeBytes: st.size,
|
|
9872
10323
|
modifiedAt: st.mtime.toISOString()
|
|
9873
10324
|
});
|
|
@@ -9970,7 +10421,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
9970
10421
|
return { kds, sections, chunks };
|
|
9971
10422
|
}
|
|
9972
10423
|
async function buildArtifact(accountId, wf, embed2) {
|
|
9973
|
-
const name =
|
|
10424
|
+
const name = basename4(wf.absolute);
|
|
9974
10425
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
9975
10426
|
const displayName = await readDisplayName(wf.absolute);
|
|
9976
10427
|
const embedInput = `${name}
|
|
@@ -10013,8 +10464,8 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
10013
10464
|
return withSession(opts, async (session) => {
|
|
10014
10465
|
const walked = [];
|
|
10015
10466
|
const subtreeRoots = [
|
|
10016
|
-
|
|
10017
|
-
|
|
10467
|
+
resolve16(dataRoot, "uploads", accountId),
|
|
10468
|
+
resolve16(dataRoot, "accounts", accountId)
|
|
10018
10469
|
];
|
|
10019
10470
|
let clean = true;
|
|
10020
10471
|
for (const root of subtreeRoots) {
|
|
@@ -10095,7 +10546,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
10095
10546
|
async function indexFile(accountId, relativePath, opts) {
|
|
10096
10547
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
10097
10548
|
const embed2 = opts?.embed ?? embed;
|
|
10098
|
-
const absolute =
|
|
10549
|
+
const absolute = resolve16(dataRoot, relativePath);
|
|
10099
10550
|
await withSession(opts, async (session) => {
|
|
10100
10551
|
const st = await fsp.stat(absolute);
|
|
10101
10552
|
const wf = {
|
|
@@ -10129,7 +10580,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
10129
10580
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10130
10581
|
async function readMeta(absDir, baseName) {
|
|
10131
10582
|
try {
|
|
10132
|
-
const raw = await readFile4(
|
|
10583
|
+
const raw = await readFile4(join15(absDir, `${baseName}.meta.json`), "utf8");
|
|
10133
10584
|
const parsed = JSON.parse(raw);
|
|
10134
10585
|
if (typeof parsed?.filename === "string") {
|
|
10135
10586
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -10140,7 +10591,7 @@ async function readMeta(absDir, baseName) {
|
|
|
10140
10591
|
}
|
|
10141
10592
|
async function readAccountNames() {
|
|
10142
10593
|
const map = /* @__PURE__ */ new Map();
|
|
10143
|
-
const accountsDir =
|
|
10594
|
+
const accountsDir = resolve17(DATA_ROOT, "accounts");
|
|
10144
10595
|
let names;
|
|
10145
10596
|
try {
|
|
10146
10597
|
names = await readdir3(accountsDir);
|
|
@@ -10149,7 +10600,7 @@ async function readAccountNames() {
|
|
|
10149
10600
|
}
|
|
10150
10601
|
for (const name of names) {
|
|
10151
10602
|
if (!UUID_RE3.test(name)) continue;
|
|
10152
|
-
const configPath2 =
|
|
10603
|
+
const configPath2 = resolve17(accountsDir, name, "account.json");
|
|
10153
10604
|
try {
|
|
10154
10605
|
const raw = await readFile4(configPath2, "utf8");
|
|
10155
10606
|
const parsed = JSON.parse(raw);
|
|
@@ -10167,7 +10618,7 @@ async function readAccountNames() {
|
|
|
10167
10618
|
}
|
|
10168
10619
|
async function enrich(absolute, entry, accountNames) {
|
|
10169
10620
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
10170
|
-
const meta = await readMeta(
|
|
10621
|
+
const meta = await readMeta(join15(absolute, entry.name), entry.name);
|
|
10171
10622
|
if (meta?.filename) {
|
|
10172
10623
|
entry.displayName = meta.filename;
|
|
10173
10624
|
entry.mimeType = meta.mimeType;
|
|
@@ -10227,8 +10678,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
10227
10678
|
await session.close();
|
|
10228
10679
|
}
|
|
10229
10680
|
}
|
|
10230
|
-
var
|
|
10231
|
-
|
|
10681
|
+
var app17 = new Hono();
|
|
10682
|
+
app17.get("/", requireAdminSession, async (c) => {
|
|
10232
10683
|
const cacheKey = c.var.cacheKey;
|
|
10233
10684
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10234
10685
|
if (!accountId) {
|
|
@@ -10265,7 +10716,7 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
10265
10716
|
continue;
|
|
10266
10717
|
}
|
|
10267
10718
|
try {
|
|
10268
|
-
const entryPath =
|
|
10719
|
+
const entryPath = join15(absolute, name);
|
|
10269
10720
|
const s = await stat4(entryPath);
|
|
10270
10721
|
entries.push({
|
|
10271
10722
|
name,
|
|
@@ -10294,7 +10745,7 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
10294
10745
|
return c.json({ error: message }, 500);
|
|
10295
10746
|
}
|
|
10296
10747
|
});
|
|
10297
|
-
|
|
10748
|
+
app17.get("/download", requireAdminSession, async (c) => {
|
|
10298
10749
|
const cacheKey = c.var.cacheKey;
|
|
10299
10750
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10300
10751
|
if (!accountId) {
|
|
@@ -10331,7 +10782,7 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
10331
10782
|
if (!info.isFile()) {
|
|
10332
10783
|
return c.json({ error: "Path is not a file" }, 400);
|
|
10333
10784
|
}
|
|
10334
|
-
const filename =
|
|
10785
|
+
const filename = basename5(absolute);
|
|
10335
10786
|
const mimeType = detectMimeType(absolute);
|
|
10336
10787
|
const nodeStream = createReadStream2(absolute);
|
|
10337
10788
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -10358,7 +10809,7 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
10358
10809
|
return c.json({ error: message }, 500);
|
|
10359
10810
|
}
|
|
10360
10811
|
});
|
|
10361
|
-
|
|
10812
|
+
app17.post("/upload", requireAdminSession, async (c) => {
|
|
10362
10813
|
const cacheKey = c.var.cacheKey;
|
|
10363
10814
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10364
10815
|
if (!accountId) {
|
|
@@ -10388,15 +10839,15 @@ app15.post("/upload", requireAdminSession, async (c) => {
|
|
|
10388
10839
|
error: `Unsupported file type: "${file.type}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
10389
10840
|
}, 422);
|
|
10390
10841
|
}
|
|
10391
|
-
const safeName =
|
|
10842
|
+
const safeName = basename5(file.name).replace(/[\0/\\]/g, "_");
|
|
10392
10843
|
const finalName = `${Date.now()}-${safeName}`;
|
|
10393
|
-
const destDir =
|
|
10394
|
-
const destPath =
|
|
10844
|
+
const destDir = resolve17(DATA_ROOT, "uploads", accountId);
|
|
10845
|
+
const destPath = resolve17(destDir, finalName);
|
|
10395
10846
|
try {
|
|
10396
10847
|
await mkdir3(destDir, { recursive: true });
|
|
10397
10848
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
10398
10849
|
const destDirReal = realpathSync4(destDir);
|
|
10399
|
-
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal +
|
|
10850
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep5)) {
|
|
10400
10851
|
console.error(`[data] path-traversal-blocked requested="uploads/${accountId}" resolved="${destDirReal}"`);
|
|
10401
10852
|
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
10402
10853
|
}
|
|
@@ -10419,7 +10870,7 @@ app15.post("/upload", requireAdminSession, async (c) => {
|
|
|
10419
10870
|
mimeType: file.type
|
|
10420
10871
|
});
|
|
10421
10872
|
});
|
|
10422
|
-
|
|
10873
|
+
app17.delete("/", requireAdminSession, async (c) => {
|
|
10423
10874
|
const cacheKey = c.var.cacheKey;
|
|
10424
10875
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10425
10876
|
if (!accountId) {
|
|
@@ -10440,7 +10891,7 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
10440
10891
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
10441
10892
|
return c.json({ error: "Not found" }, 404);
|
|
10442
10893
|
}
|
|
10443
|
-
const base =
|
|
10894
|
+
const base = basename5(absolute);
|
|
10444
10895
|
const segments = relPath.split("/").filter(Boolean);
|
|
10445
10896
|
if (base === "account.json" || segments.includes(".git")) {
|
|
10446
10897
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected"`);
|
|
@@ -10456,7 +10907,7 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
10456
10907
|
}
|
|
10457
10908
|
const dot = base.lastIndexOf(".");
|
|
10458
10909
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10459
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
10910
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join15(dirname4(absolute), `${stem}.meta.json`) : null;
|
|
10460
10911
|
await unlink2(absolute);
|
|
10461
10912
|
if (sidecarPath) {
|
|
10462
10913
|
try {
|
|
@@ -10495,7 +10946,7 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
10495
10946
|
return c.json({ error: message }, 500);
|
|
10496
10947
|
}
|
|
10497
10948
|
});
|
|
10498
|
-
var files_default =
|
|
10949
|
+
var files_default = app17;
|
|
10499
10950
|
|
|
10500
10951
|
// ../lib/graph-search/src/index.ts
|
|
10501
10952
|
var import_dist = __toESM(require_dist());
|
|
@@ -11260,8 +11711,8 @@ var DEFAULT_LIMIT = 20;
|
|
|
11260
11711
|
var MAX_LIMIT = 2e3;
|
|
11261
11712
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
11262
11713
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
11263
|
-
var
|
|
11264
|
-
|
|
11714
|
+
var app18 = new Hono();
|
|
11715
|
+
app18.get("/", requireAdminSession, async (c) => {
|
|
11265
11716
|
const cacheKey = c.var.cacheKey;
|
|
11266
11717
|
const q = (c.req.query("q") ?? "").trim();
|
|
11267
11718
|
const rawLimit = c.req.query("limit");
|
|
@@ -11397,7 +11848,7 @@ app16.get("/", requireAdminSession, async (c) => {
|
|
|
11397
11848
|
await session.close();
|
|
11398
11849
|
}
|
|
11399
11850
|
});
|
|
11400
|
-
var graph_search_default =
|
|
11851
|
+
var graph_search_default = app18;
|
|
11401
11852
|
|
|
11402
11853
|
// server/routes/admin/graph-subgraph.ts
|
|
11403
11854
|
import neo4j from "neo4j-driver";
|
|
@@ -11475,8 +11926,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
11475
11926
|
"otpCode",
|
|
11476
11927
|
"cacheKey"
|
|
11477
11928
|
]);
|
|
11478
|
-
var
|
|
11479
|
-
|
|
11929
|
+
var app19 = new Hono();
|
|
11930
|
+
app19.get("/", requireAdminSession, async (c) => {
|
|
11480
11931
|
const cacheKey = c.var.cacheKey;
|
|
11481
11932
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11482
11933
|
if (!accountId) {
|
|
@@ -12059,12 +12510,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
12059
12510
|
}
|
|
12060
12511
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
12061
12512
|
}
|
|
12062
|
-
var graph_subgraph_default =
|
|
12513
|
+
var graph_subgraph_default = app19;
|
|
12063
12514
|
|
|
12064
12515
|
// server/routes/admin/graph-delete.ts
|
|
12065
12516
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
|
|
12066
|
-
var
|
|
12067
|
-
|
|
12517
|
+
var app20 = new Hono();
|
|
12518
|
+
app20.post("/", requireAdminSession, async (c) => {
|
|
12068
12519
|
const cacheKey = c.var.cacheKey;
|
|
12069
12520
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12070
12521
|
if (!accountId) {
|
|
@@ -12227,11 +12678,11 @@ app18.post("/", requireAdminSession, async (c) => {
|
|
|
12227
12678
|
}
|
|
12228
12679
|
}
|
|
12229
12680
|
});
|
|
12230
|
-
var graph_delete_default =
|
|
12681
|
+
var graph_delete_default = app20;
|
|
12231
12682
|
|
|
12232
12683
|
// server/routes/admin/graph-restore.ts
|
|
12233
|
-
var
|
|
12234
|
-
|
|
12684
|
+
var app21 = new Hono();
|
|
12685
|
+
app21.post("/", requireAdminSession, async (c) => {
|
|
12235
12686
|
const cacheKey = c.var.cacheKey;
|
|
12236
12687
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12237
12688
|
if (!accountId) {
|
|
@@ -12295,11 +12746,11 @@ app19.post("/", requireAdminSession, async (c) => {
|
|
|
12295
12746
|
}
|
|
12296
12747
|
}
|
|
12297
12748
|
});
|
|
12298
|
-
var graph_restore_default =
|
|
12749
|
+
var graph_restore_default = app21;
|
|
12299
12750
|
|
|
12300
12751
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
12301
|
-
var
|
|
12302
|
-
|
|
12752
|
+
var app22 = new Hono();
|
|
12753
|
+
app22.get("/", requireAdminSession, async (c) => {
|
|
12303
12754
|
const cacheKey = c.var.cacheKey;
|
|
12304
12755
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12305
12756
|
if (!accountId) {
|
|
@@ -12365,11 +12816,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
12365
12816
|
sum(halfEdges) AS relDegree
|
|
12366
12817
|
RETURN label, nodeCount, relDegree
|
|
12367
12818
|
`;
|
|
12368
|
-
var graph_labels_in_graph_default =
|
|
12819
|
+
var graph_labels_in_graph_default = app22;
|
|
12369
12820
|
|
|
12370
12821
|
// server/routes/admin/graph-default-view.ts
|
|
12371
|
-
var
|
|
12372
|
-
|
|
12822
|
+
var app23 = new Hono();
|
|
12823
|
+
app23.get("/", requireAdminSession, async (c) => {
|
|
12373
12824
|
const cacheKey = c.var.cacheKey;
|
|
12374
12825
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12375
12826
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12407,7 +12858,7 @@ app21.get("/", requireAdminSession, async (c) => {
|
|
|
12407
12858
|
}
|
|
12408
12859
|
}
|
|
12409
12860
|
});
|
|
12410
|
-
|
|
12861
|
+
app23.put("/", requireAdminSession, async (c) => {
|
|
12411
12862
|
const cacheKey = c.var.cacheKey;
|
|
12412
12863
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12413
12864
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12496,20 +12947,20 @@ var WRITE_CYPHER = `
|
|
|
12496
12947
|
p.updatedAt = $updatedAt
|
|
12497
12948
|
RETURN p.labels AS labels
|
|
12498
12949
|
`;
|
|
12499
|
-
var graph_default_view_default =
|
|
12950
|
+
var graph_default_view_default = app23;
|
|
12500
12951
|
|
|
12501
12952
|
// server/routes/admin/sidebar-artefacts.ts
|
|
12502
12953
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
12503
|
-
import { resolve as
|
|
12954
|
+
import { resolve as resolve18, relative as relative3, isAbsolute, sep as sep6, basename as basename6 } from "path";
|
|
12504
12955
|
import { existsSync as existsSync17 } from "fs";
|
|
12505
12956
|
var LIMIT = 50;
|
|
12506
12957
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
12507
12958
|
function toDataRootRelPath(absPath) {
|
|
12508
|
-
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT +
|
|
12959
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep6)) return null;
|
|
12509
12960
|
return relative3(DATA_ROOT, absPath);
|
|
12510
12961
|
}
|
|
12511
|
-
var
|
|
12512
|
-
|
|
12962
|
+
var app24 = new Hono();
|
|
12963
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
12513
12964
|
const cacheKey = c.var.cacheKey;
|
|
12514
12965
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12515
12966
|
if (!accountId) {
|
|
@@ -12520,7 +12971,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
12520
12971
|
if (accountFiles === null) {
|
|
12521
12972
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
12522
12973
|
}
|
|
12523
|
-
const accountDir =
|
|
12974
|
+
const accountDir = resolve18(ACCOUNTS_DIR, accountId);
|
|
12524
12975
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
12525
12976
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
12526
12977
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -12552,7 +13003,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
12552
13003
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
12553
13004
|
return {
|
|
12554
13005
|
id: `account-file:${relativePath}`,
|
|
12555
|
-
name: displayName ??
|
|
13006
|
+
name: displayName ?? basename6(relativePath),
|
|
12556
13007
|
kind: "account-file",
|
|
12557
13008
|
updatedAt: modifiedAt,
|
|
12558
13009
|
mimeType,
|
|
@@ -12564,371 +13015,127 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
12564
13015
|
const message = err instanceof Error ? err.message : String(err);
|
|
12565
13016
|
console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
|
|
12566
13017
|
return null;
|
|
12567
|
-
} finally {
|
|
12568
|
-
await session.close();
|
|
12569
|
-
}
|
|
12570
|
-
}
|
|
12571
|
-
async function fetchAgentTemplateRows(accountDir) {
|
|
12572
|
-
const rows = [];
|
|
12573
|
-
for (const filename of ADMIN_AGENT_FILES) {
|
|
12574
|
-
const overridePath = resolve16(accountDir, "agents", "admin", filename);
|
|
12575
|
-
const bundledPath = resolve16(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
12576
|
-
const labelStem = filename.replace(/\.md$/, "");
|
|
12577
|
-
const row = await readAgentTemplateRow({
|
|
12578
|
-
id: `agent-template:admin:${filename}`,
|
|
12579
|
-
displayName: `Admin \xB7 ${labelStem}`,
|
|
12580
|
-
logName: `admin/${filename}`,
|
|
12581
|
-
overridePath,
|
|
12582
|
-
overrideRoot: accountDir,
|
|
12583
|
-
bundledPath,
|
|
12584
|
-
bundledRoot: PLATFORM_ROOT
|
|
12585
|
-
});
|
|
12586
|
-
if (row) rows.push(row);
|
|
12587
|
-
}
|
|
12588
|
-
const overrideDir = resolve16(accountDir, "specialists", "agents");
|
|
12589
|
-
const bundledDir = resolve16(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
12590
|
-
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
12591
|
-
for (const filename of specialistNames) {
|
|
12592
|
-
const overridePath = resolve16(overrideDir, filename);
|
|
12593
|
-
const bundledPath = resolve16(bundledDir, filename);
|
|
12594
|
-
const row = await readAgentTemplateRow({
|
|
12595
|
-
id: `agent-template:specialist:${filename}`,
|
|
12596
|
-
displayName: filename.replace(/\.md$/, ""),
|
|
12597
|
-
logName: `specialist/${filename}`,
|
|
12598
|
-
overridePath,
|
|
12599
|
-
overrideRoot: accountDir,
|
|
12600
|
-
bundledPath,
|
|
12601
|
-
bundledRoot: PLATFORM_ROOT
|
|
12602
|
-
});
|
|
12603
|
-
if (row) rows.push(row);
|
|
12604
|
-
}
|
|
12605
|
-
return rows;
|
|
12606
|
-
}
|
|
12607
|
-
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
12608
|
-
const names = /* @__PURE__ */ new Set();
|
|
12609
|
-
for (const dir of [overrideDir, bundledDir]) {
|
|
12610
|
-
if (!existsSync17(dir)) continue;
|
|
12611
|
-
try {
|
|
12612
|
-
const entries = await readdir4(dir);
|
|
12613
|
-
for (const entry of entries) {
|
|
12614
|
-
if (entry.endsWith(".md")) names.add(entry);
|
|
12615
|
-
}
|
|
12616
|
-
} catch (err) {
|
|
12617
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
12618
|
-
console.error(`[admin/sidebar-artefacts] specialists-read-failed dir=${dir} error="${message}"`);
|
|
12619
|
-
}
|
|
12620
|
-
}
|
|
12621
|
-
return [...names].sort();
|
|
12622
|
-
}
|
|
12623
|
-
async function readAgentTemplateRow(inp) {
|
|
12624
|
-
let chosenPath = null;
|
|
12625
|
-
if (existsSync17(inp.overridePath)) {
|
|
12626
|
-
try {
|
|
12627
|
-
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
12628
|
-
chosenPath = inp.overridePath;
|
|
12629
|
-
} catch (err) {
|
|
12630
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
12631
|
-
console.error(
|
|
12632
|
-
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
|
|
12633
|
-
);
|
|
12634
|
-
return null;
|
|
12635
|
-
}
|
|
12636
|
-
} else if (existsSync17(inp.bundledPath)) {
|
|
12637
|
-
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
12638
|
-
console.error(
|
|
12639
|
-
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
12640
|
-
);
|
|
12641
|
-
return null;
|
|
12642
|
-
}
|
|
12643
|
-
chosenPath = inp.bundledPath;
|
|
12644
|
-
}
|
|
12645
|
-
if (!chosenPath) return null;
|
|
12646
|
-
try {
|
|
12647
|
-
const st = await stat5(chosenPath);
|
|
12648
|
-
const dlPath = toDataRootRelPath(chosenPath);
|
|
12649
|
-
return {
|
|
12650
|
-
id: inp.id,
|
|
12651
|
-
name: inp.displayName,
|
|
12652
|
-
kind: "agent-template",
|
|
12653
|
-
updatedAt: st.mtime.toISOString(),
|
|
12654
|
-
mimeType: "text/markdown",
|
|
12655
|
-
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
12656
|
-
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
12657
|
-
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
12658
|
-
// Agent templates only ever resolve under DATA_ROOT, so the download
|
|
12659
|
-
// root is `data` whenever the path is non-null.
|
|
12660
|
-
downloadPath: dlPath,
|
|
12661
|
-
downloadRoot: dlPath ? "data" : null
|
|
12662
|
-
};
|
|
12663
|
-
} catch (err) {
|
|
12664
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
12665
|
-
console.error(
|
|
12666
|
-
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
|
|
12667
|
-
);
|
|
12668
|
-
return null;
|
|
12669
|
-
}
|
|
12670
|
-
}
|
|
12671
|
-
function isWithin(target, root) {
|
|
12672
|
-
const rel = relative3(root, target);
|
|
12673
|
-
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
12674
|
-
}
|
|
12675
|
-
var sidebar_artefacts_default = app22;
|
|
12676
|
-
|
|
12677
|
-
// server/routes/admin/sidebar-sessions.ts
|
|
12678
|
-
import { readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync7 } from "fs";
|
|
12679
|
-
import { join as join14, resolve as resolve17 } from "path";
|
|
12680
|
-
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
12681
|
-
var PID_FILE_RE = /^([0-9]+)\.json$/;
|
|
12682
|
-
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
12683
|
-
var PUBLIC_ROLE = "public";
|
|
12684
|
-
var WEBCHAT_CHANNEL = "webchat";
|
|
12685
|
-
var app23 = new Hono();
|
|
12686
|
-
function claudeConfigDir() {
|
|
12687
|
-
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
12688
|
-
}
|
|
12689
|
-
function enumerateJsonls(projectsRoot) {
|
|
12690
|
-
const out = [];
|
|
12691
|
-
let slugs;
|
|
12692
|
-
try {
|
|
12693
|
-
slugs = readdirSync9(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
12694
|
-
} catch (err) {
|
|
12695
|
-
if (err.code === "ENOENT") return out;
|
|
12696
|
-
throw err;
|
|
12697
|
-
}
|
|
12698
|
-
for (const slug of slugs) {
|
|
12699
|
-
const slugDir = join14(projectsRoot, slug);
|
|
12700
|
-
let entries;
|
|
12701
|
-
try {
|
|
12702
|
-
entries = readdirSync9(slugDir, { withFileTypes: true });
|
|
12703
|
-
} catch (err) {
|
|
12704
|
-
const code = err.code ?? "unknown";
|
|
12705
|
-
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
12706
|
-
continue;
|
|
12707
|
-
}
|
|
12708
|
-
for (const entry of entries) {
|
|
12709
|
-
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
12710
|
-
out.push({ path: join14(slugDir, entry.name), isSubagent: false });
|
|
12711
|
-
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
12712
|
-
const subDir = join14(slugDir, entry.name);
|
|
12713
|
-
let subEntries;
|
|
12714
|
-
try {
|
|
12715
|
-
subEntries = readdirSync9(subDir, { withFileTypes: true });
|
|
12716
|
-
} catch (err) {
|
|
12717
|
-
const code = err.code ?? "unknown";
|
|
12718
|
-
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
12719
|
-
continue;
|
|
12720
|
-
}
|
|
12721
|
-
for (const sub of subEntries) {
|
|
12722
|
-
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
12723
|
-
out.push({ path: join14(subDir, sub.name), isSubagent: true });
|
|
12724
|
-
}
|
|
12725
|
-
}
|
|
12726
|
-
}
|
|
12727
|
-
}
|
|
12728
|
-
}
|
|
12729
|
-
return out;
|
|
12730
|
-
}
|
|
12731
|
-
function sessionIdToPidMap(configDir2) {
|
|
12732
|
-
const out = /* @__PURE__ */ new Map();
|
|
12733
|
-
const sessionsDir = join14(configDir2, "sessions");
|
|
12734
|
-
let entries;
|
|
12735
|
-
try {
|
|
12736
|
-
entries = readdirSync9(sessionsDir, { withFileTypes: true });
|
|
12737
|
-
} catch {
|
|
12738
|
-
return out;
|
|
12739
|
-
}
|
|
12740
|
-
for (const entry of entries) {
|
|
12741
|
-
if (!entry.isFile()) continue;
|
|
12742
|
-
const m = entry.name.match(PID_FILE_RE);
|
|
12743
|
-
if (!m) continue;
|
|
12744
|
-
const pid = Number(m[1]);
|
|
12745
|
-
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
12746
|
-
let body;
|
|
12747
|
-
try {
|
|
12748
|
-
body = readFileSync15(join14(sessionsDir, entry.name), "utf8");
|
|
12749
|
-
} catch {
|
|
12750
|
-
continue;
|
|
12751
|
-
}
|
|
12752
|
-
let parsed;
|
|
12753
|
-
try {
|
|
12754
|
-
parsed = JSON.parse(body);
|
|
12755
|
-
} catch {
|
|
12756
|
-
continue;
|
|
12757
|
-
}
|
|
12758
|
-
if (!parsed || typeof parsed !== "object") continue;
|
|
12759
|
-
const sid = parsed.sessionId;
|
|
12760
|
-
if (typeof sid === "string" && sid.length > 0) out.set(sid, pid);
|
|
12761
|
-
}
|
|
12762
|
-
return out;
|
|
12763
|
-
}
|
|
12764
|
-
function loadUserTitles(accountDir) {
|
|
12765
|
-
const out = /* @__PURE__ */ new Map();
|
|
12766
|
-
if (!accountDir) return out;
|
|
12767
|
-
const path2 = join14(accountDir, "session-titles.json");
|
|
12768
|
-
let raw;
|
|
12769
|
-
try {
|
|
12770
|
-
raw = readFileSync15(path2, "utf8");
|
|
12771
|
-
} catch {
|
|
12772
|
-
return out;
|
|
12773
|
-
}
|
|
12774
|
-
let parsed;
|
|
12775
|
-
try {
|
|
12776
|
-
parsed = JSON.parse(raw);
|
|
12777
|
-
} catch {
|
|
12778
|
-
return out;
|
|
12779
|
-
}
|
|
12780
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return out;
|
|
12781
|
-
for (const [sessionId, value] of Object.entries(parsed)) {
|
|
12782
|
-
if (!sessionId) continue;
|
|
12783
|
-
if (!value || typeof value !== "object") continue;
|
|
12784
|
-
const v = value;
|
|
12785
|
-
if (typeof v.title !== "string") continue;
|
|
12786
|
-
const trimmed = v.title.trim();
|
|
12787
|
-
if (!trimmed) continue;
|
|
12788
|
-
out.set(sessionId, trimmed);
|
|
13018
|
+
} finally {
|
|
13019
|
+
await session.close();
|
|
12789
13020
|
}
|
|
12790
|
-
return out;
|
|
12791
13021
|
}
|
|
12792
|
-
function
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
13022
|
+
async function fetchAgentTemplateRows(accountDir) {
|
|
13023
|
+
const rows = [];
|
|
13024
|
+
for (const filename of ADMIN_AGENT_FILES) {
|
|
13025
|
+
const overridePath = resolve18(accountDir, "agents", "admin", filename);
|
|
13026
|
+
const bundledPath = resolve18(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
13027
|
+
const labelStem = filename.replace(/\.md$/, "");
|
|
13028
|
+
const row = await readAgentTemplateRow({
|
|
13029
|
+
id: `agent-template:admin:${filename}`,
|
|
13030
|
+
displayName: `Admin \xB7 ${labelStem}`,
|
|
13031
|
+
logName: `admin/${filename}`,
|
|
13032
|
+
overridePath,
|
|
13033
|
+
overrideRoot: accountDir,
|
|
13034
|
+
bundledPath,
|
|
13035
|
+
bundledRoot: PLATFORM_ROOT
|
|
13036
|
+
});
|
|
13037
|
+
if (row) rows.push(row);
|
|
12798
13038
|
}
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
13039
|
+
const overrideDir = resolve18(accountDir, "specialists", "agents");
|
|
13040
|
+
const bundledDir = resolve18(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
13041
|
+
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
13042
|
+
for (const filename of specialistNames) {
|
|
13043
|
+
const overridePath = resolve18(overrideDir, filename);
|
|
13044
|
+
const bundledPath = resolve18(bundledDir, filename);
|
|
13045
|
+
const row = await readAgentTemplateRow({
|
|
13046
|
+
id: `agent-template:specialist:${filename}`,
|
|
13047
|
+
displayName: filename.replace(/\.md$/, ""),
|
|
13048
|
+
logName: `specialist/${filename}`,
|
|
13049
|
+
overridePath,
|
|
13050
|
+
overrideRoot: accountDir,
|
|
13051
|
+
bundledPath,
|
|
13052
|
+
bundledRoot: PLATFORM_ROOT
|
|
13053
|
+
});
|
|
13054
|
+
if (row) rows.push(row);
|
|
12804
13055
|
}
|
|
12805
|
-
|
|
12806
|
-
const r = parsed;
|
|
12807
|
-
const bridgeIds = Array.isArray(r.bridgeIds) ? r.bridgeIds.filter((b) => typeof b === "string" && b.length > 0) : [];
|
|
12808
|
-
return {
|
|
12809
|
-
bridgeIds,
|
|
12810
|
-
role: typeof r.role === "string" ? r.role : null,
|
|
12811
|
-
channel: typeof r.channel === "string" ? r.channel : null
|
|
12812
|
-
};
|
|
12813
|
-
}
|
|
12814
|
-
function startsWithCliMarker(s) {
|
|
12815
|
-
for (const p of CLI_MARKER_PREFIXES) if (s.startsWith(p)) return true;
|
|
12816
|
-
return false;
|
|
12817
|
-
}
|
|
12818
|
-
function trimToTitle(raw) {
|
|
12819
|
-
return raw.trim().replace(/\s+/g, " ");
|
|
13056
|
+
return rows;
|
|
12820
13057
|
}
|
|
12821
|
-
function
|
|
12822
|
-
const
|
|
12823
|
-
|
|
12824
|
-
|
|
12825
|
-
let firstUserMessage = null;
|
|
12826
|
-
for (const line of body.split("\n")) {
|
|
12827
|
-
if (!line || line[0] !== "{") continue;
|
|
12828
|
-
let parsed;
|
|
13058
|
+
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
13059
|
+
const names = /* @__PURE__ */ new Set();
|
|
13060
|
+
for (const dir of [overrideDir, bundledDir]) {
|
|
13061
|
+
if (!existsSync17(dir)) continue;
|
|
12829
13062
|
try {
|
|
12830
|
-
|
|
12831
|
-
|
|
12832
|
-
|
|
12833
|
-
|
|
12834
|
-
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
const t = row.aiTitle.trim();
|
|
12838
|
-
if (t) aiTitle = t;
|
|
12839
|
-
continue;
|
|
12840
|
-
}
|
|
12841
|
-
if (firstUserMessage === null && row.type === "user" && row.message && row.message.role === "user") {
|
|
12842
|
-
const content = row.message.content;
|
|
12843
|
-
if (typeof content !== "string") continue;
|
|
12844
|
-
const trimmed = content.trim();
|
|
12845
|
-
if (!trimmed) continue;
|
|
12846
|
-
if (startsWithCliMarker(trimmed)) continue;
|
|
12847
|
-
firstUserMessage = trimmed;
|
|
13063
|
+
const entries = await readdir4(dir);
|
|
13064
|
+
for (const entry of entries) {
|
|
13065
|
+
if (entry.endsWith(".md")) names.add(entry);
|
|
13066
|
+
}
|
|
13067
|
+
} catch (err) {
|
|
13068
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13069
|
+
console.error(`[admin/sidebar-artefacts] specialists-read-failed dir=${dir} error="${message}"`);
|
|
12848
13070
|
}
|
|
12849
13071
|
}
|
|
12850
|
-
|
|
12851
|
-
if (firstUserMessage) return { title: trimToTitle(firstUserMessage), source: "first-message" };
|
|
12852
|
-
return { title: sessionId.slice(0, 8), source: "prefix" };
|
|
13072
|
+
return [...names].sort();
|
|
12853
13073
|
}
|
|
12854
|
-
|
|
12855
|
-
|
|
12856
|
-
|
|
12857
|
-
if (!configDir2) {
|
|
12858
|
-
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
12859
|
-
return c.json({ sessions: [], accountId });
|
|
12860
|
-
}
|
|
12861
|
-
const projectsRoot = join14(configDir2, "projects");
|
|
12862
|
-
const jsonls = enumerateJsonls(projectsRoot);
|
|
12863
|
-
const pidsBySession = sessionIdToPidMap(configDir2);
|
|
12864
|
-
const accountDir = accountId ? resolve17(ACCOUNTS_DIR, accountId) : null;
|
|
12865
|
-
const userTitles = loadUserTitles(accountDir);
|
|
12866
|
-
const rows = [];
|
|
12867
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
12868
|
-
let liveCount = 0;
|
|
12869
|
-
let subagentCount = 0;
|
|
12870
|
-
let nonResumableCount = 0;
|
|
12871
|
-
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
12872
|
-
for (const { path: path2, isSubagent } of jsonls) {
|
|
12873
|
-
const lastSlash = path2.lastIndexOf("/");
|
|
12874
|
-
const base = path2.slice(lastSlash + 1);
|
|
12875
|
-
const projectDir = path2.slice(0, lastSlash);
|
|
12876
|
-
const sessionId = base.slice(0, -".jsonl".length);
|
|
12877
|
-
if (seenIds.has(sessionId)) {
|
|
12878
|
-
console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path2}`);
|
|
12879
|
-
continue;
|
|
12880
|
-
}
|
|
12881
|
-
seenIds.add(sessionId);
|
|
12882
|
-
let body;
|
|
12883
|
-
let mtimeMs;
|
|
13074
|
+
async function readAgentTemplateRow(inp) {
|
|
13075
|
+
let chosenPath = null;
|
|
13076
|
+
if (existsSync17(inp.overridePath)) {
|
|
12884
13077
|
try {
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
} catch {
|
|
12888
|
-
|
|
13078
|
+
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
13079
|
+
chosenPath = inp.overridePath;
|
|
13080
|
+
} catch (err) {
|
|
13081
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13082
|
+
console.error(
|
|
13083
|
+
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
|
|
13084
|
+
);
|
|
13085
|
+
return null;
|
|
12889
13086
|
}
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
sessionId,
|
|
12899
|
-
title: resolved.title,
|
|
12900
|
-
titleSource: resolved.source,
|
|
12901
|
-
startedAt: new Date(mtimeMs).toISOString(),
|
|
12902
|
-
live,
|
|
12903
|
-
isSubagent,
|
|
12904
|
-
pid,
|
|
12905
|
-
projectDir,
|
|
12906
|
-
bridgeIds,
|
|
12907
|
-
resumable
|
|
12908
|
-
});
|
|
12909
|
-
if (live) liveCount += 1;
|
|
12910
|
-
if (isSubagent) subagentCount += 1;
|
|
12911
|
-
if (!resumable) nonResumableCount += 1;
|
|
13087
|
+
} else if (existsSync17(inp.bundledPath)) {
|
|
13088
|
+
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
13089
|
+
console.error(
|
|
13090
|
+
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
13091
|
+
);
|
|
13092
|
+
return null;
|
|
13093
|
+
}
|
|
13094
|
+
chosenPath = inp.bundledPath;
|
|
12912
13095
|
}
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
|
|
13096
|
+
if (!chosenPath) return null;
|
|
13097
|
+
try {
|
|
13098
|
+
const st = await stat5(chosenPath);
|
|
13099
|
+
const dlPath = toDataRootRelPath(chosenPath);
|
|
13100
|
+
return {
|
|
13101
|
+
id: inp.id,
|
|
13102
|
+
name: inp.displayName,
|
|
13103
|
+
kind: "agent-template",
|
|
13104
|
+
updatedAt: st.mtime.toISOString(),
|
|
13105
|
+
mimeType: "text/markdown",
|
|
13106
|
+
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
13107
|
+
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
13108
|
+
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
13109
|
+
// Agent templates only ever resolve under DATA_ROOT, so the download
|
|
13110
|
+
// root is `data` whenever the path is non-null.
|
|
13111
|
+
downloadPath: dlPath,
|
|
13112
|
+
downloadRoot: dlPath ? "data" : null
|
|
13113
|
+
};
|
|
13114
|
+
} catch (err) {
|
|
13115
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13116
|
+
console.error(
|
|
13117
|
+
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
|
|
13118
|
+
);
|
|
13119
|
+
return null;
|
|
13120
|
+
}
|
|
13121
|
+
}
|
|
13122
|
+
function isWithin(target, root) {
|
|
13123
|
+
const rel = relative3(root, target);
|
|
13124
|
+
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
13125
|
+
}
|
|
13126
|
+
var sidebar_artefacts_default = app24;
|
|
12920
13127
|
|
|
12921
13128
|
// server/routes/admin/session-delete.ts
|
|
12922
|
-
import { existsSync as existsSync18, readdirSync as readdirSync10, readFileSync as
|
|
12923
|
-
import { join as
|
|
12924
|
-
var
|
|
12925
|
-
var
|
|
13129
|
+
import { existsSync as existsSync18, readdirSync as readdirSync10, readFileSync as readFileSync17, unlinkSync as unlinkSync2 } from "fs";
|
|
13130
|
+
import { join as join16, resolve as resolve19 } from "path";
|
|
13131
|
+
var app25 = new Hono();
|
|
13132
|
+
var SESSION_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12926
13133
|
var PID_FILE_RE2 = /^([0-9]+)\.json$/;
|
|
12927
13134
|
var SIGTERM_WAIT_MS = 2e3;
|
|
12928
13135
|
var SIGKILL_WAIT_MS = 1e3;
|
|
12929
13136
|
var POLL_INTERVAL_MS = 50;
|
|
12930
13137
|
function findPidForSession(configDir2, sessionId) {
|
|
12931
|
-
const sessionsDir =
|
|
13138
|
+
const sessionsDir = join16(configDir2, "sessions");
|
|
12932
13139
|
let entries;
|
|
12933
13140
|
try {
|
|
12934
13141
|
entries = readdirSync10(sessionsDir, { withFileTypes: true });
|
|
@@ -12943,7 +13150,7 @@ function findPidForSession(configDir2, sessionId) {
|
|
|
12943
13150
|
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
12944
13151
|
let body;
|
|
12945
13152
|
try {
|
|
12946
|
-
body =
|
|
13153
|
+
body = readFileSync17(join16(sessionsDir, entry.name), "utf8");
|
|
12947
13154
|
} catch {
|
|
12948
13155
|
continue;
|
|
12949
13156
|
}
|
|
@@ -12969,7 +13176,7 @@ function isPidAlive(pid) {
|
|
|
12969
13176
|
}
|
|
12970
13177
|
}
|
|
12971
13178
|
function sleep2(ms) {
|
|
12972
|
-
return new Promise((
|
|
13179
|
+
return new Promise((resolve28) => setTimeout(resolve28, ms));
|
|
12973
13180
|
}
|
|
12974
13181
|
function sendSignal(pid, signal) {
|
|
12975
13182
|
try {
|
|
@@ -13018,7 +13225,7 @@ async function killAndWait(pid) {
|
|
|
13018
13225
|
exited: false
|
|
13019
13226
|
};
|
|
13020
13227
|
}
|
|
13021
|
-
|
|
13228
|
+
app25.post("/", requireAdminSession, async (c) => {
|
|
13022
13229
|
let body;
|
|
13023
13230
|
try {
|
|
13024
13231
|
body = await c.req.json();
|
|
@@ -13027,7 +13234,7 @@ app24.post("/", requireAdminSession, async (c) => {
|
|
|
13027
13234
|
}
|
|
13028
13235
|
const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
|
|
13029
13236
|
const projectDir = typeof body.projectDir === "string" ? body.projectDir : "";
|
|
13030
|
-
if (!
|
|
13237
|
+
if (!SESSION_ID_RE3.test(sessionId)) {
|
|
13031
13238
|
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
13032
13239
|
}
|
|
13033
13240
|
if (!projectDir) {
|
|
@@ -13037,14 +13244,14 @@ app24.post("/", requireAdminSession, async (c) => {
|
|
|
13037
13244
|
if (!configDir2) {
|
|
13038
13245
|
return c.json({ error: "CLAUDE_CONFIG_DIR not set" }, 500);
|
|
13039
13246
|
}
|
|
13040
|
-
const projectsRoot =
|
|
13041
|
-
const resolvedProject =
|
|
13247
|
+
const projectsRoot = resolve19(join16(configDir2, "projects")) + "/";
|
|
13248
|
+
const resolvedProject = resolve19(projectDir) + "/";
|
|
13042
13249
|
if (!resolvedProject.startsWith(projectsRoot)) {
|
|
13043
13250
|
console.error(`[sessions-delete] reject reason=projectDir-outside-tree projectDir=${projectDir}`);
|
|
13044
13251
|
return c.json({ error: "projectDir is not under CLAUDE_CONFIG_DIR/projects/" }, 400);
|
|
13045
13252
|
}
|
|
13046
|
-
const jsonlPath =
|
|
13047
|
-
const sidecarPath =
|
|
13253
|
+
const jsonlPath = join16(projectDir, `${sessionId}.jsonl`);
|
|
13254
|
+
const sidecarPath = join16(projectDir, `${sessionId}.meta.json`);
|
|
13048
13255
|
const pid = findPidForSession(configDir2, sessionId);
|
|
13049
13256
|
let pidKilled = "absent";
|
|
13050
13257
|
let waitForExitMs = 0;
|
|
@@ -13084,7 +13291,7 @@ app24.post("/", requireAdminSession, async (c) => {
|
|
|
13084
13291
|
}
|
|
13085
13292
|
if (pid !== null) {
|
|
13086
13293
|
try {
|
|
13087
|
-
const pidFile =
|
|
13294
|
+
const pidFile = join16(configDir2, "sessions", `${pid}.json`);
|
|
13088
13295
|
if (existsSync18(pidFile)) unlinkSync2(pidFile);
|
|
13089
13296
|
} catch {
|
|
13090
13297
|
}
|
|
@@ -13101,16 +13308,16 @@ app24.post("/", requireAdminSession, async (c) => {
|
|
|
13101
13308
|
);
|
|
13102
13309
|
return c.json({ deleted, pidKilled, jsonlPath, waitForExitMs, escalatedToSIGKILL });
|
|
13103
13310
|
});
|
|
13104
|
-
var session_delete_default =
|
|
13311
|
+
var session_delete_default = app25;
|
|
13105
13312
|
|
|
13106
13313
|
// server/routes/admin/session-rc-spawn.ts
|
|
13107
|
-
var
|
|
13314
|
+
var app26 = new Hono();
|
|
13108
13315
|
function managerBase4() {
|
|
13109
13316
|
const port2 = process.env.CLAUDE_SESSION_MANAGER_PORT;
|
|
13110
13317
|
if (!port2) throw new Error("CLAUDE_SESSION_MANAGER_PORT is not set");
|
|
13111
13318
|
return `http://127.0.0.1:${port2}`;
|
|
13112
13319
|
}
|
|
13113
|
-
|
|
13320
|
+
app26.post("/", requireAdminSession, async (c) => {
|
|
13114
13321
|
let body;
|
|
13115
13322
|
try {
|
|
13116
13323
|
body = await c.req.json();
|
|
@@ -13144,7 +13351,7 @@ app25.post("/", requireAdminSession, async (c) => {
|
|
|
13144
13351
|
}
|
|
13145
13352
|
return c.json(parsed ?? {});
|
|
13146
13353
|
});
|
|
13147
|
-
var session_rc_spawn_default =
|
|
13354
|
+
var session_rc_spawn_default = app26;
|
|
13148
13355
|
|
|
13149
13356
|
// server/routes/admin/system-stats.ts
|
|
13150
13357
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -13241,8 +13448,8 @@ async function sample() {
|
|
|
13241
13448
|
if (process.platform === "linux") return sampleLinux();
|
|
13242
13449
|
return sampleOsFallback();
|
|
13243
13450
|
}
|
|
13244
|
-
var
|
|
13245
|
-
|
|
13451
|
+
var app27 = new Hono();
|
|
13452
|
+
app27.get("/", async (c) => {
|
|
13246
13453
|
const started = Date.now();
|
|
13247
13454
|
if (!inflight) {
|
|
13248
13455
|
inflight = sample().finally(() => {
|
|
@@ -13265,27 +13472,27 @@ app26.get("/", async (c) => {
|
|
|
13265
13472
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
13266
13473
|
}
|
|
13267
13474
|
});
|
|
13268
|
-
var system_stats_default =
|
|
13475
|
+
var system_stats_default = app27;
|
|
13269
13476
|
|
|
13270
13477
|
// server/routes/admin/health.ts
|
|
13271
|
-
import { existsSync as existsSync19, readFileSync as
|
|
13272
|
-
import { resolve as
|
|
13273
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
13478
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
|
|
13479
|
+
import { resolve as resolve20, join as join17 } from "path";
|
|
13480
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
13274
13481
|
var brandHostname = "maxy";
|
|
13275
|
-
var brandJsonPath =
|
|
13482
|
+
var brandJsonPath = join17(PLATFORM_ROOT6, "config", "brand.json");
|
|
13276
13483
|
if (existsSync19(brandJsonPath)) {
|
|
13277
13484
|
try {
|
|
13278
|
-
const brand = JSON.parse(
|
|
13485
|
+
const brand = JSON.parse(readFileSync18(brandJsonPath, "utf-8"));
|
|
13279
13486
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
13280
13487
|
} catch {
|
|
13281
13488
|
}
|
|
13282
13489
|
}
|
|
13283
|
-
var VERSION_FILE =
|
|
13490
|
+
var VERSION_FILE = resolve20(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
13284
13491
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
13285
13492
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
13286
13493
|
function readVersion() {
|
|
13287
13494
|
if (!existsSync19(VERSION_FILE)) return "unknown";
|
|
13288
|
-
return
|
|
13495
|
+
return readFileSync18(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
13289
13496
|
}
|
|
13290
13497
|
async function probeConversationDb() {
|
|
13291
13498
|
let session;
|
|
@@ -13310,8 +13517,8 @@ async function probeConversationDb() {
|
|
|
13310
13517
|
});
|
|
13311
13518
|
}
|
|
13312
13519
|
}
|
|
13313
|
-
var
|
|
13314
|
-
|
|
13520
|
+
var app28 = new Hono();
|
|
13521
|
+
app28.get("/", async (c) => {
|
|
13315
13522
|
const version = readVersion();
|
|
13316
13523
|
const probe = await probeConversationDb();
|
|
13317
13524
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -13333,7 +13540,7 @@ app27.get("/", async (c) => {
|
|
|
13333
13540
|
uptimeMs
|
|
13334
13541
|
});
|
|
13335
13542
|
});
|
|
13336
|
-
var health_default2 =
|
|
13543
|
+
var health_default2 = app28;
|
|
13337
13544
|
|
|
13338
13545
|
// server/routes/admin/linkedin-ingest.ts
|
|
13339
13546
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -13435,8 +13642,8 @@ function buildInitialMessage(env) {
|
|
|
13435
13642
|
}
|
|
13436
13643
|
return header;
|
|
13437
13644
|
}
|
|
13438
|
-
var
|
|
13439
|
-
|
|
13645
|
+
var app29 = new Hono();
|
|
13646
|
+
app29.post("/", requireAdminSession, async (c) => {
|
|
13440
13647
|
let body;
|
|
13441
13648
|
try {
|
|
13442
13649
|
body = await c.req.json();
|
|
@@ -13481,7 +13688,7 @@ app28.post("/", requireAdminSession, async (c) => {
|
|
|
13481
13688
|
);
|
|
13482
13689
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
13483
13690
|
});
|
|
13484
|
-
var linkedin_ingest_default =
|
|
13691
|
+
var linkedin_ingest_default = app29;
|
|
13485
13692
|
|
|
13486
13693
|
// server/routes/admin/post-turn-context.ts
|
|
13487
13694
|
import neo4j2 from "neo4j-driver";
|
|
@@ -13523,8 +13730,8 @@ function pruneProperties(raw) {
|
|
|
13523
13730
|
}
|
|
13524
13731
|
return out;
|
|
13525
13732
|
}
|
|
13526
|
-
var
|
|
13527
|
-
|
|
13733
|
+
var app30 = new Hono();
|
|
13734
|
+
app30.get("/", async (c) => {
|
|
13528
13735
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
13529
13736
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
13530
13737
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -13584,7 +13791,7 @@ app29.get("/", async (c) => {
|
|
|
13584
13791
|
await session.close();
|
|
13585
13792
|
}
|
|
13586
13793
|
});
|
|
13587
|
-
var post_turn_context_default =
|
|
13794
|
+
var post_turn_context_default = app30;
|
|
13588
13795
|
|
|
13589
13796
|
// server/routes/admin/public-session-context.ts
|
|
13590
13797
|
import neo4j3 from "neo4j-driver";
|
|
@@ -13626,8 +13833,8 @@ function pruneProperties2(raw) {
|
|
|
13626
13833
|
}
|
|
13627
13834
|
return out;
|
|
13628
13835
|
}
|
|
13629
|
-
var
|
|
13630
|
-
|
|
13836
|
+
var app31 = new Hono();
|
|
13837
|
+
app31.get("/", async (c) => {
|
|
13631
13838
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
13632
13839
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
13633
13840
|
console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -13686,15 +13893,15 @@ app30.get("/", async (c) => {
|
|
|
13686
13893
|
await session.close();
|
|
13687
13894
|
}
|
|
13688
13895
|
});
|
|
13689
|
-
var public_session_context_default =
|
|
13896
|
+
var public_session_context_default = app31;
|
|
13690
13897
|
|
|
13691
13898
|
// server/routes/admin/public-session-exit.ts
|
|
13692
13899
|
var TAG26 = "[public-session-exit-route]";
|
|
13693
13900
|
function isLoopbackAddr4(addr) {
|
|
13694
13901
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
13695
13902
|
}
|
|
13696
|
-
var
|
|
13697
|
-
|
|
13903
|
+
var app32 = new Hono();
|
|
13904
|
+
app32.post("/", async (c) => {
|
|
13698
13905
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
13699
13906
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
13700
13907
|
console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -13721,15 +13928,15 @@ app31.post("/", async (c) => {
|
|
|
13721
13928
|
handlePublicSessionExit(sessionId);
|
|
13722
13929
|
return c.json({ ok: true });
|
|
13723
13930
|
});
|
|
13724
|
-
var public_session_exit_default =
|
|
13931
|
+
var public_session_exit_default = app32;
|
|
13725
13932
|
|
|
13726
13933
|
// server/routes/admin/access-session-evict.ts
|
|
13727
13934
|
var TAG27 = "[access-session-evict]";
|
|
13728
13935
|
function isLoopbackAddr5(addr) {
|
|
13729
13936
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
13730
13937
|
}
|
|
13731
|
-
var
|
|
13732
|
-
|
|
13938
|
+
var app33 = new Hono();
|
|
13939
|
+
app33.post("/", async (c) => {
|
|
13733
13940
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
13734
13941
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
13735
13942
|
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -13757,11 +13964,11 @@ app32.post("/", async (c) => {
|
|
|
13757
13964
|
console.log(`${TAG27} grantId=${grantId} dropped=${dropped}`);
|
|
13758
13965
|
return c.json({ ok: true, dropped });
|
|
13759
13966
|
});
|
|
13760
|
-
var access_session_evict_default =
|
|
13967
|
+
var access_session_evict_default = app33;
|
|
13761
13968
|
|
|
13762
13969
|
// server/routes/admin/browser.ts
|
|
13763
|
-
var
|
|
13764
|
-
|
|
13970
|
+
var app34 = new Hono();
|
|
13971
|
+
app34.post("/launch", requireAdminSession, async (c) => {
|
|
13765
13972
|
try {
|
|
13766
13973
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
13767
13974
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -13789,52 +13996,52 @@ app33.post("/launch", requireAdminSession, async (c) => {
|
|
|
13789
13996
|
);
|
|
13790
13997
|
}
|
|
13791
13998
|
});
|
|
13792
|
-
var browser_default =
|
|
13999
|
+
var browser_default = app34;
|
|
13793
14000
|
|
|
13794
14001
|
// server/routes/admin/index.ts
|
|
13795
|
-
var
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
var admin_default =
|
|
14002
|
+
var app35 = new Hono();
|
|
14003
|
+
app35.route("/session", session_default);
|
|
14004
|
+
app35.route("/logs", logs_default);
|
|
14005
|
+
app35.route("/claude-info", claude_info_default);
|
|
14006
|
+
app35.route("/attachment", attachment_default);
|
|
14007
|
+
app35.route("/agents", agents_default);
|
|
14008
|
+
app35.route("/sessions", sessions_default);
|
|
14009
|
+
app35.route("/claude-sessions", claude_sessions_default);
|
|
14010
|
+
app35.route("/log-ingest", log_ingest_default);
|
|
14011
|
+
app35.route("/events", events_default);
|
|
14012
|
+
app35.route("/files", files_default);
|
|
14013
|
+
app35.route("/graph-search", graph_search_default);
|
|
14014
|
+
app35.route("/graph-subgraph", graph_subgraph_default);
|
|
14015
|
+
app35.route("/graph-delete", graph_delete_default);
|
|
14016
|
+
app35.route("/graph-restore", graph_restore_default);
|
|
14017
|
+
app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
14018
|
+
app35.route("/graph-default-view", graph_default_view_default);
|
|
14019
|
+
app35.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
14020
|
+
app35.route("/sidebar-sessions", sidebar_sessions_default);
|
|
14021
|
+
app35.route("/session-delete", session_delete_default);
|
|
14022
|
+
app35.route("/browser", browser_default);
|
|
14023
|
+
app35.route("/session-rc-spawn", session_rc_spawn_default);
|
|
14024
|
+
app35.route("/system-stats", system_stats_default);
|
|
14025
|
+
app35.route("/health-brand", health_default2);
|
|
14026
|
+
app35.route("/linkedin-ingest", linkedin_ingest_default);
|
|
14027
|
+
app35.route("/post-turn-context", post_turn_context_default);
|
|
14028
|
+
app35.route("/public-session-context", public_session_context_default);
|
|
14029
|
+
app35.route("/public-session-exit", public_session_exit_default);
|
|
14030
|
+
app35.route("/access-session-evict", access_session_evict_default);
|
|
14031
|
+
var admin_default = app35;
|
|
13825
14032
|
|
|
13826
14033
|
// app/lib/access-gate.ts
|
|
13827
14034
|
import neo4j4 from "neo4j-driver";
|
|
13828
|
-
import { readFileSync as
|
|
13829
|
-
import { resolve as
|
|
14035
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
14036
|
+
import { resolve as resolve21 } from "path";
|
|
13830
14037
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
13831
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14038
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
13832
14039
|
var driver = null;
|
|
13833
14040
|
function readPassword() {
|
|
13834
14041
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
13835
|
-
const passwordFile =
|
|
14042
|
+
const passwordFile = resolve21(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
13836
14043
|
try {
|
|
13837
|
-
return
|
|
14044
|
+
return readFileSync19(passwordFile, "utf-8").trim();
|
|
13838
14045
|
} catch {
|
|
13839
14046
|
throw new Error(
|
|
13840
14047
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -14035,8 +14242,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
14035
14242
|
var TAG28 = "[access-verify]";
|
|
14036
14243
|
var MINT_TAG = "[access-session-mint]";
|
|
14037
14244
|
var COOKIE_NAME = "__access_session";
|
|
14038
|
-
var
|
|
14039
|
-
|
|
14245
|
+
var app36 = new Hono();
|
|
14246
|
+
app36.post("/", async (c) => {
|
|
14040
14247
|
const ip = c.var.clientIp || "unknown";
|
|
14041
14248
|
let body;
|
|
14042
14249
|
try {
|
|
@@ -14118,13 +14325,13 @@ app35.post("/", async (c) => {
|
|
|
14118
14325
|
displayName: grant.displayName
|
|
14119
14326
|
});
|
|
14120
14327
|
});
|
|
14121
|
-
var verify_token_default =
|
|
14328
|
+
var verify_token_default = app36;
|
|
14122
14329
|
|
|
14123
14330
|
// app/lib/access-email.ts
|
|
14124
14331
|
import { spawn as spawn2 } from "child_process";
|
|
14125
|
-
import { resolve as
|
|
14126
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14127
|
-
var SEND_SCRIPT =
|
|
14332
|
+
import { resolve as resolve22 } from "path";
|
|
14333
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
|
|
14334
|
+
var SEND_SCRIPT = resolve22(
|
|
14128
14335
|
PLATFORM_ROOT8,
|
|
14129
14336
|
"plugins",
|
|
14130
14337
|
"email",
|
|
@@ -14181,9 +14388,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
14181
14388
|
|
|
14182
14389
|
// server/routes/access/request-magic-link.ts
|
|
14183
14390
|
var TAG29 = "[access-request-link]";
|
|
14184
|
-
var
|
|
14391
|
+
var app37 = new Hono();
|
|
14185
14392
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
14186
|
-
|
|
14393
|
+
app37.post("/", async (c) => {
|
|
14187
14394
|
let body;
|
|
14188
14395
|
try {
|
|
14189
14396
|
body = await c.req.json();
|
|
@@ -14257,17 +14464,17 @@ app36.post("/", async (c) => {
|
|
|
14257
14464
|
);
|
|
14258
14465
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
14259
14466
|
});
|
|
14260
|
-
var request_magic_link_default =
|
|
14467
|
+
var request_magic_link_default = app37;
|
|
14261
14468
|
|
|
14262
14469
|
// server/routes/access/index.ts
|
|
14263
|
-
var
|
|
14264
|
-
|
|
14265
|
-
|
|
14266
|
-
var access_default =
|
|
14470
|
+
var app38 = new Hono();
|
|
14471
|
+
app38.route("/verify-token", verify_token_default);
|
|
14472
|
+
app38.route("/request-magic-link", request_magic_link_default);
|
|
14473
|
+
var access_default = app38;
|
|
14267
14474
|
|
|
14268
14475
|
// server/routes/sites.ts
|
|
14269
|
-
import { existsSync as existsSync20, readFileSync as
|
|
14270
|
-
import { resolve as
|
|
14476
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
|
|
14477
|
+
import { resolve as resolve23 } from "path";
|
|
14271
14478
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14272
14479
|
var MIME = {
|
|
14273
14480
|
".html": "text/html; charset=utf-8",
|
|
@@ -14298,8 +14505,8 @@ function getExt(p) {
|
|
|
14298
14505
|
if (idx < p.lastIndexOf("/")) return "";
|
|
14299
14506
|
return p.slice(idx).toLowerCase();
|
|
14300
14507
|
}
|
|
14301
|
-
var
|
|
14302
|
-
|
|
14508
|
+
var app39 = new Hono();
|
|
14509
|
+
app39.get("/:rel{.*}", (c) => {
|
|
14303
14510
|
const reqPath = c.req.path;
|
|
14304
14511
|
const rawRel = c.req.param("rel") ?? "";
|
|
14305
14512
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -14324,15 +14531,15 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
14324
14531
|
}
|
|
14325
14532
|
segments.push(seg);
|
|
14326
14533
|
}
|
|
14327
|
-
const rootDir =
|
|
14328
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
14534
|
+
const rootDir = resolve23(account.accountDir, "sites");
|
|
14535
|
+
let filePath = segments.length === 0 ? rootDir : resolve23(rootDir, ...segments);
|
|
14329
14536
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
14330
14537
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
14331
14538
|
return c.text("Forbidden", 403);
|
|
14332
14539
|
}
|
|
14333
14540
|
let stat7;
|
|
14334
14541
|
try {
|
|
14335
|
-
stat7 = existsSync20(filePath) ?
|
|
14542
|
+
stat7 = existsSync20(filePath) ? statSync9(filePath) : null;
|
|
14336
14543
|
} catch {
|
|
14337
14544
|
stat7 = null;
|
|
14338
14545
|
}
|
|
@@ -14345,7 +14552,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
14345
14552
|
return c.redirect(target, 301);
|
|
14346
14553
|
}
|
|
14347
14554
|
if (stat7?.isDirectory()) {
|
|
14348
|
-
filePath =
|
|
14555
|
+
filePath = resolve23(filePath, "index.html");
|
|
14349
14556
|
}
|
|
14350
14557
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
14351
14558
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -14370,7 +14577,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
14370
14577
|
}
|
|
14371
14578
|
let body;
|
|
14372
14579
|
try {
|
|
14373
|
-
body =
|
|
14580
|
+
body = readFileSync20(realPath);
|
|
14374
14581
|
} catch (err) {
|
|
14375
14582
|
const code = err?.code;
|
|
14376
14583
|
if (code === "EISDIR") {
|
|
@@ -14402,12 +14609,12 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
14402
14609
|
"X-Content-Type-Options": "nosniff"
|
|
14403
14610
|
});
|
|
14404
14611
|
});
|
|
14405
|
-
var sites_default =
|
|
14612
|
+
var sites_default = app39;
|
|
14406
14613
|
|
|
14407
14614
|
// app/lib/visitor-token.ts
|
|
14408
14615
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
14409
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
14410
|
-
import { dirname as
|
|
14616
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync21, writeFileSync as writeFileSync7 } from "fs";
|
|
14617
|
+
import { dirname as dirname5 } from "path";
|
|
14411
14618
|
var TOKEN_PREFIX = "v1.";
|
|
14412
14619
|
var SECRET_BYTES = 32;
|
|
14413
14620
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -14415,7 +14622,7 @@ var cachedSecret = null;
|
|
|
14415
14622
|
function getSecret() {
|
|
14416
14623
|
if (cachedSecret) return cachedSecret;
|
|
14417
14624
|
try {
|
|
14418
|
-
const hex2 =
|
|
14625
|
+
const hex2 = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
14419
14626
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
14420
14627
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
14421
14628
|
return cachedSecret;
|
|
@@ -14424,12 +14631,12 @@ function getSecret() {
|
|
|
14424
14631
|
}
|
|
14425
14632
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
14426
14633
|
try {
|
|
14427
|
-
mkdirSync4(
|
|
14634
|
+
mkdirSync4(dirname5(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
14428
14635
|
writeFileSync7(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
14429
14636
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
14430
14637
|
} catch {
|
|
14431
14638
|
}
|
|
14432
|
-
const hex =
|
|
14639
|
+
const hex = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
14433
14640
|
cachedSecret = Buffer.from(hex, "hex");
|
|
14434
14641
|
return cachedSecret;
|
|
14435
14642
|
}
|
|
@@ -14482,8 +14689,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
14482
14689
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
14483
14690
|
|
|
14484
14691
|
// app/lib/brand-config.ts
|
|
14485
|
-
import { existsSync as existsSync21, readFileSync as
|
|
14486
|
-
import { join as
|
|
14692
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
|
|
14693
|
+
import { join as join18 } from "path";
|
|
14487
14694
|
var cached2 = null;
|
|
14488
14695
|
var cachedAttempted = false;
|
|
14489
14696
|
function readBrandConfig() {
|
|
@@ -14491,10 +14698,10 @@ function readBrandConfig() {
|
|
|
14491
14698
|
cachedAttempted = true;
|
|
14492
14699
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
14493
14700
|
if (!platformRoot2) return null;
|
|
14494
|
-
const brandPath =
|
|
14701
|
+
const brandPath = join18(platformRoot2, "config", "brand.json");
|
|
14495
14702
|
if (!existsSync21(brandPath)) return null;
|
|
14496
14703
|
try {
|
|
14497
|
-
cached2 = JSON.parse(
|
|
14704
|
+
cached2 = JSON.parse(readFileSync22(brandPath, "utf-8"));
|
|
14498
14705
|
return cached2;
|
|
14499
14706
|
} catch {
|
|
14500
14707
|
return null;
|
|
@@ -14502,7 +14709,7 @@ function readBrandConfig() {
|
|
|
14502
14709
|
}
|
|
14503
14710
|
|
|
14504
14711
|
// server/routes/visitor-consent.ts
|
|
14505
|
-
var
|
|
14712
|
+
var app40 = new Hono();
|
|
14506
14713
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
14507
14714
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
14508
14715
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -14547,17 +14754,17 @@ function siteSlugFromReferer(referer) {
|
|
|
14547
14754
|
return "";
|
|
14548
14755
|
}
|
|
14549
14756
|
}
|
|
14550
|
-
|
|
14757
|
+
app40.options("/consent", (c) => {
|
|
14551
14758
|
const origin = getOrigin(c);
|
|
14552
14759
|
setCorsHeaders(c, origin);
|
|
14553
14760
|
return c.body(null, 204);
|
|
14554
14761
|
});
|
|
14555
|
-
|
|
14762
|
+
app40.options("/brand-config", (c) => {
|
|
14556
14763
|
const origin = getOrigin(c);
|
|
14557
14764
|
setCorsHeaders(c, origin);
|
|
14558
14765
|
return c.body(null, 204);
|
|
14559
14766
|
});
|
|
14560
|
-
|
|
14767
|
+
app40.post("/consent", async (c) => {
|
|
14561
14768
|
const origin = getOrigin(c);
|
|
14562
14769
|
setCorsHeaders(c, origin);
|
|
14563
14770
|
let raw;
|
|
@@ -14597,7 +14804,7 @@ app39.post("/consent", async (c) => {
|
|
|
14597
14804
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
14598
14805
|
return c.body(null, 204);
|
|
14599
14806
|
});
|
|
14600
|
-
|
|
14807
|
+
app40.get("/brand-config", (c) => {
|
|
14601
14808
|
const origin = getOrigin(c);
|
|
14602
14809
|
setCorsHeaders(c, origin);
|
|
14603
14810
|
const brand = readBrandConfig();
|
|
@@ -14607,7 +14814,7 @@ app39.get("/brand-config", (c) => {
|
|
|
14607
14814
|
c.header("Cache-Control", "public, max-age=300");
|
|
14608
14815
|
return c.json({ consent: { copy, palette } });
|
|
14609
14816
|
});
|
|
14610
|
-
var visitor_consent_default =
|
|
14817
|
+
var visitor_consent_default = app40;
|
|
14611
14818
|
|
|
14612
14819
|
// server/routes/listings.ts
|
|
14613
14820
|
function getCookie(headerValue, name) {
|
|
@@ -14628,14 +14835,14 @@ function appendConsentParams(pageUrl, token) {
|
|
|
14628
14835
|
const hashIdx = pageUrl.indexOf("#");
|
|
14629
14836
|
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
14630
14837
|
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
14631
|
-
const
|
|
14632
|
-
return base +
|
|
14838
|
+
const sep8 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
14839
|
+
return base + sep8 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
14633
14840
|
}
|
|
14634
14841
|
}
|
|
14635
14842
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
14636
14843
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
14637
|
-
var
|
|
14638
|
-
|
|
14844
|
+
var app41 = new Hono();
|
|
14845
|
+
app41.get("/:slug/click", async (c) => {
|
|
14639
14846
|
const slug = c.req.param("slug") ?? "";
|
|
14640
14847
|
const rawSession = c.req.query("session") ?? "";
|
|
14641
14848
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -14699,10 +14906,10 @@ app40.get("/:slug/click", async (c) => {
|
|
|
14699
14906
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
14700
14907
|
return c.redirect(redirectUrl, 302);
|
|
14701
14908
|
});
|
|
14702
|
-
var listings_default =
|
|
14909
|
+
var listings_default = app41;
|
|
14703
14910
|
|
|
14704
14911
|
// server/routes/visitor-event.ts
|
|
14705
|
-
var
|
|
14912
|
+
var app42 = new Hono();
|
|
14706
14913
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
14707
14914
|
var buckets = /* @__PURE__ */ new Map();
|
|
14708
14915
|
var RATE_LIMIT = 60;
|
|
@@ -14769,12 +14976,12 @@ function originAllowed(origin, allowlist) {
|
|
|
14769
14976
|
return false;
|
|
14770
14977
|
}
|
|
14771
14978
|
}
|
|
14772
|
-
|
|
14979
|
+
app42.options("/event", (c) => {
|
|
14773
14980
|
const origin = getOrigin2(c);
|
|
14774
14981
|
setCorsHeaders2(c, origin);
|
|
14775
14982
|
return c.body(null, 204);
|
|
14776
14983
|
});
|
|
14777
|
-
|
|
14984
|
+
app42.post("/event", async (c) => {
|
|
14778
14985
|
const origin = getOrigin2(c);
|
|
14779
14986
|
setCorsHeaders2(c, origin);
|
|
14780
14987
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -14979,17 +15186,17 @@ async function writeEvent(opts) {
|
|
|
14979
15186
|
);
|
|
14980
15187
|
}
|
|
14981
15188
|
}
|
|
14982
|
-
var visitor_event_default =
|
|
15189
|
+
var visitor_event_default = app42;
|
|
14983
15190
|
|
|
14984
15191
|
// server/routes/session.ts
|
|
14985
|
-
import { resolve as
|
|
15192
|
+
import { resolve as resolve24 } from "path";
|
|
14986
15193
|
import { existsSync as existsSync22, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
14987
15194
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14988
15195
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
14989
15196
|
try {
|
|
14990
|
-
const cacheDir =
|
|
15197
|
+
const cacheDir = resolve24(MAXY_DIR, "branding-cache", accountId);
|
|
14991
15198
|
mkdirSync5(cacheDir, { recursive: true });
|
|
14992
|
-
writeFileSync8(
|
|
15199
|
+
writeFileSync8(resolve24(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
14993
15200
|
} catch (err) {
|
|
14994
15201
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14995
15202
|
}
|
|
@@ -15025,8 +15232,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
15025
15232
|
headers
|
|
15026
15233
|
});
|
|
15027
15234
|
}
|
|
15028
|
-
var
|
|
15029
|
-
|
|
15235
|
+
var app43 = new Hono();
|
|
15236
|
+
app43.post("/", async (c) => {
|
|
15030
15237
|
let body;
|
|
15031
15238
|
try {
|
|
15032
15239
|
body = await c.req.json();
|
|
@@ -15077,8 +15284,8 @@ app42.post("/", async (c) => {
|
|
|
15077
15284
|
}
|
|
15078
15285
|
let agentConfig = null;
|
|
15079
15286
|
if (account) {
|
|
15080
|
-
const agentDir =
|
|
15081
|
-
if (!existsSync22(agentDir) || !existsSync22(
|
|
15287
|
+
const agentDir = resolve24(account.accountDir, "agents", agentSlug);
|
|
15288
|
+
if (!existsSync22(agentDir) || !existsSync22(resolve24(agentDir, "config.json"))) {
|
|
15082
15289
|
return c.json({ error: "Agent not found" }, 404);
|
|
15083
15290
|
}
|
|
15084
15291
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -15237,7 +15444,7 @@ app42.post("/", async (c) => {
|
|
|
15237
15444
|
newVisitorId
|
|
15238
15445
|
);
|
|
15239
15446
|
});
|
|
15240
|
-
var session_default2 =
|
|
15447
|
+
var session_default2 = app43;
|
|
15241
15448
|
|
|
15242
15449
|
// app/lib/graph-health.ts
|
|
15243
15450
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -15358,13 +15565,13 @@ function startGraphHealthTimer() {
|
|
|
15358
15565
|
|
|
15359
15566
|
// app/lib/file-watcher.ts
|
|
15360
15567
|
import * as fsp2 from "fs/promises";
|
|
15361
|
-
import { resolve as
|
|
15568
|
+
import { resolve as resolve25, sep as sep7 } from "path";
|
|
15362
15569
|
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;
|
|
15363
15570
|
var DEFAULT_COALESCE_MS = 500;
|
|
15364
15571
|
var ROOTS = ["uploads", "accounts"];
|
|
15365
15572
|
function _routeEvent(rootName, filename) {
|
|
15366
15573
|
if (!filename) return null;
|
|
15367
|
-
const segs = filename.split(
|
|
15574
|
+
const segs = filename.split(sep7).filter(Boolean);
|
|
15368
15575
|
if (segs.length < 2) return null;
|
|
15369
15576
|
const accountId = segs[0];
|
|
15370
15577
|
if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
|
|
@@ -15377,7 +15584,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
15377
15584
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
15378
15585
|
for (const r of ROOTS) {
|
|
15379
15586
|
try {
|
|
15380
|
-
await fsp2.mkdir(
|
|
15587
|
+
await fsp2.mkdir(resolve25(dataRoot, r), { recursive: true });
|
|
15381
15588
|
} catch (err) {
|
|
15382
15589
|
console.error(
|
|
15383
15590
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -15398,7 +15605,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
15398
15605
|
timers.set(relativePath, t);
|
|
15399
15606
|
}
|
|
15400
15607
|
async function runHook(relativePath, accountId) {
|
|
15401
|
-
const absolute =
|
|
15608
|
+
const absolute = resolve25(dataRoot, relativePath);
|
|
15402
15609
|
let exists = false;
|
|
15403
15610
|
try {
|
|
15404
15611
|
const st = await fsp2.stat(absolute);
|
|
@@ -15422,7 +15629,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
15422
15629
|
}
|
|
15423
15630
|
}
|
|
15424
15631
|
async function watchRoot(rootName) {
|
|
15425
|
-
const absRoot =
|
|
15632
|
+
const absRoot = resolve25(dataRoot, rootName);
|
|
15426
15633
|
try {
|
|
15427
15634
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
15428
15635
|
for await (const event of iter) {
|
|
@@ -15732,8 +15939,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
15732
15939
|
|
|
15733
15940
|
// app/lib/whatsapp/gateway/routes.ts
|
|
15734
15941
|
function createWaChannelRoutes(deps) {
|
|
15735
|
-
const
|
|
15736
|
-
|
|
15942
|
+
const app45 = new Hono();
|
|
15943
|
+
app45.get("/wa-channel/inbound", (c) => {
|
|
15737
15944
|
const senderId = c.req.query("senderId");
|
|
15738
15945
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
15739
15946
|
return streamSSE(c, async (stream2) => {
|
|
@@ -15751,7 +15958,7 @@ function createWaChannelRoutes(deps) {
|
|
|
15751
15958
|
}
|
|
15752
15959
|
});
|
|
15753
15960
|
});
|
|
15754
|
-
|
|
15961
|
+
app45.post("/wa-channel/reply", async (c) => {
|
|
15755
15962
|
const body = await c.req.json().catch(() => null);
|
|
15756
15963
|
const senderId = body?.senderId;
|
|
15757
15964
|
const text = body?.text;
|
|
@@ -15770,7 +15977,7 @@ function createWaChannelRoutes(deps) {
|
|
|
15770
15977
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
15771
15978
|
return c.json({ ok: true });
|
|
15772
15979
|
});
|
|
15773
|
-
|
|
15980
|
+
app45.post("/wa-channel/ready", async (c) => {
|
|
15774
15981
|
const body = await c.req.json().catch(() => null);
|
|
15775
15982
|
const senderId = body?.senderId;
|
|
15776
15983
|
if (typeof senderId !== "string") {
|
|
@@ -15779,7 +15986,7 @@ function createWaChannelRoutes(deps) {
|
|
|
15779
15986
|
deps.onReady?.(senderId);
|
|
15780
15987
|
return c.json({ ok: true });
|
|
15781
15988
|
});
|
|
15782
|
-
|
|
15989
|
+
app45.post("/wa-channel/received", async (c) => {
|
|
15783
15990
|
const body = await c.req.json().catch(() => null);
|
|
15784
15991
|
const senderId = body?.senderId;
|
|
15785
15992
|
const waMessageId = body?.waMessageId;
|
|
@@ -15789,7 +15996,7 @@ function createWaChannelRoutes(deps) {
|
|
|
15789
15996
|
deps.onReceived?.(senderId, waMessageId);
|
|
15790
15997
|
return c.json({ ok: true });
|
|
15791
15998
|
});
|
|
15792
|
-
return
|
|
15999
|
+
return app45;
|
|
15793
16000
|
}
|
|
15794
16001
|
|
|
15795
16002
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -15850,13 +16057,22 @@ var WaGateway = class {
|
|
|
15850
16057
|
const bytes = Buffer.byteLength(input.text, "utf8");
|
|
15851
16058
|
const hadSubscriber = this.hub.hasSubscriber(input.senderId);
|
|
15852
16059
|
const willDeliverNow = this.hub.isReady(input.senderId);
|
|
16060
|
+
const hasFileMedia = !!input.mediaPath && input.mediaType !== "audio";
|
|
16061
|
+
const mediaField = hasFileMedia ? `media=${input.mediaType} mediaPath=${input.mediaPath}` : input.mediaType === "audio" ? "media=audio mediaPath=transcribed" : "media=none";
|
|
15853
16062
|
this.replies.set(input.senderId, input.reply);
|
|
15854
16063
|
this.hub.deliver(
|
|
15855
|
-
{
|
|
16064
|
+
{
|
|
16065
|
+
senderId: input.senderId,
|
|
16066
|
+
text: input.text,
|
|
16067
|
+
waMessageId: `wa-${++this.seq}`,
|
|
16068
|
+
mediaPath: input.mediaPath,
|
|
16069
|
+
mediaType: input.mediaType,
|
|
16070
|
+
mediaMimetype: input.mediaMimetype
|
|
16071
|
+
},
|
|
15856
16072
|
Date.now()
|
|
15857
16073
|
);
|
|
15858
16074
|
console.error(
|
|
15859
|
-
`[whatsapp-native] op=inbound senderId=${input.senderId} accountId=${input.accountId} bytes=${bytes} delivery=${willDeliverNow ? "immediate" : "queued"}`
|
|
16075
|
+
`[whatsapp-native] op=inbound senderId=${input.senderId} accountId=${input.accountId} bytes=${bytes} ${mediaField} delivery=${willDeliverNow ? "immediate" : "queued"}`
|
|
15860
16076
|
);
|
|
15861
16077
|
if (!hadSubscriber && !this.spawning.has(input.senderId)) {
|
|
15862
16078
|
this.spawning.add(input.senderId);
|
|
@@ -15975,8 +16191,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
15975
16191
|
|
|
15976
16192
|
// ../lib/entitlement/src/index.ts
|
|
15977
16193
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
15978
|
-
import { existsSync as existsSync23, readFileSync as
|
|
15979
|
-
import { resolve as
|
|
16194
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
|
|
16195
|
+
import { resolve as resolve26 } from "path";
|
|
15980
16196
|
|
|
15981
16197
|
// ../lib/entitlement/src/canonicalize.ts
|
|
15982
16198
|
function canonicalize(value) {
|
|
@@ -16011,7 +16227,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
16011
16227
|
var GRACE_DAYS = 7;
|
|
16012
16228
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
16013
16229
|
function pubkeyPath(brand) {
|
|
16014
|
-
return
|
|
16230
|
+
return resolve26(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
16015
16231
|
}
|
|
16016
16232
|
var memo = null;
|
|
16017
16233
|
function memoKey(mtimeMs, account) {
|
|
@@ -16023,11 +16239,11 @@ function resolveEntitlement(brand, account) {
|
|
|
16023
16239
|
if (brand.commercialMode !== true) {
|
|
16024
16240
|
return logResolved(implicitTrust(account), null);
|
|
16025
16241
|
}
|
|
16026
|
-
const entitlementPath =
|
|
16242
|
+
const entitlementPath = resolve26(brand.configDir, "entitlement.json");
|
|
16027
16243
|
if (!existsSync23(entitlementPath)) {
|
|
16028
16244
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
16029
16245
|
}
|
|
16030
|
-
const stat7 =
|
|
16246
|
+
const stat7 = statSync10(entitlementPath);
|
|
16031
16247
|
const key = memoKey(stat7.mtimeMs, account);
|
|
16032
16248
|
if (memo && memo.key === key) {
|
|
16033
16249
|
return memo.result;
|
|
@@ -16039,7 +16255,7 @@ function resolveEntitlement(brand, account) {
|
|
|
16039
16255
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
16040
16256
|
let pubkeyPem;
|
|
16041
16257
|
try {
|
|
16042
|
-
pubkeyPem =
|
|
16258
|
+
pubkeyPem = readFileSync23(pubkeyPath(brand), "utf-8");
|
|
16043
16259
|
} catch (err) {
|
|
16044
16260
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
16045
16261
|
reason: "pubkey-missing"
|
|
@@ -16053,7 +16269,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
16053
16269
|
}
|
|
16054
16270
|
let envelope;
|
|
16055
16271
|
try {
|
|
16056
|
-
envelope = JSON.parse(
|
|
16272
|
+
envelope = JSON.parse(readFileSync23(entitlementPath, "utf-8"));
|
|
16057
16273
|
} catch {
|
|
16058
16274
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
16059
16275
|
}
|
|
@@ -16214,14 +16430,14 @@ function clientFrom(c) {
|
|
|
16214
16430
|
);
|
|
16215
16431
|
}
|
|
16216
16432
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
16217
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
16433
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join19(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
16218
16434
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
16219
16435
|
if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
|
|
16220
16436
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
16221
16437
|
}
|
|
16222
16438
|
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
16223
16439
|
try {
|
|
16224
|
-
const parsed = JSON.parse(
|
|
16440
|
+
const parsed = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
|
|
16225
16441
|
BRAND = { ...BRAND, ...parsed };
|
|
16226
16442
|
} catch (err) {
|
|
16227
16443
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -16240,11 +16456,11 @@ var brandLoginOpts = {
|
|
|
16240
16456
|
bodyFont: BRAND.defaultFonts?.body,
|
|
16241
16457
|
logoContainsName: !!BRAND.logoContainsName
|
|
16242
16458
|
};
|
|
16243
|
-
var ALIAS_DOMAINS_PATH =
|
|
16459
|
+
var ALIAS_DOMAINS_PATH = join19(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
16244
16460
|
function loadAliasDomains() {
|
|
16245
16461
|
try {
|
|
16246
16462
|
if (!existsSync24(ALIAS_DOMAINS_PATH)) return null;
|
|
16247
|
-
const parsed = JSON.parse(
|
|
16463
|
+
const parsed = JSON.parse(readFileSync24(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
16248
16464
|
if (!Array.isArray(parsed)) {
|
|
16249
16465
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
16250
16466
|
return null;
|
|
@@ -16268,10 +16484,10 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
16268
16484
|
function isPublicHost(host) {
|
|
16269
16485
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
16270
16486
|
}
|
|
16271
|
-
var
|
|
16487
|
+
var app44 = new Hono();
|
|
16272
16488
|
var waGateway = new WaGateway({
|
|
16273
16489
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
16274
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
16490
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
16275
16491
|
ensureChannelSession: async ({ accountId, senderId, gatewayUrl, serverPath }) => {
|
|
16276
16492
|
const userId = resolveAdminUserId({ accountId, senderPhone: senderId }) ?? void 0;
|
|
16277
16493
|
console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
|
|
@@ -16286,10 +16502,10 @@ var waGateway = new WaGateway({
|
|
|
16286
16502
|
}
|
|
16287
16503
|
}
|
|
16288
16504
|
});
|
|
16289
|
-
|
|
16505
|
+
app44.route("/", waGateway.routes());
|
|
16290
16506
|
waGateway.startSweeper();
|
|
16291
|
-
|
|
16292
|
-
|
|
16507
|
+
app44.use("*", clientIpMiddleware);
|
|
16508
|
+
app44.use("*", async (c, next) => {
|
|
16293
16509
|
await next();
|
|
16294
16510
|
c.header("X-Content-Type-Options", "nosniff");
|
|
16295
16511
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -16299,7 +16515,7 @@ app43.use("*", async (c, next) => {
|
|
|
16299
16515
|
);
|
|
16300
16516
|
});
|
|
16301
16517
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
16302
|
-
|
|
16518
|
+
app44.use("*", async (c, next) => {
|
|
16303
16519
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
16304
16520
|
await next();
|
|
16305
16521
|
return;
|
|
@@ -16317,7 +16533,7 @@ app43.use("*", async (c, next) => {
|
|
|
16317
16533
|
});
|
|
16318
16534
|
}
|
|
16319
16535
|
});
|
|
16320
|
-
|
|
16536
|
+
app44.use("*", async (c, next) => {
|
|
16321
16537
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16322
16538
|
if (!isPublicHost(host)) {
|
|
16323
16539
|
await next();
|
|
@@ -16348,7 +16564,7 @@ function resolveRemoteAuthOpts() {
|
|
|
16348
16564
|
return brandLoginOpts;
|
|
16349
16565
|
}
|
|
16350
16566
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
16351
|
-
|
|
16567
|
+
app44.post("/__remote-auth/login", async (c) => {
|
|
16352
16568
|
const client = clientFrom(c);
|
|
16353
16569
|
const clientIp = client.ip || "unknown";
|
|
16354
16570
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -16393,7 +16609,7 @@ app43.post("/__remote-auth/login", async (c) => {
|
|
|
16393
16609
|
}
|
|
16394
16610
|
});
|
|
16395
16611
|
});
|
|
16396
|
-
|
|
16612
|
+
app44.get("/__remote-auth/logout", (c) => {
|
|
16397
16613
|
const client = clientFrom(c);
|
|
16398
16614
|
const clientIp = client.ip || "unknown";
|
|
16399
16615
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -16406,7 +16622,7 @@ app43.get("/__remote-auth/logout", (c) => {
|
|
|
16406
16622
|
}
|
|
16407
16623
|
});
|
|
16408
16624
|
});
|
|
16409
|
-
|
|
16625
|
+
app44.post("/__remote-auth/change-password", async (c) => {
|
|
16410
16626
|
const client = clientFrom(c);
|
|
16411
16627
|
const clientIp = client.ip || "unknown";
|
|
16412
16628
|
const rateLimited = checkRateLimit(client);
|
|
@@ -16457,13 +16673,13 @@ app43.post("/__remote-auth/change-password", async (c) => {
|
|
|
16457
16673
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
16458
16674
|
}
|
|
16459
16675
|
});
|
|
16460
|
-
|
|
16676
|
+
app44.get("/__remote-auth/setup", (c) => {
|
|
16461
16677
|
if (isRemoteAuthConfigured()) {
|
|
16462
16678
|
return c.redirect("/");
|
|
16463
16679
|
}
|
|
16464
16680
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
16465
16681
|
});
|
|
16466
|
-
|
|
16682
|
+
app44.post("/__remote-auth/set-initial-password", async (c) => {
|
|
16467
16683
|
if (isRemoteAuthConfigured()) {
|
|
16468
16684
|
return c.redirect("/");
|
|
16469
16685
|
}
|
|
@@ -16501,10 +16717,10 @@ app43.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
16501
16717
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
16502
16718
|
}
|
|
16503
16719
|
});
|
|
16504
|
-
|
|
16720
|
+
app44.get("/api/remote-auth/status", (c) => {
|
|
16505
16721
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
16506
16722
|
});
|
|
16507
|
-
|
|
16723
|
+
app44.post("/api/remote-auth/set-password", async (c) => {
|
|
16508
16724
|
let body;
|
|
16509
16725
|
try {
|
|
16510
16726
|
body = await c.req.json();
|
|
@@ -16535,9 +16751,9 @@ app43.post("/api/remote-auth/set-password", async (c) => {
|
|
|
16535
16751
|
return c.json({ error: "Failed to save password" }, 500);
|
|
16536
16752
|
}
|
|
16537
16753
|
});
|
|
16538
|
-
|
|
16754
|
+
app44.route("/api/_client-error", client_error_default);
|
|
16539
16755
|
console.log("[client-error-route] mounted");
|
|
16540
|
-
|
|
16756
|
+
app44.use("*", async (c, next) => {
|
|
16541
16757
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16542
16758
|
const path2 = c.req.path;
|
|
16543
16759
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -16570,13 +16786,14 @@ app43.use("*", async (c, next) => {
|
|
|
16570
16786
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
16571
16787
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
16572
16788
|
});
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16789
|
+
app44.route("/api/health", health_default);
|
|
16790
|
+
app44.route("/api/chat", chat_default);
|
|
16791
|
+
app44.route("/api/whatsapp", whatsapp_default);
|
|
16792
|
+
app44.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
16793
|
+
app44.route("/api/onboarding", onboarding_default);
|
|
16794
|
+
app44.route("/api/admin", admin_default);
|
|
16795
|
+
app44.route("/api/access", access_default);
|
|
16796
|
+
app44.route("/api/session", session_default2);
|
|
16580
16797
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
16581
16798
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
16582
16799
|
var IMAGE_MIME = {
|
|
@@ -16588,7 +16805,7 @@ var IMAGE_MIME = {
|
|
|
16588
16805
|
".svg": "image/svg+xml",
|
|
16589
16806
|
".ico": "image/x-icon"
|
|
16590
16807
|
};
|
|
16591
|
-
|
|
16808
|
+
app44.get("/agent-assets/:slug/:filename", (c) => {
|
|
16592
16809
|
const slug = c.req.param("slug");
|
|
16593
16810
|
const filename = c.req.param("filename");
|
|
16594
16811
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -16604,8 +16821,8 @@ app43.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
16604
16821
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
16605
16822
|
return c.text("Not found", 404);
|
|
16606
16823
|
}
|
|
16607
|
-
const filePath =
|
|
16608
|
-
const expectedDir =
|
|
16824
|
+
const filePath = resolve27(account.accountDir, "agents", slug, "assets", filename);
|
|
16825
|
+
const expectedDir = resolve27(account.accountDir, "agents", slug, "assets");
|
|
16609
16826
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
16610
16827
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
16611
16828
|
return c.text("Forbidden", 403);
|
|
@@ -16617,13 +16834,13 @@ app43.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
16617
16834
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
16618
16835
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
16619
16836
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
16620
|
-
const body =
|
|
16837
|
+
const body = readFileSync24(filePath);
|
|
16621
16838
|
return c.body(body, 200, {
|
|
16622
16839
|
"Content-Type": contentType,
|
|
16623
16840
|
"Cache-Control": "public, max-age=3600"
|
|
16624
16841
|
});
|
|
16625
16842
|
});
|
|
16626
|
-
|
|
16843
|
+
app44.get("/generated/:filename", (c) => {
|
|
16627
16844
|
const filename = c.req.param("filename");
|
|
16628
16845
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
16629
16846
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -16634,8 +16851,8 @@ app43.get("/generated/:filename", (c) => {
|
|
|
16634
16851
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
16635
16852
|
return c.text("Not found", 404);
|
|
16636
16853
|
}
|
|
16637
|
-
const filePath =
|
|
16638
|
-
const expectedDir =
|
|
16854
|
+
const filePath = resolve27(account.accountDir, "generated", filename);
|
|
16855
|
+
const expectedDir = resolve27(account.accountDir, "generated");
|
|
16639
16856
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
16640
16857
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
16641
16858
|
return c.text("Forbidden", 403);
|
|
@@ -16647,22 +16864,22 @@ app43.get("/generated/:filename", (c) => {
|
|
|
16647
16864
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
16648
16865
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
16649
16866
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
16650
|
-
const body =
|
|
16867
|
+
const body = readFileSync24(filePath);
|
|
16651
16868
|
return c.body(body, 200, {
|
|
16652
16869
|
"Content-Type": contentType,
|
|
16653
16870
|
"Cache-Control": "public, max-age=86400"
|
|
16654
16871
|
});
|
|
16655
16872
|
});
|
|
16656
|
-
|
|
16657
|
-
|
|
16658
|
-
|
|
16659
|
-
|
|
16873
|
+
app44.route("/sites", sites_default);
|
|
16874
|
+
app44.route("/listings", listings_default);
|
|
16875
|
+
app44.route("/v", visitor_event_default);
|
|
16876
|
+
app44.route("/v", visitor_consent_default);
|
|
16660
16877
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
16661
16878
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
16662
16879
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
16663
16880
|
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
16664
16881
|
try {
|
|
16665
|
-
const fullBrand = JSON.parse(
|
|
16882
|
+
const fullBrand = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
|
|
16666
16883
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
16667
16884
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
16668
16885
|
} catch {
|
|
@@ -16679,9 +16896,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
16679
16896
|
function readInstalledVersion() {
|
|
16680
16897
|
try {
|
|
16681
16898
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
16682
|
-
const versionFile =
|
|
16899
|
+
const versionFile = join19(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
16683
16900
|
if (!existsSync24(versionFile)) return "unknown";
|
|
16684
|
-
const content =
|
|
16901
|
+
const content = readFileSync24(versionFile, "utf-8").trim();
|
|
16685
16902
|
return content || "unknown";
|
|
16686
16903
|
} catch {
|
|
16687
16904
|
return "unknown";
|
|
@@ -16722,7 +16939,7 @@ var clientErrorReporterScript = `<script>
|
|
|
16722
16939
|
function cachedHtml(file) {
|
|
16723
16940
|
let html = htmlCache.get(file);
|
|
16724
16941
|
if (!html) {
|
|
16725
|
-
html =
|
|
16942
|
+
html = readFileSync24(resolve27(process.cwd(), "public", file), "utf-8");
|
|
16726
16943
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
16727
16944
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
16728
16945
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -16738,13 +16955,13 @@ ${clientErrorReporterScript}
|
|
|
16738
16955
|
}
|
|
16739
16956
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
16740
16957
|
function loadBrandingCache(agentSlug) {
|
|
16741
|
-
const configDir2 =
|
|
16958
|
+
const configDir2 = join19(homedir2(), BRAND.configDir);
|
|
16742
16959
|
try {
|
|
16743
16960
|
const accountId = getDefaultAccountId();
|
|
16744
16961
|
if (!accountId) return null;
|
|
16745
|
-
const cachePath =
|
|
16962
|
+
const cachePath = join19(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
16746
16963
|
if (!existsSync24(cachePath)) return null;
|
|
16747
|
-
return JSON.parse(
|
|
16964
|
+
return JSON.parse(readFileSync24(cachePath, "utf-8"));
|
|
16748
16965
|
} catch {
|
|
16749
16966
|
return null;
|
|
16750
16967
|
}
|
|
@@ -16787,7 +17004,7 @@ function escapeHtml(s) {
|
|
|
16787
17004
|
function agentUnavailableHtml() {
|
|
16788
17005
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
16789
17006
|
}
|
|
16790
|
-
|
|
17007
|
+
app44.get("/", (c) => {
|
|
16791
17008
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16792
17009
|
if (isPublicHost(host)) {
|
|
16793
17010
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -16803,12 +17020,12 @@ app43.get("/", (c) => {
|
|
|
16803
17020
|
}
|
|
16804
17021
|
return c.html(cachedHtml("index.html"));
|
|
16805
17022
|
});
|
|
16806
|
-
|
|
17023
|
+
app44.get("/public", (c) => {
|
|
16807
17024
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16808
17025
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16809
17026
|
return c.html(cachedHtml("public.html"));
|
|
16810
17027
|
});
|
|
16811
|
-
|
|
17028
|
+
app44.get("/chat", (c) => {
|
|
16812
17029
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16813
17030
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16814
17031
|
return c.html(cachedHtml("public.html"));
|
|
@@ -16827,12 +17044,12 @@ async function logViewerFetch(c, next) {
|
|
|
16827
17044
|
duration_ms: Date.now() - start
|
|
16828
17045
|
});
|
|
16829
17046
|
}
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
17047
|
+
app44.use("/vnc-viewer.html", logViewerFetch);
|
|
17048
|
+
app44.use("/vnc-popout.html", logViewerFetch);
|
|
17049
|
+
app44.get("/vnc-popout.html", (c) => {
|
|
16833
17050
|
let html = htmlCache.get("vnc-popout.html");
|
|
16834
17051
|
if (!html) {
|
|
16835
|
-
html =
|
|
17052
|
+
html = readFileSync24(resolve27(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
16836
17053
|
const name = escapeHtml(BRAND.productName);
|
|
16837
17054
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
16838
17055
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -16842,7 +17059,7 @@ app43.get("/vnc-popout.html", (c) => {
|
|
|
16842
17059
|
}
|
|
16843
17060
|
return c.html(html);
|
|
16844
17061
|
});
|
|
16845
|
-
|
|
17062
|
+
app44.post("/api/vnc/client-event", async (c) => {
|
|
16846
17063
|
let body;
|
|
16847
17064
|
try {
|
|
16848
17065
|
body = await c.req.json();
|
|
@@ -16863,30 +17080,30 @@ app43.post("/api/vnc/client-event", async (c) => {
|
|
|
16863
17080
|
});
|
|
16864
17081
|
return c.json({ ok: true });
|
|
16865
17082
|
});
|
|
16866
|
-
|
|
17083
|
+
app44.get("/g/:slug", (c) => {
|
|
16867
17084
|
return c.html(brandedPublicHtml());
|
|
16868
17085
|
});
|
|
16869
|
-
|
|
17086
|
+
app44.get("/graph", (c) => {
|
|
16870
17087
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16871
17088
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16872
17089
|
return c.html(cachedHtml("graph.html"));
|
|
16873
17090
|
});
|
|
16874
|
-
|
|
17091
|
+
app44.get("/sessions", (c) => {
|
|
16875
17092
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16876
17093
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16877
17094
|
return c.html(cachedHtml("sessions.html"));
|
|
16878
17095
|
});
|
|
16879
|
-
|
|
17096
|
+
app44.get("/data", (c) => {
|
|
16880
17097
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16881
17098
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16882
17099
|
return c.html(cachedHtml("data.html"));
|
|
16883
17100
|
});
|
|
16884
|
-
|
|
17101
|
+
app44.get("/browser", (c) => {
|
|
16885
17102
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16886
17103
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
16887
17104
|
return c.html(cachedHtml("browser.html"));
|
|
16888
17105
|
});
|
|
16889
|
-
|
|
17106
|
+
app44.get("/:slug", async (c, next) => {
|
|
16890
17107
|
const slug = c.req.param("slug");
|
|
16891
17108
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
16892
17109
|
const account = resolveAccount();
|
|
@@ -16901,13 +17118,13 @@ app43.get("/:slug", async (c, next) => {
|
|
|
16901
17118
|
await next();
|
|
16902
17119
|
});
|
|
16903
17120
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
16904
|
-
|
|
17121
|
+
app44.get("/favicon.ico", (c) => {
|
|
16905
17122
|
c.header("Cache-Control", "public, max-age=300");
|
|
16906
17123
|
return c.redirect(brandFaviconPath, 302);
|
|
16907
17124
|
});
|
|
16908
17125
|
}
|
|
16909
|
-
|
|
16910
|
-
|
|
17126
|
+
app44.use("/*", serveStatic({ root: "./public" }));
|
|
17127
|
+
app44.all("*", (c) => {
|
|
16911
17128
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
16912
17129
|
const path2 = c.req.path;
|
|
16913
17130
|
if (isPublicHost(host)) {
|
|
@@ -16921,7 +17138,7 @@ app43.all("*", (c) => {
|
|
|
16921
17138
|
});
|
|
16922
17139
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
16923
17140
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
16924
|
-
var httpServer = serve({ fetch:
|
|
17141
|
+
var httpServer = serve({ fetch: app44.fetch, port, hostname });
|
|
16925
17142
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
16926
17143
|
startAuthHealthHeartbeat();
|
|
16927
17144
|
{
|
|
@@ -16943,6 +17160,7 @@ var SUBAPP_MANIFEST = [
|
|
|
16943
17160
|
{ prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
|
|
16944
17161
|
{ prefix: "/api/chat", file: "server/routes/chat.ts", subapp: chat_default },
|
|
16945
17162
|
{ prefix: "/api/whatsapp", file: "server/routes/whatsapp.ts", subapp: whatsapp_default },
|
|
17163
|
+
{ prefix: "/api/whatsapp-reader", file: "server/routes/whatsapp-reader.ts", subapp: whatsapp_reader_default },
|
|
16946
17164
|
{ prefix: "/api/onboarding", file: "server/routes/onboarding.ts", subapp: onboarding_default },
|
|
16947
17165
|
{ prefix: "/api/admin", file: "server/routes/admin/index.ts", subapp: admin_default },
|
|
16948
17166
|
{ prefix: "/api/access", file: "server/routes/access/index.ts", subapp: access_default },
|
|
@@ -16958,7 +17176,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
16958
17176
|
}
|
|
16959
17177
|
try {
|
|
16960
17178
|
const registered = [];
|
|
16961
|
-
for (const r of
|
|
17179
|
+
for (const r of app44.routes ?? []) {
|
|
16962
17180
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
16963
17181
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
16964
17182
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -16990,7 +17208,7 @@ async function runAdminUserReconcileTick() {
|
|
|
16990
17208
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
16991
17209
|
return;
|
|
16992
17210
|
}
|
|
16993
|
-
const usersRaw =
|
|
17211
|
+
const usersRaw = readFileSync24(USERS_FILE, "utf-8").trim();
|
|
16994
17212
|
if (!usersRaw) {
|
|
16995
17213
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
16996
17214
|
return;
|
|
@@ -17038,7 +17256,7 @@ try {
|
|
|
17038
17256
|
} catch (err) {
|
|
17039
17257
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
17040
17258
|
}
|
|
17041
|
-
var configDirForWhatsApp =
|
|
17259
|
+
var configDirForWhatsApp = basename7(MAXY_DIR) || ".maxy";
|
|
17042
17260
|
var bootAccount = resolveAccount();
|
|
17043
17261
|
var bootAccountConfig = bootAccount?.config;
|
|
17044
17262
|
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
|
|
@@ -17097,7 +17315,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
17097
17315
|
}
|
|
17098
17316
|
init({
|
|
17099
17317
|
configDir: configDirForWhatsApp,
|
|
17100
|
-
platformRoot:
|
|
17318
|
+
platformRoot: resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, "..")),
|
|
17101
17319
|
accountConfig: bootAccountConfig,
|
|
17102
17320
|
onMessage: async (msg) => {
|
|
17103
17321
|
if (msg.isOwnerMirror) {
|
|
@@ -17108,8 +17326,9 @@ init({
|
|
|
17108
17326
|
console.error(`[whatsapp:route] dropped reason=non-admin-sender senderId=${msg.senderPhone} agentType=${msg.agentType}`);
|
|
17109
17327
|
return;
|
|
17110
17328
|
}
|
|
17111
|
-
|
|
17112
|
-
|
|
17329
|
+
const hasFileMedia = !!msg.mediaPath && msg.mediaType !== "audio";
|
|
17330
|
+
if (!msg.text && !hasFileMedia) {
|
|
17331
|
+
console.error(`[whatsapp:route] dropped reason=no-text-no-media senderId=${msg.senderPhone} media=${msg.mediaType ?? "none"}`);
|
|
17113
17332
|
return;
|
|
17114
17333
|
}
|
|
17115
17334
|
try {
|
|
@@ -17119,7 +17338,10 @@ init({
|
|
|
17119
17338
|
accountId: msg.accountId,
|
|
17120
17339
|
senderId: msg.senderPhone,
|
|
17121
17340
|
text: msg.text,
|
|
17122
|
-
reply: msg.reply
|
|
17341
|
+
reply: msg.reply,
|
|
17342
|
+
mediaPath: msg.mediaPath,
|
|
17343
|
+
mediaType: msg.mediaType,
|
|
17344
|
+
mediaMimetype: msg.mediaMimetype
|
|
17123
17345
|
});
|
|
17124
17346
|
} catch (err) {
|
|
17125
17347
|
console.error(
|