@rubytech/create-sitedesk-code 0.1.508 → 0.1.510
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +53 -0
- package/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-1902-account-owned-entry-declarations.md +555 -0
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-1926-portal-push-concurrency-guard.md +482 -0
- package/payload/platform/docs/superpowers/plans/2026-07-26-task-2023-sidebar-sessions-async-reads.md +394 -0
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-1902-account-owned-entry-declarations-design.md +232 -0
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-1926-portal-push-concurrency-guard-design.md +200 -0
- package/payload/platform/docs/superpowers/specs/2026-07-26-task-2014-ui-suite-nondeterminism-design.md +169 -0
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +12 -7
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
- package/payload/platform/plugins/business-assistant/PLUGIN.md +1 -0
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -0
- package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +68 -28
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +271 -29
- package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +21 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +5 -4
- package/payload/platform/plugins/docs/references/admin-ui.md +10 -5
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -0
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +112 -4
- package/payload/platform/scripts/__tests__/check-brand-cache.test.sh +231 -0
- package/payload/platform/scripts/check-brand-cache.sh +138 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +61 -32
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +17 -30
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +50 -4
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +58 -15
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/server/maxy-edge.js +26 -11
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/AdminLoginScreens-CWMpccrR.css.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-CWMpccrR.css.gz +0 -0
- package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-HeELCCjJ.js → AdminShell-BMPEWNZk.js} +1 -1
- package/payload/server/public/assets/AdminShell-BMPEWNZk.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BMPEWNZk.js.gz +0 -0
- package/payload/server/public/assets/_baseFor-Be3EKK3K.js.br +0 -0
- package/payload/server/public/assets/_baseFor-Be3EKK3K.js.gz +0 -0
- package/payload/server/public/assets/{activity-BEIDAxDA.js → activity-ByWYF5dC.js} +1 -1
- package/payload/server/public/assets/activity-ByWYF5dC.js.br +0 -0
- package/payload/server/public/assets/activity-ByWYF5dC.js.gz +0 -0
- package/payload/server/public/assets/admin-DGr1HuPg.js +1 -0
- package/payload/server/public/assets/admin-DGr1HuPg.js.br +0 -0
- package/payload/server/public/assets/admin-DGr1HuPg.js.gz +0 -0
- package/payload/server/public/assets/agents-C0rTfrYd.js +1 -0
- package/payload/server/public/assets/agents-C0rTfrYd.js.br +0 -0
- package/payload/server/public/assets/agents-C0rTfrYd.js.gz +0 -0
- package/payload/server/public/assets/arc-DaI5MLTq.js.br +0 -0
- package/payload/server/public/assets/arc-DaI5MLTq.js.gz +0 -0
- package/payload/server/public/assets/architecture-YZFGNWBL-DWZIX5aV.js.br +0 -0
- package/payload/server/public/assets/architectureDiagram-Q4EWVU46-CBGVUEN9.js.br +0 -0
- package/payload/server/public/assets/architectureDiagram-Q4EWVU46-CBGVUEN9.js.gz +0 -0
- package/payload/server/public/assets/array-X0JlPOfd.js.br +0 -0
- package/payload/server/public/assets/blockDiagram-DXYQGD6D-DS6dS4GZ.js.br +0 -0
- package/payload/server/public/assets/blockDiagram-DXYQGD6D-DS6dS4GZ.js.gz +0 -0
- package/payload/server/public/assets/{browser-GkVTGqlb.js → browser-4tTaem8N.js} +1 -1
- package/payload/server/public/assets/browser-4tTaem8N.js.br +0 -0
- package/payload/server/public/assets/browser-4tTaem8N.js.gz +0 -0
- package/payload/server/public/assets/c4Diagram-AHTNJAMY-hBSBUZPt.js.br +0 -0
- package/payload/server/public/assets/c4Diagram-AHTNJAMY-hBSBUZPt.js.gz +0 -0
- package/payload/server/public/assets/{calendar-CSqJeFEg.js → calendar-BEjnkKG1.js} +1 -1
- package/payload/server/public/assets/calendar-BEjnkKG1.js.br +0 -0
- package/payload/server/public/assets/calendar-BEjnkKG1.js.gz +0 -0
- package/payload/server/public/assets/channel-BEokjAeE.js.br +0 -0
- package/payload/server/public/assets/chat-DBgzjDIE.js +1 -0
- package/payload/server/public/assets/chat-DBgzjDIE.js.br +0 -0
- package/payload/server/public/assets/chat-DBgzjDIE.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DqYv3oFh.js +1 -0
- package/payload/server/public/assets/chevron-right-CQfPGsFb.js +1 -0
- package/payload/server/public/assets/chevron-right-CQfPGsFb.js.br +0 -0
- package/payload/server/public/assets/chunk-2KRD3SAO-B6koUoB7.js.br +0 -0
- package/payload/server/public/assets/chunk-2KRD3SAO-B6koUoB7.js.gz +0 -0
- package/payload/server/public/assets/chunk-336JU56O-BF6BRh8u.js.br +0 -0
- package/payload/server/public/assets/chunk-336JU56O-BF6BRh8u.js.gz +0 -0
- package/payload/server/public/assets/chunk-426QAEUC-pbQ4PWBU.js.br +0 -0
- package/payload/server/public/assets/chunk-426QAEUC-pbQ4PWBU.js.gz +0 -0
- package/payload/server/public/assets/chunk-4BX2VUAB-7sO95xR2.js.br +0 -0
- package/payload/server/public/assets/chunk-4BX2VUAB-7sO95xR2.js.gz +0 -0
- package/payload/server/public/assets/chunk-4TB4RGXK-GCTndJYx.js.br +0 -0
- package/payload/server/public/assets/chunk-4TB4RGXK-GCTndJYx.js.gz +0 -0
- package/payload/server/public/assets/chunk-55IACEB6-ggIJf_TC.js.br +0 -0
- package/payload/server/public/assets/chunk-55IACEB6-ggIJf_TC.js.gz +0 -0
- package/payload/server/public/assets/chunk-5FUZZQ4R-DeGmkimt.js.br +0 -0
- package/payload/server/public/assets/chunk-5FUZZQ4R-DeGmkimt.js.gz +0 -0
- package/payload/server/public/assets/chunk-5PVQY5BW-aFIQKk_U.js.br +0 -0
- package/payload/server/public/assets/chunk-5PVQY5BW-aFIQKk_U.js.gz +0 -0
- package/payload/server/public/assets/chunk-67CJDMHE-LS8rUbii.js.br +2 -0
- package/payload/server/public/assets/chunk-67CJDMHE-LS8rUbii.js.gz +0 -0
- package/payload/server/public/assets/chunk-7N4EOEYR-JKOVngS0.js.br +2 -0
- package/payload/server/public/assets/chunk-7N4EOEYR-JKOVngS0.js.gz +0 -0
- package/payload/server/public/assets/chunk-AA7GKIK3-CoXnTVK6.js.br +0 -0
- package/payload/server/public/assets/chunk-AA7GKIK3-CoXnTVK6.js.gz +0 -0
- package/payload/server/public/assets/chunk-BSJP7CBP-CcsqObFg.js.br +0 -0
- package/payload/server/public/assets/chunk-BSJP7CBP-CcsqObFg.js.gz +0 -0
- package/payload/server/public/assets/chunk-CIAEETIT-CpsybR7q.js.br +0 -0
- package/payload/server/public/assets/chunk-CIAEETIT-CpsybR7q.js.gz +0 -0
- package/payload/server/public/assets/chunk-CltuBf4Z.js.br +0 -0
- package/payload/server/public/assets/chunk-CltuBf4Z.js.gz +0 -0
- package/payload/server/public/assets/chunk-EDXVE4YY-BZ2I9PSq.js.br +0 -0
- package/payload/server/public/assets/chunk-EDXVE4YY-BZ2I9PSq.js.gz +0 -0
- package/payload/server/public/assets/chunk-ENJZ2VHE-DbTwt6OZ.js.br +0 -0
- package/payload/server/public/assets/chunk-ENJZ2VHE-DbTwt6OZ.js.gz +0 -0
- package/payload/server/public/assets/chunk-FMBD7UC4-D27VnSCa.js.br +0 -0
- package/payload/server/public/assets/chunk-FMBD7UC4-D27VnSCa.js.gz +0 -0
- package/payload/server/public/assets/chunk-FOC6F5B3-C0tU2UFl.js.br +0 -0
- package/payload/server/public/assets/chunk-FOC6F5B3-C0tU2UFl.js.gz +0 -0
- package/payload/server/public/assets/chunk-ICPOFSXX-UPPu2OIq.js.br +0 -0
- package/payload/server/public/assets/chunk-ICPOFSXX-UPPu2OIq.js.gz +0 -0
- package/payload/server/public/assets/chunk-K5T4RW27-DIKxqyYw.js.br +0 -0
- package/payload/server/public/assets/chunk-K5T4RW27-DIKxqyYw.js.gz +0 -0
- package/payload/server/public/assets/chunk-KGLVRYIC-CiL4YVLo.js.br +0 -0
- package/payload/server/public/assets/chunk-KGLVRYIC-CiL4YVLo.js.gz +0 -0
- package/payload/server/public/assets/chunk-LIHQZDEY-ejKezVlD.js.br +0 -0
- package/payload/server/public/assets/chunk-LIHQZDEY-ejKezVlD.js.gz +0 -0
- package/payload/server/public/assets/chunk-ORNJ4GCN-Cc0vqc-D.js.br +0 -0
- package/payload/server/public/assets/chunk-ORNJ4GCN-Cc0vqc-D.js.gz +0 -0
- package/payload/server/public/assets/chunk-OYMX7WX6-Drxn1qG0.js.br +0 -0
- package/payload/server/public/assets/chunk-OYMX7WX6-Drxn1qG0.js.gz +0 -0
- package/payload/server/public/assets/chunk-QZHKN3VN-Dhlh7Pkk.js.br +0 -0
- package/payload/server/public/assets/chunk-QZHKN3VN-Dhlh7Pkk.js.gz +0 -0
- package/payload/server/public/assets/chunk-U2HBQHQK-DnbQIkRP.js.br +0 -0
- package/payload/server/public/assets/chunk-U2HBQHQK-DnbQIkRP.js.gz +0 -0
- package/payload/server/public/assets/chunk-X2U36JSP-CauTSVWg.js.br +0 -0
- package/payload/server/public/assets/chunk-X2U36JSP-CauTSVWg.js.gz +0 -0
- package/payload/server/public/assets/chunk-XPW4576I-DZqqB9Zi.js.br +0 -0
- package/payload/server/public/assets/chunk-XPW4576I-DZqqB9Zi.js.gz +0 -0
- package/payload/server/public/assets/chunk-YZCP3GAM-BGHo4Li-.js.br +0 -0
- package/payload/server/public/assets/chunk-YZCP3GAM-BGHo4Li-.js.gz +0 -0
- package/payload/server/public/assets/chunk-ZZ45TVLE-DWGJKPd7.js.br +0 -0
- package/payload/server/public/assets/chunk-ZZ45TVLE-DWGJKPd7.js.gz +0 -0
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-D2z_ZV1x.js.br +0 -0
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-D2z_ZV1x.js.gz +0 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BJwJoNEK.js.br +0 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BJwJoNEK.js.gz +0 -0
- package/payload/server/public/assets/clock-Dn6FHB51.js +1 -0
- package/payload/server/public/assets/clock-Dn6FHB51.js.br +0 -0
- package/payload/server/public/assets/clock-Dn6FHB51.js.gz +0 -0
- package/payload/server/public/assets/clone-Bn7XXVhr.js.br +0 -0
- package/payload/server/public/assets/cose-bilkent-S5V4N54A-D-95BzXL.js.br +0 -0
- package/payload/server/public/assets/cose-bilkent-S5V4N54A-D-95BzXL.js.gz +0 -0
- package/payload/server/public/assets/cytoscape.esm-CI2IWMLB.js.br +0 -0
- package/payload/server/public/assets/cytoscape.esm-CI2IWMLB.js.gz +0 -0
- package/payload/server/public/assets/dagre-BZYNBHvT.js.br +0 -0
- package/payload/server/public/assets/dagre-BZYNBHvT.js.gz +0 -0
- package/payload/server/public/assets/dagre-KV5264BT-DyU4HQLQ.js.br +0 -0
- package/payload/server/public/assets/dagre-KV5264BT-DyU4HQLQ.js.gz +0 -0
- package/payload/server/public/assets/data-D_e6Vdfd.js +1 -0
- package/payload/server/public/assets/data-D_e6Vdfd.js.br +0 -0
- package/payload/server/public/assets/data-D_e6Vdfd.js.gz +0 -0
- package/payload/server/public/assets/defaultLocale-B6RGN4id.js.br +0 -0
- package/payload/server/public/assets/defaultLocale-B6RGN4id.js.gz +0 -0
- package/payload/server/public/assets/diagram-5BDNPKRD-CCttJ9XA.js.br +0 -0
- package/payload/server/public/assets/diagram-5BDNPKRD-CCttJ9XA.js.gz +0 -0
- package/payload/server/public/assets/diagram-G4DWMVQ6-DvkpgSLO.js.br +0 -0
- package/payload/server/public/assets/diagram-G4DWMVQ6-DvkpgSLO.js.gz +0 -0
- package/payload/server/public/assets/diagram-MMDJMWI5-DHmW5Y9k.js.br +0 -0
- package/payload/server/public/assets/diagram-MMDJMWI5-DHmW5Y9k.js.gz +0 -0
- package/payload/server/public/assets/diagram-TYMM5635-C6T4hwzO.js.br +0 -0
- package/payload/server/public/assets/diagram-TYMM5635-C6T4hwzO.js.gz +0 -0
- package/payload/server/public/assets/dist-QvbmK1IP.js.br +0 -0
- package/payload/server/public/assets/dist-QvbmK1IP.js.gz +0 -0
- package/payload/server/public/assets/erDiagram-SMLLAGMA-5v_o7s3T.js.br +0 -0
- package/payload/server/public/assets/erDiagram-SMLLAGMA-5v_o7s3T.js.gz +0 -0
- package/payload/server/public/assets/{file-text-DiscM2pP.js → file-text-DMKw3nIk.js} +1 -1
- package/payload/server/public/assets/file-text-DMKw3nIk.js.br +0 -0
- package/payload/server/public/assets/file-text-DMKw3nIk.js.gz +0 -0
- package/payload/server/public/assets/flatten-BtIc9jX7.js.br +0 -0
- package/payload/server/public/assets/flatten-BtIc9jX7.js.gz +0 -0
- package/payload/server/public/assets/flowDiagram-DWJPFMVM-3UhCDsjt.js.br +0 -0
- package/payload/server/public/assets/flowDiagram-DWJPFMVM-3UhCDsjt.js.gz +0 -0
- package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-F2zgHIIQ.js.br +0 -0
- package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-F2zgHIIQ.js.gz +0 -0
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-C-FvNTHZ.js.br +0 -0
- package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-oQc1N3dT.js.br +0 -0
- package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-oQc1N3dT.js.gz +0 -0
- package/payload/server/public/assets/{graph-CRP5DM8C.js → graph-C3vW8lvw.js} +1 -1
- package/payload/server/public/assets/graph-C3vW8lvw.js.br +0 -0
- package/payload/server/public/assets/graph-C3vW8lvw.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-Du-6KoBE.js → graph-labels-BZgd0L6n.js} +1 -1
- package/payload/server/public/assets/graph-labels-BZgd0L6n.js.br +0 -0
- package/payload/server/public/assets/graph-labels-BZgd0L6n.js.gz +0 -0
- package/payload/server/public/assets/graphlib-DY4-AT2Q.js.br +0 -0
- package/payload/server/public/assets/graphlib-DY4-AT2Q.js.gz +0 -0
- package/payload/server/public/assets/info-OMHHGYJF-BjLPgHAC.js.br +0 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CXNKLTui.js.br +0 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CXNKLTui.js.gz +0 -0
- package/payload/server/public/assets/init-BmUWJJHz.js.br +0 -0
- package/payload/server/public/assets/init-BmUWJJHz.js.gz +0 -0
- package/payload/server/public/assets/isEmpty-Bu4fZ8Kf.js.br +0 -0
- package/payload/server/public/assets/isEmpty-Bu4fZ8Kf.js.gz +0 -0
- package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-wJhSOkuw.js.br +0 -0
- package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-wJhSOkuw.js.gz +0 -0
- package/payload/server/public/assets/journeyDiagram-VCZTEJTY-DgadC6Pz.js.br +0 -0
- package/payload/server/public/assets/journeyDiagram-VCZTEJTY-DgadC6Pz.js.gz +0 -0
- package/payload/server/public/assets/kanban-definition-6JOO6SKY-Bs4nQqXI.js.br +0 -0
- package/payload/server/public/assets/kanban-definition-6JOO6SKY-Bs4nQqXI.js.gz +0 -0
- package/payload/server/public/assets/katex-BjZuzSQn.js.br +0 -0
- package/payload/server/public/assets/katex-BjZuzSQn.js.gz +0 -0
- package/payload/server/public/assets/line-Bnmxy1hO.js.br +0 -0
- package/payload/server/public/assets/line-Bnmxy1hO.js.gz +0 -0
- package/payload/server/public/assets/linear-RvwZxFzh.js.br +0 -0
- package/payload/server/public/assets/linear-RvwZxFzh.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-D-H_uIV-.js → maximize-2-la3IBA3M.js} +1 -1
- package/payload/server/public/assets/maximize-2-la3IBA3M.js.br +0 -0
- package/payload/server/public/assets/maximize-2-la3IBA3M.js.gz +0 -0
- package/payload/server/public/assets/mermaid-parser.core-DeNV8RtA.js.br +0 -0
- package/payload/server/public/assets/mermaid-parser.core-DeNV8RtA.js.gz +0 -0
- package/payload/server/public/assets/mermaid.core-BU9IiSCP.js.br +0 -0
- package/payload/server/public/assets/mermaid.core-BU9IiSCP.js.gz +0 -0
- package/payload/server/public/assets/mindmap-definition-QFDTVHPH-D1PMUxxm.js.br +0 -0
- package/payload/server/public/assets/mindmap-definition-QFDTVHPH-D1PMUxxm.js.gz +0 -0
- package/payload/server/public/assets/{operator-D5rA76YY.js → operator-D9NgVL9_.js} +1 -1
- package/payload/server/public/assets/operator-D9NgVL9_.js.br +0 -0
- package/payload/server/public/assets/operator-D9NgVL9_.js.gz +0 -0
- package/payload/server/public/assets/ordinal-C2TEWKNu.js.br +0 -0
- package/payload/server/public/assets/ordinal-C2TEWKNu.js.gz +0 -0
- package/payload/server/public/assets/packet-4T2RLAQJ-BBAZASfb.js.br +0 -0
- package/payload/server/public/assets/{page-CHK1415C.js → page-BWFHRIAH.js} +1 -1
- package/payload/server/public/assets/page-BWFHRIAH.js.br +0 -0
- package/payload/server/public/assets/page-BWFHRIAH.js.gz +0 -0
- package/payload/server/public/assets/{page-DZE3H_n4.js → page-DC11gesX.js} +1 -1
- package/payload/server/public/assets/page-DC11gesX.js.br +0 -0
- package/payload/server/public/assets/page-DC11gesX.js.gz +0 -0
- package/payload/server/public/assets/path-CoPyR7c2.js.br +0 -0
- package/payload/server/public/assets/path-CoPyR7c2.js.gz +0 -0
- package/payload/server/public/assets/pdf-render-C257cidb.js.br +0 -0
- package/payload/server/public/assets/pdf-render-C257cidb.js.gz +0 -0
- package/payload/server/public/assets/pdf.worker.min-yatZIOMy.mjs.br +0 -0
- package/payload/server/public/assets/pdf.worker.min-yatZIOMy.mjs.gz +0 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-CCJUnMeG.js.br +0 -0
- package/payload/server/public/assets/pieDiagram-DEJITSTG-BzdNzoKA.js.br +0 -0
- package/payload/server/public/assets/pieDiagram-DEJITSTG-BzdNzoKA.js.gz +0 -0
- package/payload/server/public/assets/preload-helper-BQrMkyGX.js.br +0 -0
- package/payload/server/public/assets/preload-helper-BQrMkyGX.js.gz +0 -0
- package/payload/server/public/assets/{public-DFHXVkdD.js → public-DQbbLHQN.js} +1 -1
- package/payload/server/public/assets/public-DQbbLHQN.js.br +0 -0
- package/payload/server/public/assets/public-DQbbLHQN.js.gz +0 -0
- package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-oFr1MJRO.js.br +0 -0
- package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-oFr1MJRO.js.gz +0 -0
- package/payload/server/public/assets/radar-PYXPWWZC-BsRU8Aep.js.br +0 -0
- package/payload/server/public/assets/reduce-BGpN5lgn.js.br +0 -0
- package/payload/server/public/assets/reduce-BGpN5lgn.js.gz +0 -0
- package/payload/server/public/assets/requirementDiagram-MS252O5E-C9QBQxDh.js.br +0 -0
- package/payload/server/public/assets/requirementDiagram-MS252O5E-C9QBQxDh.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-CesEJsuO.js → rotate-ccw-OQD5si8N.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-OQD5si8N.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-OQD5si8N.js.gz +0 -0
- package/payload/server/public/assets/rough.esm-jSt7UMyi.js.br +0 -0
- package/payload/server/public/assets/rough.esm-jSt7UMyi.js.gz +0 -0
- package/payload/server/public/assets/{routines-DYMYY_r8.js → routines-asrBGZUR.js} +1 -1
- package/payload/server/public/assets/routines-asrBGZUR.js.br +0 -0
- package/payload/server/public/assets/routines-asrBGZUR.js.gz +0 -0
- package/payload/server/public/assets/sankeyDiagram-XADWPNL6-c_y3bvVv.js.br +0 -0
- package/payload/server/public/assets/sankeyDiagram-XADWPNL6-c_y3bvVv.js.gz +0 -0
- package/payload/server/public/assets/sequenceDiagram-FGHM5R23-YwlCBPHE.js.br +0 -0
- package/payload/server/public/assets/sequenceDiagram-FGHM5R23-YwlCBPHE.js.gz +0 -0
- package/payload/server/public/assets/{skills-67jtJ16D.js → skills-D4ECwoxa.js} +1 -1
- package/payload/server/public/assets/skills-D4ECwoxa.js.br +0 -0
- package/payload/server/public/assets/skills-D4ECwoxa.js.gz +0 -0
- package/payload/server/public/assets/src-C2WwTWSY.js.br +0 -0
- package/payload/server/public/assets/src-C2WwTWSY.js.gz +0 -0
- package/payload/server/public/assets/stateDiagram-FHFEXIEX-BFE3e-FM.js.br +0 -0
- package/payload/server/public/assets/stateDiagram-FHFEXIEX-BFE3e-FM.js.gz +0 -0
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CpjB4ykI.js.br +4 -0
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CpjB4ykI.js.gz +0 -0
- package/payload/server/public/assets/{tasks-D2C2a-uk.js → tasks-U3QdbUsO.js} +1 -1
- package/payload/server/public/assets/tasks-U3QdbUsO.js.br +0 -0
- package/payload/server/public/assets/tasks-U3QdbUsO.js.gz +0 -0
- package/payload/server/public/assets/{time-entry-format-BixTGQAd.js → time-entry-format-BgdTKgYr.js} +1 -1
- package/payload/server/public/assets/time-entry-format-BgdTKgYr.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-BgdTKgYr.js.gz +0 -0
- package/payload/server/public/assets/timeline-definition-GMOUNBTQ-azqhmRwZ.js.br +0 -0
- package/payload/server/public/assets/timeline-definition-GMOUNBTQ-azqhmRwZ.js.gz +0 -0
- package/payload/server/public/assets/treeView-SZITEDCU-BDzhKA6v.js.br +0 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-epHpdeWa.js.br +0 -0
- package/payload/server/public/assets/{triangle-alert-Co9RWb9q.js → triangle-alert-Ck_3VhT9.js} +1 -1
- package/payload/server/public/assets/triangle-alert-Ck_3VhT9.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-Ck_3VhT9.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-7zwf9_w4.js → useCopyFeedback-BdUwyNpa.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-BdUwyNpa.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-BdUwyNpa.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CJKjEPNN.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CJKjEPNN.js.gz +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DE4v5_Fz.css → useSubAccountSwitcher-DOWQXDT8.css} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-DOWQXDT8.css.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DOWQXDT8.css.gz +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-CZDDiwMD.js → useVoiceRecorder-ChnBrzbZ.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-ChnBrzbZ.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-ChnBrzbZ.js.gz +0 -0
- package/payload/server/public/assets/vennDiagram-DHZGUBPP-Da2RfFs8.js.br +0 -0
- package/payload/server/public/assets/vennDiagram-DHZGUBPP-Da2RfFs8.js.gz +0 -0
- package/payload/server/public/assets/wardley-RL74JXVD-DNSZCrxV.js.br +0 -0
- package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-HdrdBYES.js.br +0 -0
- package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-HdrdBYES.js.gz +0 -0
- package/payload/server/public/assets/{wrench-CjQqdj4P.js → wrench-Cpee3C3J.js} +1 -1
- package/payload/server/public/assets/wrench-Cpee3C3J.js.br +2 -0
- package/payload/server/public/assets/wrench-Cpee3C3J.js.gz +0 -0
- package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DMk6rTcQ.js.br +0 -0
- package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DMk6rTcQ.js.gz +0 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +6 -6
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +817 -715
- package/payload/server/public/assets/AdminLoginScreens-DKeCt1uf.js +0 -1
- package/payload/server/public/assets/admin-C0-WU1sf.js +0 -1
- package/payload/server/public/assets/agents-DjUvMFTj.js +0 -1
- package/payload/server/public/assets/chat-C0Ps84U5.js +0 -1
- package/payload/server/public/assets/chevron-left-DQ2uNlu9.js +0 -1
- package/payload/server/public/assets/chevron-right-C4QCiRGD.js +0 -1
- package/payload/server/public/assets/clock-BEeQ7JxX.js +0 -1
- package/payload/server/public/assets/data-CGuNfym7.js +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-Bg72hdQ8.js → useSubAccountSwitcher-CJKjEPNN.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1601,233 +1601,11 @@ var require_dist5 = __commonJS({
|
|
|
1601
1601
|
}
|
|
1602
1602
|
});
|
|
1603
1603
|
|
|
1604
|
-
// node_modules/hono/dist/utils/mime.js
|
|
1605
|
-
var getMimeType = (filename, mimes = baseMimes) => {
|
|
1606
|
-
const regexp = /\.([a-zA-Z0-9]+?)$/;
|
|
1607
|
-
const match = filename.match(regexp);
|
|
1608
|
-
if (!match) {
|
|
1609
|
-
return;
|
|
1610
|
-
}
|
|
1611
|
-
let mimeType = mimes[match[1].toLowerCase()];
|
|
1612
|
-
if (mimeType && mimeType.startsWith("text")) {
|
|
1613
|
-
mimeType += "; charset=utf-8";
|
|
1614
|
-
}
|
|
1615
|
-
return mimeType;
|
|
1616
|
-
};
|
|
1617
|
-
var _baseMimes = {
|
|
1618
|
-
aac: "audio/aac",
|
|
1619
|
-
avi: "video/x-msvideo",
|
|
1620
|
-
avif: "image/avif",
|
|
1621
|
-
av1: "video/av1",
|
|
1622
|
-
bin: "application/octet-stream",
|
|
1623
|
-
bmp: "image/bmp",
|
|
1624
|
-
css: "text/css",
|
|
1625
|
-
csv: "text/csv",
|
|
1626
|
-
eot: "application/vnd.ms-fontobject",
|
|
1627
|
-
epub: "application/epub+zip",
|
|
1628
|
-
gif: "image/gif",
|
|
1629
|
-
gz: "application/gzip",
|
|
1630
|
-
htm: "text/html",
|
|
1631
|
-
html: "text/html",
|
|
1632
|
-
ico: "image/x-icon",
|
|
1633
|
-
ics: "text/calendar",
|
|
1634
|
-
jpeg: "image/jpeg",
|
|
1635
|
-
jpg: "image/jpeg",
|
|
1636
|
-
js: "text/javascript",
|
|
1637
|
-
json: "application/json",
|
|
1638
|
-
jsonld: "application/ld+json",
|
|
1639
|
-
map: "application/json",
|
|
1640
|
-
mid: "audio/x-midi",
|
|
1641
|
-
midi: "audio/x-midi",
|
|
1642
|
-
mjs: "text/javascript",
|
|
1643
|
-
mp3: "audio/mpeg",
|
|
1644
|
-
mp4: "video/mp4",
|
|
1645
|
-
mpeg: "video/mpeg",
|
|
1646
|
-
oga: "audio/ogg",
|
|
1647
|
-
ogv: "video/ogg",
|
|
1648
|
-
ogx: "application/ogg",
|
|
1649
|
-
opus: "audio/opus",
|
|
1650
|
-
otf: "font/otf",
|
|
1651
|
-
pdf: "application/pdf",
|
|
1652
|
-
png: "image/png",
|
|
1653
|
-
rtf: "application/rtf",
|
|
1654
|
-
svg: "image/svg+xml",
|
|
1655
|
-
tif: "image/tiff",
|
|
1656
|
-
tiff: "image/tiff",
|
|
1657
|
-
ts: "video/mp2t",
|
|
1658
|
-
ttf: "font/ttf",
|
|
1659
|
-
txt: "text/plain",
|
|
1660
|
-
wasm: "application/wasm",
|
|
1661
|
-
webm: "video/webm",
|
|
1662
|
-
weba: "audio/webm",
|
|
1663
|
-
webmanifest: "application/manifest+json",
|
|
1664
|
-
webp: "image/webp",
|
|
1665
|
-
woff: "font/woff",
|
|
1666
|
-
woff2: "font/woff2",
|
|
1667
|
-
xhtml: "application/xhtml+xml",
|
|
1668
|
-
xml: "application/xml",
|
|
1669
|
-
zip: "application/zip",
|
|
1670
|
-
"3gp": "video/3gpp",
|
|
1671
|
-
"3g2": "video/3gpp2",
|
|
1672
|
-
gltf: "model/gltf+json",
|
|
1673
|
-
glb: "model/gltf-binary"
|
|
1674
|
-
};
|
|
1675
|
-
var baseMimes = _baseMimes;
|
|
1676
|
-
|
|
1677
|
-
// node_modules/@hono/node-server/dist/serve-static.mjs
|
|
1678
|
-
import { createReadStream, statSync, existsSync } from "fs";
|
|
1679
|
-
import { join } from "path";
|
|
1680
|
-
import { versions } from "process";
|
|
1681
|
-
import { Readable } from "stream";
|
|
1682
|
-
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
1683
|
-
var ENCODINGS = {
|
|
1684
|
-
br: ".br",
|
|
1685
|
-
zstd: ".zst",
|
|
1686
|
-
gzip: ".gz"
|
|
1687
|
-
};
|
|
1688
|
-
var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
|
|
1689
|
-
var pr54206Applied = () => {
|
|
1690
|
-
const [major, minor] = versions.node.split(".").map((component) => parseInt(component));
|
|
1691
|
-
return major >= 23 || major === 22 && minor >= 7 || major === 20 && minor >= 18;
|
|
1692
|
-
};
|
|
1693
|
-
var useReadableToWeb = pr54206Applied();
|
|
1694
|
-
var createStreamBody = (stream2) => {
|
|
1695
|
-
if (useReadableToWeb) {
|
|
1696
|
-
return Readable.toWeb(stream2);
|
|
1697
|
-
}
|
|
1698
|
-
const body = new ReadableStream({
|
|
1699
|
-
start(controller) {
|
|
1700
|
-
stream2.on("data", (chunk) => {
|
|
1701
|
-
controller.enqueue(chunk);
|
|
1702
|
-
});
|
|
1703
|
-
stream2.on("error", (err) => {
|
|
1704
|
-
controller.error(err);
|
|
1705
|
-
});
|
|
1706
|
-
stream2.on("end", () => {
|
|
1707
|
-
controller.close();
|
|
1708
|
-
});
|
|
1709
|
-
},
|
|
1710
|
-
cancel() {
|
|
1711
|
-
stream2.destroy();
|
|
1712
|
-
}
|
|
1713
|
-
});
|
|
1714
|
-
return body;
|
|
1715
|
-
};
|
|
1716
|
-
var getStats = (path3) => {
|
|
1717
|
-
let stats;
|
|
1718
|
-
try {
|
|
1719
|
-
stats = statSync(path3);
|
|
1720
|
-
} catch {
|
|
1721
|
-
}
|
|
1722
|
-
return stats;
|
|
1723
|
-
};
|
|
1724
|
-
var tryDecode = (str, decoder) => {
|
|
1725
|
-
try {
|
|
1726
|
-
return decoder(str);
|
|
1727
|
-
} catch {
|
|
1728
|
-
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
|
1729
|
-
try {
|
|
1730
|
-
return decoder(match);
|
|
1731
|
-
} catch {
|
|
1732
|
-
return match;
|
|
1733
|
-
}
|
|
1734
|
-
});
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
1738
|
-
var serveStatic = (options = { root: "" }) => {
|
|
1739
|
-
const root = options.root || "";
|
|
1740
|
-
const optionPath = options.path;
|
|
1741
|
-
if (root !== "" && !existsSync(root)) {
|
|
1742
|
-
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
1743
|
-
}
|
|
1744
|
-
return async (c, next) => {
|
|
1745
|
-
if (c.finalized) {
|
|
1746
|
-
return next();
|
|
1747
|
-
}
|
|
1748
|
-
let filename;
|
|
1749
|
-
if (optionPath) {
|
|
1750
|
-
filename = optionPath;
|
|
1751
|
-
} else {
|
|
1752
|
-
try {
|
|
1753
|
-
filename = tryDecodeURI(c.req.path);
|
|
1754
|
-
if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
|
|
1755
|
-
throw new Error();
|
|
1756
|
-
}
|
|
1757
|
-
} catch {
|
|
1758
|
-
await options.onNotFound?.(c.req.path, c);
|
|
1759
|
-
return next();
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
let path3 = join(
|
|
1763
|
-
root,
|
|
1764
|
-
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
|
1765
|
-
);
|
|
1766
|
-
let stats = getStats(path3);
|
|
1767
|
-
if (stats && stats.isDirectory()) {
|
|
1768
|
-
const indexFile2 = options.index ?? "index.html";
|
|
1769
|
-
path3 = join(path3, indexFile2);
|
|
1770
|
-
stats = getStats(path3);
|
|
1771
|
-
}
|
|
1772
|
-
if (!stats) {
|
|
1773
|
-
await options.onNotFound?.(path3, c);
|
|
1774
|
-
return next();
|
|
1775
|
-
}
|
|
1776
|
-
const mimeType = getMimeType(path3);
|
|
1777
|
-
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
1778
|
-
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
|
1779
|
-
const acceptEncodingSet = new Set(
|
|
1780
|
-
c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim())
|
|
1781
|
-
);
|
|
1782
|
-
for (const encoding of ENCODINGS_ORDERED_KEYS) {
|
|
1783
|
-
if (!acceptEncodingSet.has(encoding)) {
|
|
1784
|
-
continue;
|
|
1785
|
-
}
|
|
1786
|
-
const precompressedStats = getStats(path3 + ENCODINGS[encoding]);
|
|
1787
|
-
if (precompressedStats) {
|
|
1788
|
-
c.header("Content-Encoding", encoding);
|
|
1789
|
-
c.header("Vary", "Accept-Encoding", { append: true });
|
|
1790
|
-
stats = precompressedStats;
|
|
1791
|
-
path3 = path3 + ENCODINGS[encoding];
|
|
1792
|
-
break;
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
let result;
|
|
1797
|
-
const size = stats.size;
|
|
1798
|
-
const range = c.req.header("range") || "";
|
|
1799
|
-
if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
|
|
1800
|
-
c.header("Content-Length", size.toString());
|
|
1801
|
-
c.status(200);
|
|
1802
|
-
result = c.body(null);
|
|
1803
|
-
} else if (!range) {
|
|
1804
|
-
c.header("Content-Length", size.toString());
|
|
1805
|
-
result = c.body(createStreamBody(createReadStream(path3)), 200);
|
|
1806
|
-
} else {
|
|
1807
|
-
c.header("Accept-Ranges", "bytes");
|
|
1808
|
-
c.header("Date", stats.birthtime.toUTCString());
|
|
1809
|
-
const parts = range.replace(/bytes=/, "").split("-", 2);
|
|
1810
|
-
const start = parseInt(parts[0], 10) || 0;
|
|
1811
|
-
let end = parseInt(parts[1], 10) || size - 1;
|
|
1812
|
-
if (size < end - start + 1) {
|
|
1813
|
-
end = size - 1;
|
|
1814
|
-
}
|
|
1815
|
-
const chunksize = end - start + 1;
|
|
1816
|
-
const stream2 = createReadStream(path3, { start, end });
|
|
1817
|
-
c.header("Content-Length", chunksize.toString());
|
|
1818
|
-
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
|
1819
|
-
result = c.body(createStreamBody(stream2), 206);
|
|
1820
|
-
}
|
|
1821
|
-
await options.onFound?.(path3, c);
|
|
1822
|
-
return result;
|
|
1823
|
-
};
|
|
1824
|
-
};
|
|
1825
|
-
|
|
1826
1604
|
// server/index.ts
|
|
1827
1605
|
import { readFileSync as readFileSync48, existsSync as existsSync47, watchFile, readdirSync as readdirSync29, statSync as statSync21 } from "fs";
|
|
1828
1606
|
import { spawn as spawn3 } from "child_process";
|
|
1829
1607
|
import { createHash as createHash8 } from "crypto";
|
|
1830
|
-
import { resolve as resolve45, join as
|
|
1608
|
+
import { resolve as resolve45, join as join49, basename as basename14 } from "path";
|
|
1831
1609
|
import { homedir as homedir4 } from "os";
|
|
1832
1610
|
|
|
1833
1611
|
// server/lib/route-cache-watchers.ts
|
|
@@ -1950,21 +1728,21 @@ function onInvalidate(fn) {
|
|
|
1950
1728
|
}
|
|
1951
1729
|
|
|
1952
1730
|
// app/lib/whatsapp/message-store.ts
|
|
1953
|
-
import { existsSync
|
|
1954
|
-
import { dirname, join
|
|
1731
|
+
import { existsSync, mkdirSync, readFileSync, appendFileSync, readdirSync, statSync } from "fs";
|
|
1732
|
+
import { dirname, join } from "path";
|
|
1955
1733
|
function isReactionRecord(r) {
|
|
1956
1734
|
return r.kind === "reaction";
|
|
1957
1735
|
}
|
|
1958
|
-
var STORE_ROOT = () =>
|
|
1736
|
+
var STORE_ROOT = () => join(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-messages");
|
|
1959
1737
|
function conversationFile(platformAccountId, remoteJid) {
|
|
1960
|
-
return
|
|
1738
|
+
return join(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
|
|
1961
1739
|
}
|
|
1962
1740
|
function listStoredAccountIds() {
|
|
1963
1741
|
const root = STORE_ROOT();
|
|
1964
|
-
if (!
|
|
1742
|
+
if (!existsSync(root)) return [];
|
|
1965
1743
|
return readdirSync(root).filter((name) => {
|
|
1966
1744
|
try {
|
|
1967
|
-
return
|
|
1745
|
+
return statSync(join(root, name)).isDirectory();
|
|
1968
1746
|
} catch {
|
|
1969
1747
|
return false;
|
|
1970
1748
|
}
|
|
@@ -2000,7 +1778,7 @@ function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
|
|
|
2000
1778
|
try {
|
|
2001
1779
|
const filesToCheck = [file, ...altDedupeRemoteJids.filter((jid) => jid && jid !== record.remoteJid).map((jid) => conversationFile(platformAccountId, jid))];
|
|
2002
1780
|
for (const candidate of new Set(filesToCheck)) {
|
|
2003
|
-
if (!
|
|
1781
|
+
if (!existsSync(candidate)) continue;
|
|
2004
1782
|
const existing = parseLines(readFileSync(candidate, "utf8"));
|
|
2005
1783
|
if (existing.some((r) => r.messageId === record.messageId)) {
|
|
2006
1784
|
return { created: false };
|
|
@@ -2023,7 +1801,7 @@ function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
|
|
|
2023
1801
|
function readConversation(platformAccountId, remoteJid) {
|
|
2024
1802
|
const file = conversationFile(platformAccountId, remoteJid);
|
|
2025
1803
|
try {
|
|
2026
|
-
if (!
|
|
1804
|
+
if (!existsSync(file)) return [];
|
|
2027
1805
|
return parseLines(readFileSync(file, "utf8")).sort(byDateSentAsc);
|
|
2028
1806
|
} catch (err) {
|
|
2029
1807
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -2048,7 +1826,7 @@ function appendReaction(platformAccountId, record) {
|
|
|
2048
1826
|
function readReactions(platformAccountId, remoteJid) {
|
|
2049
1827
|
const file = conversationFile(platformAccountId, remoteJid);
|
|
2050
1828
|
try {
|
|
2051
|
-
if (!
|
|
1829
|
+
if (!existsSync(file)) return [];
|
|
2052
1830
|
const out = [];
|
|
2053
1831
|
for (const line of readFileSync(file, "utf8").split("\n")) {
|
|
2054
1832
|
if (!line.trim()) continue;
|
|
@@ -2094,23 +1872,23 @@ function summariseRecords(records) {
|
|
|
2094
1872
|
};
|
|
2095
1873
|
}
|
|
2096
1874
|
function readConversationSummaries(platformAccountId) {
|
|
2097
|
-
const dir =
|
|
1875
|
+
const dir = join(STORE_ROOT(), platformAccountId);
|
|
2098
1876
|
const out = /* @__PURE__ */ new Map();
|
|
2099
1877
|
const seen = /* @__PURE__ */ new Set();
|
|
2100
1878
|
let fullReads = 0;
|
|
2101
1879
|
let cacheHits = 0;
|
|
2102
1880
|
let bytesRead = 0;
|
|
2103
1881
|
try {
|
|
2104
|
-
if (!
|
|
1882
|
+
if (!existsSync(dir)) return out;
|
|
2105
1883
|
for (const entry of readdirSync(dir)) {
|
|
2106
1884
|
if (!entry.endsWith(".jsonl")) continue;
|
|
2107
1885
|
const remoteJid = entry.slice(0, -".jsonl".length);
|
|
2108
|
-
const file =
|
|
1886
|
+
const file = join(dir, entry);
|
|
2109
1887
|
seen.add(file);
|
|
2110
1888
|
let size;
|
|
2111
1889
|
let mtimeMs;
|
|
2112
1890
|
try {
|
|
2113
|
-
const st =
|
|
1891
|
+
const st = statSync(file);
|
|
2114
1892
|
size = st.size;
|
|
2115
1893
|
mtimeMs = st.mtimeMs;
|
|
2116
1894
|
} catch {
|
|
@@ -2150,10 +1928,10 @@ function readConversationSummaries(platformAccountId) {
|
|
|
2150
1928
|
return out;
|
|
2151
1929
|
}
|
|
2152
1930
|
function readAllConversations(platformAccountId) {
|
|
2153
|
-
const dir =
|
|
1931
|
+
const dir = join(STORE_ROOT(), platformAccountId);
|
|
2154
1932
|
const out = /* @__PURE__ */ new Map();
|
|
2155
1933
|
try {
|
|
2156
|
-
if (!
|
|
1934
|
+
if (!existsSync(dir)) return out;
|
|
2157
1935
|
for (const entry of readdirSync(dir)) {
|
|
2158
1936
|
if (!entry.endsWith(".jsonl")) continue;
|
|
2159
1937
|
const remoteJid = entry.slice(0, -".jsonl".length);
|
|
@@ -2281,110 +2059,417 @@ function attachRouteCacheWatchers() {
|
|
|
2281
2059
|
watchDirInto(resolve2(PLATFORM_ROOT, "templates", "specialists", "agents"), "sidebar-artefacts", null);
|
|
2282
2060
|
let houseId = null;
|
|
2283
2061
|
try {
|
|
2284
|
-
houseId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
2062
|
+
houseId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
2063
|
+
} catch {
|
|
2064
|
+
houseId = null;
|
|
2065
|
+
}
|
|
2066
|
+
if (houseId) {
|
|
2067
|
+
watchDirInto(STORE_ROOT(), "conversations-all", houseId);
|
|
2068
|
+
} else {
|
|
2069
|
+
console.error("[admin-events] op=watch-failed resource=conversations-all reason=house-account-unresolved");
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// server/lib/manager-events-subscriber.ts
|
|
2074
|
+
var TAG = "[webchat-pointer]";
|
|
2075
|
+
var TURN_EVENTS = /* @__PURE__ */ new Set(["row-updated", "row-created"]);
|
|
2076
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
2077
|
+
var STABLE_CONNECTION_MS = 3e4;
|
|
2078
|
+
var lastStatusBySession = /* @__PURE__ */ new Map();
|
|
2079
|
+
function handleManagerFrame(raw) {
|
|
2080
|
+
const lines = raw.split("\n");
|
|
2081
|
+
const eventLine = lines.find((l) => l.startsWith("event: "));
|
|
2082
|
+
const dataLine = lines.find((l) => l.startsWith("data: "));
|
|
2083
|
+
if (!eventLine || !dataLine) return null;
|
|
2084
|
+
if (!TURN_EVENTS.has(eventLine.slice("event: ".length).trim())) return null;
|
|
2085
|
+
let body;
|
|
2086
|
+
try {
|
|
2087
|
+
body = JSON.parse(dataLine.slice("data: ".length));
|
|
2088
|
+
} catch {
|
|
2089
|
+
console.error(`${TAG} op=skip reason=unparseable-frame`);
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
const sessionId = String(body.sessionId ?? "unknown").slice(0, 8);
|
|
2093
|
+
const accountId = typeof body.accountId === "string" && body.accountId ? body.accountId : null;
|
|
2094
|
+
if (!accountId) {
|
|
2095
|
+
console.error(`${TAG} op=skip reason=no-account sessionId=${sessionId}`);
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
const status = String(body.status ?? "unknown");
|
|
2099
|
+
const fullSessionId = String(body.sessionId ?? "");
|
|
2100
|
+
if (fullSessionId && lastStatusBySession.get(fullSessionId) === status) {
|
|
2101
|
+
return null;
|
|
2102
|
+
}
|
|
2103
|
+
if (fullSessionId) lastStatusBySession.set(fullSessionId, status);
|
|
2104
|
+
console.log(
|
|
2105
|
+
`${TAG} op=event sessionId=${sessionId} accountId=${accountId.slice(0, 8)} activity=${status}`
|
|
2106
|
+
);
|
|
2107
|
+
notify("webchat-pointer", accountId);
|
|
2108
|
+
return { resource: "webchat-pointer", accountId };
|
|
2109
|
+
}
|
|
2110
|
+
var connections = 0;
|
|
2111
|
+
var started = false;
|
|
2112
|
+
var abort = null;
|
|
2113
|
+
function startManagerEventsSubscriber() {
|
|
2114
|
+
if (started) return;
|
|
2115
|
+
started = true;
|
|
2116
|
+
abort = new AbortController();
|
|
2117
|
+
void connectLoop(abort.signal);
|
|
2118
|
+
}
|
|
2119
|
+
async function connectLoop(signal) {
|
|
2120
|
+
let backoffMs = 1e3;
|
|
2121
|
+
for (; ; ) {
|
|
2122
|
+
if (signal.aborted) return;
|
|
2123
|
+
let port2;
|
|
2124
|
+
try {
|
|
2125
|
+
port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "webchat-pointer" });
|
|
2126
|
+
} catch {
|
|
2127
|
+
console.error(`${TAG} op=drop reason=manager-port-unset`);
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
const connectedAt = Date.now();
|
|
2131
|
+
try {
|
|
2132
|
+
const res = await fetch(`http://127.0.0.1:${port2}/events`, { signal });
|
|
2133
|
+
if (!res.ok || !res.body) throw new Error(`status ${res.status}`);
|
|
2134
|
+
connections += 1;
|
|
2135
|
+
console.log(`${TAG} op=subscribe upstream-count=${connections}`);
|
|
2136
|
+
const reader = res.body.getReader();
|
|
2137
|
+
const decoder = new TextDecoder();
|
|
2138
|
+
let buffer = "";
|
|
2139
|
+
for (; ; ) {
|
|
2140
|
+
const { done, value } = await reader.read();
|
|
2141
|
+
if (done) break;
|
|
2142
|
+
buffer += decoder.decode(value, { stream: true });
|
|
2143
|
+
let cut = buffer.indexOf("\n\n");
|
|
2144
|
+
while (cut !== -1) {
|
|
2145
|
+
handleManagerFrame(buffer.slice(0, cut));
|
|
2146
|
+
buffer = buffer.slice(cut + 2);
|
|
2147
|
+
cut = buffer.indexOf("\n\n");
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
connections -= 1;
|
|
2151
|
+
} catch (err) {
|
|
2152
|
+
if (connections > 0) connections -= 1;
|
|
2153
|
+
if (signal.aborted) return;
|
|
2154
|
+
console.error(`${TAG} op=drop reason=${err instanceof Error ? err.message : String(err)}`);
|
|
2155
|
+
}
|
|
2156
|
+
if (signal.aborted) return;
|
|
2157
|
+
if (Date.now() - connectedAt >= STABLE_CONNECTION_MS) backoffMs = 1e3;
|
|
2158
|
+
console.log(`${TAG} op=reconnect inMs=${backoffMs} upstream-count=${connections}`);
|
|
2159
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
2160
|
+
backoffMs = Math.min(backoffMs * 2, MAX_BACKOFF_MS);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// server/index.ts
|
|
2165
|
+
import { monitorEventLoopDelay } from "perf_hooks";
|
|
2166
|
+
|
|
2167
|
+
// server/lib/event-loop-lag.ts
|
|
2168
|
+
function readAndResetWindow(hist, windowMs) {
|
|
2169
|
+
const toMs = (ns) => Math.round(ns / 1e6);
|
|
2170
|
+
const w = {
|
|
2171
|
+
p50Ms: toMs(hist.percentile(50)),
|
|
2172
|
+
p99Ms: toMs(hist.percentile(99)),
|
|
2173
|
+
maxMs: toMs(hist.max),
|
|
2174
|
+
// Read before the reset.
|
|
2175
|
+
count: hist.count,
|
|
2176
|
+
windowMs
|
|
2177
|
+
};
|
|
2178
|
+
hist.reset();
|
|
2179
|
+
return w;
|
|
2180
|
+
}
|
|
2181
|
+
function formatLagWindow(w) {
|
|
2182
|
+
return `[event-loop] op=lag-window p50=${w.p50Ms} p99=${w.p99Ms} max=${w.maxMs} n=${w.count} windowMs=${w.windowMs}`;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// node_modules/hono/dist/utils/mime.js
|
|
2186
|
+
var getMimeType = (filename, mimes = baseMimes) => {
|
|
2187
|
+
const regexp = /\.([a-zA-Z0-9]+?)$/;
|
|
2188
|
+
const match = filename.match(regexp);
|
|
2189
|
+
if (!match) {
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
let mimeType = mimes[match[1].toLowerCase()];
|
|
2193
|
+
if (mimeType && mimeType.startsWith("text")) {
|
|
2194
|
+
mimeType += "; charset=utf-8";
|
|
2195
|
+
}
|
|
2196
|
+
return mimeType;
|
|
2197
|
+
};
|
|
2198
|
+
var _baseMimes = {
|
|
2199
|
+
aac: "audio/aac",
|
|
2200
|
+
avi: "video/x-msvideo",
|
|
2201
|
+
avif: "image/avif",
|
|
2202
|
+
av1: "video/av1",
|
|
2203
|
+
bin: "application/octet-stream",
|
|
2204
|
+
bmp: "image/bmp",
|
|
2205
|
+
css: "text/css",
|
|
2206
|
+
csv: "text/csv",
|
|
2207
|
+
eot: "application/vnd.ms-fontobject",
|
|
2208
|
+
epub: "application/epub+zip",
|
|
2209
|
+
gif: "image/gif",
|
|
2210
|
+
gz: "application/gzip",
|
|
2211
|
+
htm: "text/html",
|
|
2212
|
+
html: "text/html",
|
|
2213
|
+
ico: "image/x-icon",
|
|
2214
|
+
ics: "text/calendar",
|
|
2215
|
+
jpeg: "image/jpeg",
|
|
2216
|
+
jpg: "image/jpeg",
|
|
2217
|
+
js: "text/javascript",
|
|
2218
|
+
json: "application/json",
|
|
2219
|
+
jsonld: "application/ld+json",
|
|
2220
|
+
map: "application/json",
|
|
2221
|
+
mid: "audio/x-midi",
|
|
2222
|
+
midi: "audio/x-midi",
|
|
2223
|
+
mjs: "text/javascript",
|
|
2224
|
+
mp3: "audio/mpeg",
|
|
2225
|
+
mp4: "video/mp4",
|
|
2226
|
+
mpeg: "video/mpeg",
|
|
2227
|
+
oga: "audio/ogg",
|
|
2228
|
+
ogv: "video/ogg",
|
|
2229
|
+
ogx: "application/ogg",
|
|
2230
|
+
opus: "audio/opus",
|
|
2231
|
+
otf: "font/otf",
|
|
2232
|
+
pdf: "application/pdf",
|
|
2233
|
+
png: "image/png",
|
|
2234
|
+
rtf: "application/rtf",
|
|
2235
|
+
svg: "image/svg+xml",
|
|
2236
|
+
tif: "image/tiff",
|
|
2237
|
+
tiff: "image/tiff",
|
|
2238
|
+
ts: "video/mp2t",
|
|
2239
|
+
ttf: "font/ttf",
|
|
2240
|
+
txt: "text/plain",
|
|
2241
|
+
wasm: "application/wasm",
|
|
2242
|
+
webm: "video/webm",
|
|
2243
|
+
weba: "audio/webm",
|
|
2244
|
+
webmanifest: "application/manifest+json",
|
|
2245
|
+
webp: "image/webp",
|
|
2246
|
+
woff: "font/woff",
|
|
2247
|
+
woff2: "font/woff2",
|
|
2248
|
+
xhtml: "application/xhtml+xml",
|
|
2249
|
+
xml: "application/xml",
|
|
2250
|
+
zip: "application/zip",
|
|
2251
|
+
"3gp": "video/3gpp",
|
|
2252
|
+
"3g2": "video/3gpp2",
|
|
2253
|
+
gltf: "model/gltf+json",
|
|
2254
|
+
glb: "model/gltf-binary"
|
|
2255
|
+
};
|
|
2256
|
+
var baseMimes = _baseMimes;
|
|
2257
|
+
|
|
2258
|
+
// node_modules/@hono/node-server/dist/serve-static.mjs
|
|
2259
|
+
import { createReadStream, statSync as statSync2, existsSync as existsSync2 } from "fs";
|
|
2260
|
+
import { join as join2 } from "path";
|
|
2261
|
+
import { versions } from "process";
|
|
2262
|
+
import { Readable } from "stream";
|
|
2263
|
+
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
2264
|
+
var ENCODINGS = {
|
|
2265
|
+
br: ".br",
|
|
2266
|
+
zstd: ".zst",
|
|
2267
|
+
gzip: ".gz"
|
|
2268
|
+
};
|
|
2269
|
+
var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
|
|
2270
|
+
var pr54206Applied = () => {
|
|
2271
|
+
const [major, minor] = versions.node.split(".").map((component) => parseInt(component));
|
|
2272
|
+
return major >= 23 || major === 22 && minor >= 7 || major === 20 && minor >= 18;
|
|
2273
|
+
};
|
|
2274
|
+
var useReadableToWeb = pr54206Applied();
|
|
2275
|
+
var createStreamBody = (stream2) => {
|
|
2276
|
+
if (useReadableToWeb) {
|
|
2277
|
+
return Readable.toWeb(stream2);
|
|
2278
|
+
}
|
|
2279
|
+
const body = new ReadableStream({
|
|
2280
|
+
start(controller) {
|
|
2281
|
+
stream2.on("data", (chunk) => {
|
|
2282
|
+
controller.enqueue(chunk);
|
|
2283
|
+
});
|
|
2284
|
+
stream2.on("error", (err) => {
|
|
2285
|
+
controller.error(err);
|
|
2286
|
+
});
|
|
2287
|
+
stream2.on("end", () => {
|
|
2288
|
+
controller.close();
|
|
2289
|
+
});
|
|
2290
|
+
},
|
|
2291
|
+
cancel() {
|
|
2292
|
+
stream2.destroy();
|
|
2293
|
+
}
|
|
2294
|
+
});
|
|
2295
|
+
return body;
|
|
2296
|
+
};
|
|
2297
|
+
var getStats = (path3) => {
|
|
2298
|
+
let stats;
|
|
2299
|
+
try {
|
|
2300
|
+
stats = statSync2(path3);
|
|
2301
|
+
} catch {
|
|
2302
|
+
}
|
|
2303
|
+
return stats;
|
|
2304
|
+
};
|
|
2305
|
+
var tryDecode = (str, decoder) => {
|
|
2306
|
+
try {
|
|
2307
|
+
return decoder(str);
|
|
2308
|
+
} catch {
|
|
2309
|
+
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
|
2310
|
+
try {
|
|
2311
|
+
return decoder(match);
|
|
2312
|
+
} catch {
|
|
2313
|
+
return match;
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
};
|
|
2318
|
+
var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
2319
|
+
var serveStatic = (options = { root: "" }) => {
|
|
2320
|
+
const root = options.root || "";
|
|
2321
|
+
const optionPath = options.path;
|
|
2322
|
+
if (root !== "" && !existsSync2(root)) {
|
|
2323
|
+
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
2324
|
+
}
|
|
2325
|
+
return async (c, next) => {
|
|
2326
|
+
if (c.finalized) {
|
|
2327
|
+
return next();
|
|
2328
|
+
}
|
|
2329
|
+
let filename;
|
|
2330
|
+
if (optionPath) {
|
|
2331
|
+
filename = optionPath;
|
|
2332
|
+
} else {
|
|
2333
|
+
try {
|
|
2334
|
+
filename = tryDecodeURI(c.req.path);
|
|
2335
|
+
if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
|
|
2336
|
+
throw new Error();
|
|
2337
|
+
}
|
|
2338
|
+
} catch {
|
|
2339
|
+
await options.onNotFound?.(c.req.path, c);
|
|
2340
|
+
return next();
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
let path3 = join2(
|
|
2344
|
+
root,
|
|
2345
|
+
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
|
2346
|
+
);
|
|
2347
|
+
let stats = getStats(path3);
|
|
2348
|
+
if (stats && stats.isDirectory()) {
|
|
2349
|
+
const indexFile2 = options.index ?? "index.html";
|
|
2350
|
+
path3 = join2(path3, indexFile2);
|
|
2351
|
+
stats = getStats(path3);
|
|
2352
|
+
}
|
|
2353
|
+
if (!stats) {
|
|
2354
|
+
await options.onNotFound?.(path3, c);
|
|
2355
|
+
return next();
|
|
2356
|
+
}
|
|
2357
|
+
const mimeType = getMimeType(path3);
|
|
2358
|
+
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
2359
|
+
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
|
2360
|
+
const acceptEncodingSet = new Set(
|
|
2361
|
+
c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim())
|
|
2362
|
+
);
|
|
2363
|
+
for (const encoding of ENCODINGS_ORDERED_KEYS) {
|
|
2364
|
+
if (!acceptEncodingSet.has(encoding)) {
|
|
2365
|
+
continue;
|
|
2366
|
+
}
|
|
2367
|
+
const precompressedStats = getStats(path3 + ENCODINGS[encoding]);
|
|
2368
|
+
if (precompressedStats) {
|
|
2369
|
+
c.header("Content-Encoding", encoding);
|
|
2370
|
+
c.header("Vary", "Accept-Encoding", { append: true });
|
|
2371
|
+
stats = precompressedStats;
|
|
2372
|
+
path3 = path3 + ENCODINGS[encoding];
|
|
2373
|
+
break;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
let result;
|
|
2378
|
+
const size = stats.size;
|
|
2379
|
+
const range = c.req.header("range") || "";
|
|
2380
|
+
if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
|
|
2381
|
+
c.header("Content-Length", size.toString());
|
|
2382
|
+
c.status(200);
|
|
2383
|
+
result = c.body(null);
|
|
2384
|
+
} else if (!range) {
|
|
2385
|
+
c.header("Content-Length", size.toString());
|
|
2386
|
+
result = c.body(createStreamBody(createReadStream(path3)), 200);
|
|
2387
|
+
} else {
|
|
2388
|
+
c.header("Accept-Ranges", "bytes");
|
|
2389
|
+
c.header("Date", stats.birthtime.toUTCString());
|
|
2390
|
+
const parts = range.replace(/bytes=/, "").split("-", 2);
|
|
2391
|
+
const start = parseInt(parts[0], 10) || 0;
|
|
2392
|
+
let end = parseInt(parts[1], 10) || size - 1;
|
|
2393
|
+
if (size < end - start + 1) {
|
|
2394
|
+
end = size - 1;
|
|
2395
|
+
}
|
|
2396
|
+
const chunksize = end - start + 1;
|
|
2397
|
+
const stream2 = createReadStream(path3, { start, end });
|
|
2398
|
+
c.header("Content-Length", chunksize.toString());
|
|
2399
|
+
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
|
2400
|
+
result = c.body(createStreamBody(stream2), 206);
|
|
2401
|
+
}
|
|
2402
|
+
await options.onFound?.(path3, c);
|
|
2403
|
+
return result;
|
|
2404
|
+
};
|
|
2405
|
+
};
|
|
2406
|
+
|
|
2407
|
+
// server/lib/static-cache.ts
|
|
2408
|
+
import { statSync as statSync3 } from "fs";
|
|
2409
|
+
import { join as join3 } from "path";
|
|
2410
|
+
var IMMUTABLE = "public, max-age=31536000, immutable";
|
|
2411
|
+
var REVALIDATE = "public, no-cache";
|
|
2412
|
+
function statOrNull(path3) {
|
|
2413
|
+
try {
|
|
2414
|
+
return statSync3(path3);
|
|
2285
2415
|
} catch {
|
|
2286
|
-
|
|
2287
|
-
}
|
|
2288
|
-
if (houseId) {
|
|
2289
|
-
watchDirInto(STORE_ROOT(), "conversations-all", houseId);
|
|
2290
|
-
} else {
|
|
2291
|
-
console.error("[admin-events] op=watch-failed resource=conversations-all reason=house-account-unresolved");
|
|
2416
|
+
return null;
|
|
2292
2417
|
}
|
|
2293
2418
|
}
|
|
2294
|
-
|
|
2295
|
-
// server/lib/manager-events-subscriber.ts
|
|
2296
|
-
var TAG = "[webchat-pointer]";
|
|
2297
|
-
var TURN_EVENTS = /* @__PURE__ */ new Set(["row-updated", "row-created"]);
|
|
2298
|
-
var MAX_BACKOFF_MS = 3e4;
|
|
2299
|
-
var STABLE_CONNECTION_MS = 3e4;
|
|
2300
|
-
var lastStatusBySession = /* @__PURE__ */ new Map();
|
|
2301
|
-
function handleManagerFrame(raw) {
|
|
2302
|
-
const lines = raw.split("\n");
|
|
2303
|
-
const eventLine = lines.find((l) => l.startsWith("event: "));
|
|
2304
|
-
const dataLine = lines.find((l) => l.startsWith("data: "));
|
|
2305
|
-
if (!eventLine || !dataLine) return null;
|
|
2306
|
-
if (!TURN_EVENTS.has(eventLine.slice("event: ".length).trim())) return null;
|
|
2307
|
-
let body;
|
|
2419
|
+
function tryDecodeURI2(str) {
|
|
2308
2420
|
try {
|
|
2309
|
-
|
|
2421
|
+
return decodeURI(str);
|
|
2310
2422
|
} catch {
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
return null;
|
|
2319
|
-
}
|
|
2320
|
-
const status = String(body.status ?? "unknown");
|
|
2321
|
-
const fullSessionId = String(body.sessionId ?? "");
|
|
2322
|
-
if (fullSessionId && lastStatusBySession.get(fullSessionId) === status) {
|
|
2323
|
-
return null;
|
|
2423
|
+
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
|
2424
|
+
try {
|
|
2425
|
+
return decodeURI(match);
|
|
2426
|
+
} catch {
|
|
2427
|
+
return match;
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2324
2430
|
}
|
|
2325
|
-
if (fullSessionId) lastStatusBySession.set(fullSessionId, status);
|
|
2326
|
-
console.log(
|
|
2327
|
-
`${TAG} op=event sessionId=${sessionId} accountId=${accountId.slice(0, 8)} activity=${status}`
|
|
2328
|
-
);
|
|
2329
|
-
notify("webchat-pointer", accountId);
|
|
2330
|
-
return { resource: "webchat-pointer", accountId };
|
|
2331
2431
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2432
|
+
function resolveStaticFile(root, reqPath) {
|
|
2433
|
+
const filename = tryDecodeURI2(reqPath);
|
|
2434
|
+
if (/(?:^|[/\\])\.\.(?:$|[/\\])/.test(filename)) return null;
|
|
2435
|
+
let path3 = join3(root, filename);
|
|
2436
|
+
let stats = statOrNull(path3);
|
|
2437
|
+
if (stats?.isDirectory()) {
|
|
2438
|
+
path3 = join3(path3, "index.html");
|
|
2439
|
+
stats = statOrNull(path3);
|
|
2440
|
+
}
|
|
2441
|
+
if (!stats?.isFile()) return null;
|
|
2442
|
+
return { path: path3, stats, filename };
|
|
2340
2443
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
console.error(`${TAG} op=drop reason=manager-port-unset`);
|
|
2350
|
-
return;
|
|
2351
|
-
}
|
|
2352
|
-
const connectedAt = Date.now();
|
|
2353
|
-
try {
|
|
2354
|
-
const res = await fetch(`http://127.0.0.1:${port2}/events`, { signal });
|
|
2355
|
-
if (!res.ok || !res.body) throw new Error(`status ${res.status}`);
|
|
2356
|
-
connections += 1;
|
|
2357
|
-
console.log(`${TAG} op=subscribe upstream-count=${connections}`);
|
|
2358
|
-
const reader = res.body.getReader();
|
|
2359
|
-
const decoder = new TextDecoder();
|
|
2360
|
-
let buffer = "";
|
|
2361
|
-
for (; ; ) {
|
|
2362
|
-
const { done, value } = await reader.read();
|
|
2363
|
-
if (done) break;
|
|
2364
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2365
|
-
let cut = buffer.indexOf("\n\n");
|
|
2366
|
-
while (cut !== -1) {
|
|
2367
|
-
handleManagerFrame(buffer.slice(0, cut));
|
|
2368
|
-
buffer = buffer.slice(cut + 2);
|
|
2369
|
-
cut = buffer.indexOf("\n\n");
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
connections -= 1;
|
|
2373
|
-
} catch (err) {
|
|
2374
|
-
if (connections > 0) connections -= 1;
|
|
2375
|
-
if (signal.aborted) return;
|
|
2376
|
-
console.error(`${TAG} op=drop reason=${err instanceof Error ? err.message : String(err)}`);
|
|
2444
|
+
function staticCacheHeaders(root) {
|
|
2445
|
+
return async (c, next) => {
|
|
2446
|
+
if (c.finalized) return next();
|
|
2447
|
+
const hit = resolveStaticFile(root, c.req.path);
|
|
2448
|
+
if (!hit) return next();
|
|
2449
|
+
if (hit.filename.startsWith("/assets/")) {
|
|
2450
|
+
c.header("Cache-Control", IMMUTABLE);
|
|
2451
|
+
return next();
|
|
2377
2452
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2453
|
+
const etag = `"${hit.stats.size}-${hit.stats.mtimeMs}"`;
|
|
2454
|
+
c.header("Cache-Control", REVALIDATE);
|
|
2455
|
+
c.header("Last-Modified", hit.stats.mtime.toUTCString());
|
|
2456
|
+
c.header("ETag", etag);
|
|
2457
|
+
if (c.req.header("If-None-Match") === etag) return c.body(null, 304);
|
|
2458
|
+
return next();
|
|
2459
|
+
};
|
|
2384
2460
|
}
|
|
2385
2461
|
|
|
2386
|
-
// server/
|
|
2387
|
-
|
|
2462
|
+
// server/lib/static-mounts.ts
|
|
2463
|
+
function mountStaticFiles(app70, root) {
|
|
2464
|
+
app70.use("/*", staticCacheHeaders(root));
|
|
2465
|
+
app70.use("/assets/*", assetsVary);
|
|
2466
|
+
app70.use("/assets/*", serveStatic({ root, precompressed: true }));
|
|
2467
|
+
app70.use("/*", serveStatic({ root }));
|
|
2468
|
+
}
|
|
2469
|
+
var assetsVary = async (c, next) => {
|
|
2470
|
+
await next();
|
|
2471
|
+
if (!c.res.headers.has("Vary")) c.res.headers.set("Vary", "Accept-Encoding");
|
|
2472
|
+
};
|
|
2388
2473
|
|
|
2389
2474
|
// app/lib/whatsapp/inbound/media-download-guard.ts
|
|
2390
2475
|
var TAG2 = "[media-guard]";
|
|
@@ -2452,14 +2537,14 @@ function installMediaDownloadGuard() {
|
|
|
2452
2537
|
}
|
|
2453
2538
|
|
|
2454
2539
|
// app/lib/whatsapp/ingest-audit.ts
|
|
2455
|
-
import { readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as
|
|
2456
|
-
import { join as
|
|
2540
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
2541
|
+
import { join as join5 } from "path";
|
|
2457
2542
|
|
|
2458
2543
|
// app/lib/whatsapp/ingest-ledger.ts
|
|
2459
2544
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, appendFileSync as appendFileSync2, readFileSync as readFileSync3, writeFileSync, readdirSync as readdirSync3 } from "fs";
|
|
2460
|
-
import { join as
|
|
2545
|
+
import { join as join4 } from "path";
|
|
2461
2546
|
var TAG3 = "[wa-ingest-ledger]";
|
|
2462
|
-
var LEDGER_ROOT = () =>
|
|
2547
|
+
var LEDGER_ROOT = () => join4(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-ingest-ledger");
|
|
2463
2548
|
var ensuredRoots = /* @__PURE__ */ new Set();
|
|
2464
2549
|
function ledgerFilePath(account) {
|
|
2465
2550
|
const root = LEDGER_ROOT();
|
|
@@ -2467,7 +2552,7 @@ function ledgerFilePath(account) {
|
|
|
2467
2552
|
if (!existsSync3(root)) mkdirSync2(root, { recursive: true });
|
|
2468
2553
|
ensuredRoots.add(root);
|
|
2469
2554
|
}
|
|
2470
|
-
return
|
|
2555
|
+
return join4(root, `${account}.jsonl`);
|
|
2471
2556
|
}
|
|
2472
2557
|
function appendStanza(entry) {
|
|
2473
2558
|
try {
|
|
@@ -2573,21 +2658,21 @@ function readAllConversationsCached(accountId) {
|
|
|
2573
2658
|
const out = /* @__PURE__ */ new Map();
|
|
2574
2659
|
let dir;
|
|
2575
2660
|
try {
|
|
2576
|
-
dir = readdirSync4(
|
|
2661
|
+
dir = readdirSync4(join5(STORE_ROOT(), accountId));
|
|
2577
2662
|
} catch {
|
|
2578
2663
|
return out;
|
|
2579
2664
|
}
|
|
2580
2665
|
for (const file of dir) {
|
|
2581
2666
|
if (!file.endsWith(".jsonl")) continue;
|
|
2582
|
-
const path3 =
|
|
2583
|
-
let
|
|
2667
|
+
const path3 = join5(STORE_ROOT(), accountId, file);
|
|
2668
|
+
let stat12;
|
|
2584
2669
|
try {
|
|
2585
|
-
|
|
2670
|
+
stat12 = statSync4(path3);
|
|
2586
2671
|
} catch {
|
|
2587
2672
|
continue;
|
|
2588
2673
|
}
|
|
2589
2674
|
const hit = idCache.get(path3);
|
|
2590
|
-
if (hit && hit.size ===
|
|
2675
|
+
if (hit && hit.size === stat12.size && hit.mtimeMs === stat12.mtimeMs) {
|
|
2591
2676
|
out.set(file, hit.ids);
|
|
2592
2677
|
continue;
|
|
2593
2678
|
}
|
|
@@ -2604,7 +2689,7 @@ function readAllConversationsCached(accountId) {
|
|
|
2604
2689
|
} catch {
|
|
2605
2690
|
continue;
|
|
2606
2691
|
}
|
|
2607
|
-
idCache.set(path3, { size:
|
|
2692
|
+
idCache.set(path3, { size: stat12.size, mtimeMs: stat12.mtimeMs, ids: parsed });
|
|
2608
2693
|
out.set(file, parsed);
|
|
2609
2694
|
}
|
|
2610
2695
|
return out;
|
|
@@ -2756,12 +2841,12 @@ function pwaCensus(d) {
|
|
|
2756
2841
|
}
|
|
2757
2842
|
|
|
2758
2843
|
// server/webchat-descriptor.ts
|
|
2759
|
-
import { resolve as resolve3, join as
|
|
2844
|
+
import { resolve as resolve3, join as join6 } from "path";
|
|
2760
2845
|
function webchatGatewayUrl() {
|
|
2761
2846
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
2762
2847
|
}
|
|
2763
2848
|
function webchatServerPath() {
|
|
2764
|
-
return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve3(process.env.MAXY_PLATFORM_ROOT ??
|
|
2849
|
+
return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve3(process.env.MAXY_PLATFORM_ROOT ?? join6(__dirname, ".."), "services/webchat-channel/dist/server.js");
|
|
2765
2850
|
}
|
|
2766
2851
|
function webchatChannelDescriptor(key) {
|
|
2767
2852
|
return { key, gatewayUrl: webchatGatewayUrl(), serverPath: webchatServerPath() };
|
|
@@ -4983,7 +5068,7 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
|
|
|
4983
5068
|
}
|
|
4984
5069
|
|
|
4985
5070
|
// app/lib/managed-service.ts
|
|
4986
|
-
import { join as
|
|
5071
|
+
import { join as join7 } from "path";
|
|
4987
5072
|
import { readFileSync as readFileSync9 } from "fs";
|
|
4988
5073
|
function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
|
|
4989
5074
|
let houseId;
|
|
@@ -4994,7 +5079,7 @@ function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
|
|
|
4994
5079
|
}
|
|
4995
5080
|
try {
|
|
4996
5081
|
const cfg = JSON.parse(
|
|
4997
|
-
readFileSync9(
|
|
5082
|
+
readFileSync9(join7(accountsDir, houseId, "account.json"), "utf-8")
|
|
4998
5083
|
);
|
|
4999
5084
|
return cfg.managedService === true;
|
|
5000
5085
|
} catch {
|
|
@@ -5008,7 +5093,7 @@ function isCustomerTurnSuppressed(role, managedService) {
|
|
|
5008
5093
|
// app/lib/whatsapp/inbound/media.ts
|
|
5009
5094
|
import { randomUUID as randomUUID4, createHash } from "crypto";
|
|
5010
5095
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
5011
|
-
import { join as
|
|
5096
|
+
import { join as join9 } from "path";
|
|
5012
5097
|
import {
|
|
5013
5098
|
downloadMediaMessage,
|
|
5014
5099
|
downloadContentFromMessage,
|
|
@@ -5023,7 +5108,7 @@ import { resolve as resolve7, extname } from "path";
|
|
|
5023
5108
|
|
|
5024
5109
|
// app/lib/data-path.ts
|
|
5025
5110
|
import { realpathSync } from "fs";
|
|
5026
|
-
import { resolve as resolve6, normalize, sep as sep2, relative, basename, join as
|
|
5111
|
+
import { resolve as resolve6, normalize, sep as sep2, relative, basename, join as join8 } from "path";
|
|
5027
5112
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "../platform");
|
|
5028
5113
|
var DATA_ROOT = resolve6(PLATFORM_ROOT3, "..", "data");
|
|
5029
5114
|
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve6(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
@@ -5091,7 +5176,7 @@ function scratchpadTmpBase() {
|
|
|
5091
5176
|
}
|
|
5092
5177
|
function sessionScratchpadRoot(projectDir, sessionId) {
|
|
5093
5178
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : 0;
|
|
5094
|
-
return
|
|
5179
|
+
return join8(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
|
|
5095
5180
|
}
|
|
5096
5181
|
function resolveScratchpadPath(raw, scratchpadRootAbs) {
|
|
5097
5182
|
return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
|
|
@@ -5634,7 +5719,7 @@ async function downloadInboundMedia(msg, sock, opts) {
|
|
|
5634
5719
|
if (!res) return void 0;
|
|
5635
5720
|
await mkdir2(MEDIA_DIR, { recursive: true });
|
|
5636
5721
|
const ext = mimeToExt(res.mimetype);
|
|
5637
|
-
const filePath =
|
|
5722
|
+
const filePath = join9(MEDIA_DIR, `${randomUUID4()}.${ext}`);
|
|
5638
5723
|
await writeFile2(filePath, res.buffer);
|
|
5639
5724
|
const sizeKB = (res.buffer.length / 1024).toFixed(0);
|
|
5640
5725
|
console.error(`${TAG14} media downloaded type=${res.mimetype} size=${sizeKB}KB path=${filePath}`);
|
|
@@ -7436,7 +7521,7 @@ var health_default = app;
|
|
|
7436
7521
|
// app/lib/stt/voice-note.ts
|
|
7437
7522
|
import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
|
|
7438
7523
|
import { tmpdir } from "os";
|
|
7439
|
-
import { join as
|
|
7524
|
+
import { join as join10 } from "path";
|
|
7440
7525
|
|
|
7441
7526
|
// app/lib/stt/audio-mime.ts
|
|
7442
7527
|
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -7490,9 +7575,9 @@ async function transcribeVoiceNote(file, source) {
|
|
|
7490
7575
|
let tempDir;
|
|
7491
7576
|
let tempPath;
|
|
7492
7577
|
try {
|
|
7493
|
-
tempDir = await mkdtemp(
|
|
7578
|
+
tempDir = await mkdtemp(join10(tmpdir(), "voice-"));
|
|
7494
7579
|
const ext = audioExtension(mimeType);
|
|
7495
|
-
tempPath =
|
|
7580
|
+
tempPath = join10(tempDir, `recording${ext}`);
|
|
7496
7581
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
7497
7582
|
await writeFile3(tempPath, buffer);
|
|
7498
7583
|
} catch (err) {
|
|
@@ -8068,7 +8153,7 @@ async function sendTelegramText(botToken, chatId, text) {
|
|
|
8068
8153
|
}
|
|
8069
8154
|
|
|
8070
8155
|
// server/routes/whatsapp.ts
|
|
8071
|
-
import { join as
|
|
8156
|
+
import { join as join13, resolve as resolve11 } from "path";
|
|
8072
8157
|
import { readdirSync as readdirSync7, readFileSync as readFileSync14, existsSync as existsSync8 } from "fs";
|
|
8073
8158
|
|
|
8074
8159
|
// app/lib/whatsapp/login.ts
|
|
@@ -8076,7 +8161,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
8076
8161
|
|
|
8077
8162
|
// app/lib/whatsapp/config-persist.ts
|
|
8078
8163
|
import { readFileSync as readFileSync13, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
|
|
8079
|
-
import { resolve as resolve9, join as
|
|
8164
|
+
import { resolve as resolve9, join as join11, dirname as dirname2, basename as basename2 } from "path";
|
|
8080
8165
|
var TAG22 = "[whatsapp:config]";
|
|
8081
8166
|
function configPath(accountDir) {
|
|
8082
8167
|
return resolve9(accountDir, "account.json");
|
|
@@ -8423,7 +8508,7 @@ function setPublicAgent(accountDir, slug) {
|
|
|
8423
8508
|
if (!trimmed) {
|
|
8424
8509
|
return { ok: false, error: "Agent slug cannot be empty." };
|
|
8425
8510
|
}
|
|
8426
|
-
const agentConfigPath =
|
|
8511
|
+
const agentConfigPath = join11(accountDir, "agents", trimmed, "config.json");
|
|
8427
8512
|
if (!existsSync7(agentConfigPath)) {
|
|
8428
8513
|
return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
|
|
8429
8514
|
}
|
|
@@ -9060,12 +9145,12 @@ function serializeWhatsAppSchema() {
|
|
|
9060
9145
|
|
|
9061
9146
|
// app/lib/whatsapp/status-reconcile.ts
|
|
9062
9147
|
import { readdirSync as readdirSync6 } from "fs";
|
|
9063
|
-
import { join as
|
|
9148
|
+
import { join as join12 } from "path";
|
|
9064
9149
|
var TAG25 = "[whatsapp:reconcile]";
|
|
9065
9150
|
var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
|
|
9066
9151
|
function listCredsAccountIds(credsRoot) {
|
|
9067
9152
|
try {
|
|
9068
|
-
return readdirSync6(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(
|
|
9153
|
+
return readdirSync6(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join12(credsRoot, e.name))).map((e) => e.name);
|
|
9069
9154
|
} catch {
|
|
9070
9155
|
return [];
|
|
9071
9156
|
}
|
|
@@ -9080,7 +9165,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
9080
9165
|
const entries2 = [];
|
|
9081
9166
|
for (const accountId of listCredsAccountIds(credsRoot)) {
|
|
9082
9167
|
if (liveAccountIds.has(accountId)) continue;
|
|
9083
|
-
const authDir =
|
|
9168
|
+
const authDir = join12(credsRoot, accountId);
|
|
9084
9169
|
const census = credsCensus(authDir);
|
|
9085
9170
|
if (census.registered && !census.hasAccountSignature) {
|
|
9086
9171
|
const inFlight3 = activeLoginAccountIds.has(accountId);
|
|
@@ -9317,7 +9402,7 @@ app2.get("/status", (c) => {
|
|
|
9317
9402
|
const live = getStatus();
|
|
9318
9403
|
const liveIds = new Set(live.map((a) => a.accountId));
|
|
9319
9404
|
const activeLoginIds = new Set(listActiveLoginAccountIds());
|
|
9320
|
-
const credsRoot =
|
|
9405
|
+
const credsRoot = join13(MAXY_DIR, "credentials", "whatsapp");
|
|
9321
9406
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
9322
9407
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds, activeLoginAccountIds: activeLoginIds });
|
|
9323
9408
|
const cfg = getWhatsAppConfig();
|
|
@@ -9354,7 +9439,7 @@ app2.post("/login/start", async (c) => {
|
|
|
9354
9439
|
if (!phone) {
|
|
9355
9440
|
return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
|
|
9356
9441
|
}
|
|
9357
|
-
const authDir =
|
|
9442
|
+
const authDir = join13(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
9358
9443
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
9359
9444
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
9360
9445
|
console.error(`${TAG26} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
@@ -10001,12 +10086,12 @@ var bodyLimit = (options) => {
|
|
|
10001
10086
|
};
|
|
10002
10087
|
|
|
10003
10088
|
// server/routes/storage-broker.ts
|
|
10004
|
-
import { join as
|
|
10089
|
+
import { join as join14, resolve as resolve12 } from "path";
|
|
10005
10090
|
import { readdirSync as readdirSync8, readFileSync as readFileSync15, existsSync as existsSync9, realpathSync as realpathSync4 } from "fs";
|
|
10006
10091
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10007
10092
|
var app3 = new Hono();
|
|
10008
10093
|
function platformRoot() {
|
|
10009
|
-
return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
10094
|
+
return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? join14(__dirname, "..", "..");
|
|
10010
10095
|
}
|
|
10011
10096
|
function caller(c) {
|
|
10012
10097
|
return c.req.header("x-maxy-caller-account")?.trim() || null;
|
|
@@ -10541,7 +10626,7 @@ async function runStorageAudit(root) {
|
|
|
10541
10626
|
if (!existsSync9(accountsDir)) return [];
|
|
10542
10627
|
const files = [];
|
|
10543
10628
|
for (const accountId of readdirSync8(accountsDir)) {
|
|
10544
|
-
const p =
|
|
10629
|
+
const p = join14(accountsDir, accountId, "secrets", "cloudflare.env");
|
|
10545
10630
|
if (existsSync9(p)) files.push({ accountId, path: p, contents: readFileSync15(p, "utf8") });
|
|
10546
10631
|
}
|
|
10547
10632
|
return files;
|
|
@@ -10640,7 +10725,7 @@ function discoverPortalAccounts(accountsDir) {
|
|
|
10640
10725
|
if (!existsSync9(accountsDir)) return [];
|
|
10641
10726
|
const found = [];
|
|
10642
10727
|
for (const accountId of readdirSync8(accountsDir)) {
|
|
10643
|
-
const configPath2 =
|
|
10728
|
+
const configPath2 = join14(accountsDir, accountId, "data-portal.json");
|
|
10644
10729
|
if (!existsSync9(configPath2)) continue;
|
|
10645
10730
|
try {
|
|
10646
10731
|
const cfg = JSON.parse(readFileSync15(configPath2, "utf-8"));
|
|
@@ -10723,7 +10808,7 @@ async function runDataPortalAudit(root) {
|
|
|
10723
10808
|
// server/portal-uploads-pull.ts
|
|
10724
10809
|
import { existsSync as existsSync10 } from "fs";
|
|
10725
10810
|
import { mkdir as mkdir3, readFile as readFile2, rename, stat as stat3, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
|
|
10726
|
-
import { basename as basename4, dirname as dirname4, join as
|
|
10811
|
+
import { basename as basename4, dirname as dirname4, join as join15, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
|
|
10727
10812
|
|
|
10728
10813
|
// ../plugins/cloudflare/bin/schema-exposed-dirs.mjs
|
|
10729
10814
|
var ONT_START = "<!-- ontology-buckets:start -->";
|
|
@@ -10821,19 +10906,19 @@ function resolveDestination(accountDir, row, exposed) {
|
|
|
10821
10906
|
if (!segments.every(safeSegment)) return { ok: false, reason: "bad-target" };
|
|
10822
10907
|
if (!exposed.includes(segments[0])) return { ok: false, reason: "bad-target" };
|
|
10823
10908
|
root = resolve13(accountDir);
|
|
10824
|
-
dir =
|
|
10909
|
+
dir = join15(root, ...segments);
|
|
10825
10910
|
} else {
|
|
10826
10911
|
root = resolve13(accountDir, "uploads");
|
|
10827
|
-
dir =
|
|
10912
|
+
dir = join15(root, row.ownerId);
|
|
10828
10913
|
}
|
|
10829
|
-
const final =
|
|
10914
|
+
const final = join15(dir, row.filename);
|
|
10830
10915
|
if (!final.startsWith(root + sep3)) {
|
|
10831
10916
|
return { ok: false, reason: row.targetPath ? "bad-target" : "bad-filename" };
|
|
10832
10917
|
}
|
|
10833
10918
|
return {
|
|
10834
10919
|
ok: true,
|
|
10835
10920
|
dir,
|
|
10836
|
-
tmp:
|
|
10921
|
+
tmp: join15(dir, ".uploads-tmp", row.filename),
|
|
10837
10922
|
final,
|
|
10838
10923
|
relative: relative2(resolve13(accountDir), final).split(sep3).join("/")
|
|
10839
10924
|
};
|
|
@@ -10846,7 +10931,7 @@ function nextFreePath(final) {
|
|
|
10846
10931
|
const stem = dot > 0 ? base.slice(0, dot) : base;
|
|
10847
10932
|
const ext = dot > 0 ? base.slice(dot) : "";
|
|
10848
10933
|
for (let n = 2; ; n++) {
|
|
10849
|
-
const candidate =
|
|
10934
|
+
const candidate = join15(dir, `${stem} (${n})${ext}`);
|
|
10850
10935
|
if (!existsSync10(candidate)) return candidate;
|
|
10851
10936
|
}
|
|
10852
10937
|
}
|
|
@@ -10950,7 +11035,7 @@ async function withdrawRow(opts) {
|
|
|
10950
11035
|
log2(`${head} removed=false result=bad-path`);
|
|
10951
11036
|
return false;
|
|
10952
11037
|
}
|
|
10953
|
-
const absolute =
|
|
11038
|
+
const absolute = join15(resolve13(accountDir), ...segments);
|
|
10954
11039
|
if (!absolute.startsWith(resolve13(accountDir) + sep3)) {
|
|
10955
11040
|
log2(`${head} removed=false result=bad-path`);
|
|
10956
11041
|
return false;
|
|
@@ -11015,13 +11100,13 @@ function parsePendingRows(raw) {
|
|
|
11015
11100
|
async function readExposedDirs(accountDir) {
|
|
11016
11101
|
let schemaText = null;
|
|
11017
11102
|
try {
|
|
11018
|
-
schemaText = await readFile2(
|
|
11103
|
+
schemaText = await readFile2(join15(accountDir, "SCHEMA.md"), "utf8");
|
|
11019
11104
|
} catch {
|
|
11020
11105
|
schemaText = null;
|
|
11021
11106
|
}
|
|
11022
11107
|
let exposeFolders = [];
|
|
11023
11108
|
try {
|
|
11024
|
-
const cfg = JSON.parse(await readFile2(
|
|
11109
|
+
const cfg = JSON.parse(await readFile2(join15(accountDir, "data-portal.json"), "utf8"));
|
|
11025
11110
|
exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
11026
11111
|
} catch {
|
|
11027
11112
|
exposeFolders = [];
|
|
@@ -11046,7 +11131,7 @@ async function runPortalUploadsPull(root) {
|
|
|
11046
11131
|
console.error(`${TAG27} op=malformed account=${portal.accountId} rows=${malformed}`);
|
|
11047
11132
|
}
|
|
11048
11133
|
if (rows.length === 0) continue;
|
|
11049
|
-
const accountDir =
|
|
11134
|
+
const accountDir = join15(accountsRoot, portal.accountId);
|
|
11050
11135
|
const r = await pullAccount({
|
|
11051
11136
|
accountDir,
|
|
11052
11137
|
accountId: portal.accountId,
|
|
@@ -11079,7 +11164,7 @@ async function runPortalUploadsPull(root) {
|
|
|
11079
11164
|
import { readFile as readFile3, readdir, stat as stat4 } from "fs/promises";
|
|
11080
11165
|
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "fs";
|
|
11081
11166
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
11082
|
-
import { join as
|
|
11167
|
+
import { join as join16, resolve as resolve14 } from "path";
|
|
11083
11168
|
import { fileURLToPath } from "url";
|
|
11084
11169
|
|
|
11085
11170
|
// ../plugins/cloudflare/bin/d1-http.mjs
|
|
@@ -11155,7 +11240,7 @@ function readEnvFile(path3) {
|
|
|
11155
11240
|
}
|
|
11156
11241
|
async function readExposeFolders(accountDir) {
|
|
11157
11242
|
try {
|
|
11158
|
-
const cfg = JSON.parse(await readFile3(
|
|
11243
|
+
const cfg = JSON.parse(await readFile3(join16(accountDir, "data-portal.json"), "utf8"));
|
|
11159
11244
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
11160
11245
|
} catch {
|
|
11161
11246
|
return [];
|
|
@@ -11166,12 +11251,12 @@ async function walkExposed(accountDir, exposed) {
|
|
|
11166
11251
|
async function walk(rel) {
|
|
11167
11252
|
let entries2;
|
|
11168
11253
|
try {
|
|
11169
|
-
entries2 = await readdir(
|
|
11254
|
+
entries2 = await readdir(join16(accountDir, rel), { withFileTypes: true });
|
|
11170
11255
|
} catch {
|
|
11171
11256
|
return;
|
|
11172
11257
|
}
|
|
11173
11258
|
try {
|
|
11174
|
-
const st = await stat4(
|
|
11259
|
+
const st = await stat4(join16(accountDir, rel));
|
|
11175
11260
|
out.push({ relPath: rel, sizeBytes: 0, modifiedAt: st.mtime.toISOString(), isDir: true });
|
|
11176
11261
|
} catch {
|
|
11177
11262
|
}
|
|
@@ -11182,7 +11267,7 @@ async function walkExposed(accountDir, exposed) {
|
|
|
11182
11267
|
await walk(childRel);
|
|
11183
11268
|
} else if (e.isFile()) {
|
|
11184
11269
|
try {
|
|
11185
|
-
const st = await stat4(
|
|
11270
|
+
const st = await stat4(join16(accountDir, childRel));
|
|
11186
11271
|
out.push({
|
|
11187
11272
|
relPath: childRel,
|
|
11188
11273
|
sizeBytes: st.size,
|
|
@@ -11201,7 +11286,7 @@ async function pushAccount(opts) {
|
|
|
11201
11286
|
const { accountDir, accountId, client, log: log2, nowIso } = opts;
|
|
11202
11287
|
let schemaText = null;
|
|
11203
11288
|
try {
|
|
11204
|
-
schemaText = await readFile3(
|
|
11289
|
+
schemaText = await readFile3(join16(accountDir, "SCHEMA.md"), "utf8");
|
|
11205
11290
|
} catch {
|
|
11206
11291
|
schemaText = null;
|
|
11207
11292
|
}
|
|
@@ -11231,19 +11316,11 @@ async function pushAccount(opts) {
|
|
|
11231
11316
|
[accountId]
|
|
11232
11317
|
);
|
|
11233
11318
|
const current = Number(state[0]?.currentGeneration ?? 0);
|
|
11234
|
-
const
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
[accountId, next]
|
|
11319
|
+
const staged = await client.query(
|
|
11320
|
+
"SELECT MAX(generation) AS g FROM directory WHERE accountId = ?",
|
|
11321
|
+
[accountId]
|
|
11238
11322
|
);
|
|
11239
|
-
const
|
|
11240
|
-
if (orphanCount > 0) {
|
|
11241
|
-
await client.query("DELETE FROM directory WHERE accountId = ? AND generation = ?", [
|
|
11242
|
-
accountId,
|
|
11243
|
-
next
|
|
11244
|
-
]);
|
|
11245
|
-
log2(`${TAG28} op=stage-clear account=${accountId} generation=${next} cleared=${orphanCount}`);
|
|
11246
|
-
}
|
|
11323
|
+
const next = Math.max(current, Number(staged[0]?.g ?? 0)) + 1;
|
|
11247
11324
|
for (const row of rows) {
|
|
11248
11325
|
await client.query(
|
|
11249
11326
|
"INSERT INTO directory (accountId, relPath, sizeBytes, modifiedAt, indexedAt, isDir, generation) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
@@ -11252,12 +11329,29 @@ async function pushAccount(opts) {
|
|
|
11252
11329
|
}
|
|
11253
11330
|
log2(`${TAG28} op=stage account=${accountId} generation=${next} inserted=${rows.length}`);
|
|
11254
11331
|
await client.query(
|
|
11255
|
-
"INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration",
|
|
11332
|
+
"INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration WHERE excluded.currentGeneration > directory_state.currentGeneration",
|
|
11256
11333
|
[accountId, next]
|
|
11257
11334
|
);
|
|
11335
|
+
const flipped = await client.query(
|
|
11336
|
+
"SELECT currentGeneration FROM directory_state WHERE accountId = ?",
|
|
11337
|
+
[accountId]
|
|
11338
|
+
);
|
|
11339
|
+
const pointer = Number(flipped[0]?.currentGeneration ?? 0);
|
|
11340
|
+
if (pointer !== next) {
|
|
11341
|
+
log2(
|
|
11342
|
+
`${TAG28} op=stage-contended account=${accountId} generation=${next} pointer=${pointer} action=superseded`
|
|
11343
|
+
);
|
|
11344
|
+
return {
|
|
11345
|
+
exposed: r.exposed,
|
|
11346
|
+
rows: rows.length,
|
|
11347
|
+
schemaPresent: true,
|
|
11348
|
+
generation: next,
|
|
11349
|
+
superseded: true
|
|
11350
|
+
};
|
|
11351
|
+
}
|
|
11258
11352
|
log2(`${TAG28} op=flip account=${accountId} generation=${next}`);
|
|
11259
11353
|
try {
|
|
11260
|
-
await client.query("DELETE FROM directory WHERE accountId = ? AND generation
|
|
11354
|
+
await client.query("DELETE FROM directory WHERE accountId = ? AND generation < ?", [
|
|
11261
11355
|
accountId,
|
|
11262
11356
|
next
|
|
11263
11357
|
]);
|
|
@@ -11309,9 +11403,9 @@ async function portalAccounts(accountsRoot) {
|
|
|
11309
11403
|
return out;
|
|
11310
11404
|
}
|
|
11311
11405
|
for (const accountId of names) {
|
|
11312
|
-
const accountDir =
|
|
11406
|
+
const accountDir = join16(accountsRoot, accountId);
|
|
11313
11407
|
try {
|
|
11314
|
-
const cfg = JSON.parse(await readFile3(
|
|
11408
|
+
const cfg = JSON.parse(await readFile3(join16(accountDir, "data-portal.json"), "utf8"));
|
|
11315
11409
|
if (typeof cfg?.portalDbName === "string" && cfg.portalDbName) {
|
|
11316
11410
|
const exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
11317
11411
|
out.push({ accountDir, accountId, dbName: cfg.portalDbName, exposeFolders });
|
|
@@ -11324,11 +11418,11 @@ async function portalAccounts(accountsRoot) {
|
|
|
11324
11418
|
return out;
|
|
11325
11419
|
}
|
|
11326
11420
|
function resolveCloudflareCredentials(platformRoot5) {
|
|
11327
|
-
const houseEnvPath =
|
|
11421
|
+
const houseEnvPath = join16(platformRoot5, "config", "cloudflare-house.env");
|
|
11328
11422
|
const house = readEnvFile(houseEnvPath);
|
|
11329
11423
|
if (!house.CLOUDFLARE_API_TOKEN) return { error: "no-house-cloudflare-credential" };
|
|
11330
11424
|
if (!house.CLOUDFLARE_ACCOUNT_ID) return { error: "no-house-cloudflare-account-id" };
|
|
11331
|
-
const cfTokenSh =
|
|
11425
|
+
const cfTokenSh = join16(platformRoot5, "plugins", "cloudflare", "bin", "cf-token.sh");
|
|
11332
11426
|
if (!existsSync11(cfTokenSh)) return { error: "cf-token-sh-missing" };
|
|
11333
11427
|
let keyName;
|
|
11334
11428
|
try {
|
|
@@ -11434,17 +11528,17 @@ async function runPortalIndexPush(root) {
|
|
|
11434
11528
|
}
|
|
11435
11529
|
|
|
11436
11530
|
// server/google-pending-audit.ts
|
|
11437
|
-
import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as
|
|
11438
|
-
import { join as
|
|
11531
|
+
import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
|
|
11532
|
+
import { join as join17 } from "path";
|
|
11439
11533
|
var GOOGLE_PENDING_LIFETIME_SEC = 600;
|
|
11440
11534
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11441
|
-
function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) =>
|
|
11535
|
+
function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) => statSync5(path3).mtimeMs) {
|
|
11442
11536
|
let scanned = 0;
|
|
11443
11537
|
let stranded = 0;
|
|
11444
11538
|
if (existsSync12(accountsDir)) {
|
|
11445
11539
|
for (const accountId of readdirSync9(accountsDir)) {
|
|
11446
11540
|
if (!UUID_RE2.test(accountId)) continue;
|
|
11447
|
-
const pendingPath2 =
|
|
11541
|
+
const pendingPath2 = join17(accountsDir, accountId, "secrets", "google", "pending-oauth.enc");
|
|
11448
11542
|
try {
|
|
11449
11543
|
if (!existsSync12(pendingPath2)) continue;
|
|
11450
11544
|
const ageSec = Math.max(0, Math.floor((nowMs - readMtimeMs(pendingPath2)) / 1e3));
|
|
@@ -11502,18 +11596,19 @@ function runReconcileLivenessAudit(statePath, nowMs, intervalMs, emit) {
|
|
|
11502
11596
|
|
|
11503
11597
|
// server/routes/whatsapp-reader.ts
|
|
11504
11598
|
import { readFileSync as readFileSync21, watch as watch2, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
|
|
11505
|
-
import { basename as basename6, dirname as dirname7, isAbsolute, join as
|
|
11599
|
+
import { basename as basename6, dirname as dirname7, isAbsolute, join as join22, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
|
|
11506
11600
|
|
|
11507
11601
|
// server/routes/admin/sidebar-sessions.ts
|
|
11508
|
-
import { readdirSync as readdirSync12, readFileSync as readFileSync19
|
|
11509
|
-
import {
|
|
11602
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync19 } from "fs";
|
|
11603
|
+
import { readFile as readFile4, stat as stat5 } from "fs/promises";
|
|
11604
|
+
import { dirname as dirname5, join as join20, resolve as resolve15 } from "path";
|
|
11510
11605
|
|
|
11511
11606
|
// ../services/claude-session-manager/src/jsonl-path.ts
|
|
11512
11607
|
import { existsSync as existsSync14, readdirSync as readdirSync10 } from "fs";
|
|
11513
11608
|
import { homedir } from "os";
|
|
11514
|
-
import { join as
|
|
11609
|
+
import { join as join18 } from "path";
|
|
11515
11610
|
function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
11516
|
-
const projectsRoot =
|
|
11611
|
+
const projectsRoot = join18(claudeConfigDir2, "projects");
|
|
11517
11612
|
if (!existsSync14(projectsRoot)) return null;
|
|
11518
11613
|
let slugs;
|
|
11519
11614
|
try {
|
|
@@ -11523,9 +11618,9 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
11523
11618
|
}
|
|
11524
11619
|
const basename15 = `${sessionId}.jsonl`;
|
|
11525
11620
|
for (const slug of slugs) {
|
|
11526
|
-
const live =
|
|
11621
|
+
const live = join18(projectsRoot, slug, basename15);
|
|
11527
11622
|
if (existsSync14(live)) return live;
|
|
11528
|
-
const archived =
|
|
11623
|
+
const archived = join18(projectsRoot, slug, "archive", basename15);
|
|
11529
11624
|
if (existsSync14(archived)) return archived;
|
|
11530
11625
|
}
|
|
11531
11626
|
return null;
|
|
@@ -11533,8 +11628,8 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
11533
11628
|
|
|
11534
11629
|
// app/lib/admin-identity/pin-validator.ts
|
|
11535
11630
|
import { createHash as createHash3 } from "crypto";
|
|
11536
|
-
import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as
|
|
11537
|
-
import { join as
|
|
11631
|
+
import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync6 } from "fs";
|
|
11632
|
+
import { join as join19 } from "path";
|
|
11538
11633
|
function hashPin(pin) {
|
|
11539
11634
|
return createHash3("sha256").update(pin).digest("hex");
|
|
11540
11635
|
}
|
|
@@ -11665,7 +11760,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11665
11760
|
throw err;
|
|
11666
11761
|
}
|
|
11667
11762
|
for (const slug of slugs) {
|
|
11668
|
-
const slugDir =
|
|
11763
|
+
const slugDir = join20(projectsRoot, slug);
|
|
11669
11764
|
let entries2;
|
|
11670
11765
|
try {
|
|
11671
11766
|
entries2 = readdirSync12(slugDir, { withFileTypes: true });
|
|
@@ -11676,9 +11771,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11676
11771
|
}
|
|
11677
11772
|
for (const entry of entries2) {
|
|
11678
11773
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
11679
|
-
out.push({ path:
|
|
11774
|
+
out.push({ path: join20(slugDir, entry.name), isSubagent: false, archived: false });
|
|
11680
11775
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
11681
|
-
const subDir =
|
|
11776
|
+
const subDir = join20(slugDir, entry.name);
|
|
11682
11777
|
let subEntries;
|
|
11683
11778
|
try {
|
|
11684
11779
|
subEntries = readdirSync12(subDir, { withFileTypes: true });
|
|
@@ -11689,11 +11784,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11689
11784
|
}
|
|
11690
11785
|
for (const sub of subEntries) {
|
|
11691
11786
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
11692
|
-
out.push({ path:
|
|
11787
|
+
out.push({ path: join20(subDir, sub.name), isSubagent: true, archived: false });
|
|
11693
11788
|
}
|
|
11694
11789
|
}
|
|
11695
11790
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
11696
|
-
const archiveDir =
|
|
11791
|
+
const archiveDir = join20(slugDir, entry.name);
|
|
11697
11792
|
let archiveEntries;
|
|
11698
11793
|
try {
|
|
11699
11794
|
archiveEntries = readdirSync12(archiveDir, { withFileTypes: true });
|
|
@@ -11704,7 +11799,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11704
11799
|
}
|
|
11705
11800
|
for (const arc of archiveEntries) {
|
|
11706
11801
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
11707
|
-
out.push({ path:
|
|
11802
|
+
out.push({ path: join20(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
11708
11803
|
}
|
|
11709
11804
|
}
|
|
11710
11805
|
}
|
|
@@ -11735,15 +11830,27 @@ async function fetchLiveSessions() {
|
|
|
11735
11830
|
return out;
|
|
11736
11831
|
}
|
|
11737
11832
|
function loadUserTitles(accountDir) {
|
|
11738
|
-
|
|
11739
|
-
if (!accountDir) return out;
|
|
11740
|
-
const path3 = join19(accountDir, "session-titles.json");
|
|
11833
|
+
if (!accountDir) return /* @__PURE__ */ new Map();
|
|
11741
11834
|
let raw;
|
|
11742
11835
|
try {
|
|
11743
|
-
raw = readFileSync19(
|
|
11836
|
+
raw = readFileSync19(join20(accountDir, "session-titles.json"), "utf8");
|
|
11744
11837
|
} catch {
|
|
11745
|
-
return
|
|
11838
|
+
return /* @__PURE__ */ new Map();
|
|
11839
|
+
}
|
|
11840
|
+
return parseUserTitles(raw);
|
|
11841
|
+
}
|
|
11842
|
+
async function loadUserTitlesAsync(accountDir) {
|
|
11843
|
+
if (!accountDir) return /* @__PURE__ */ new Map();
|
|
11844
|
+
let raw;
|
|
11845
|
+
try {
|
|
11846
|
+
raw = await readFile4(join20(accountDir, "session-titles.json"), "utf8");
|
|
11847
|
+
} catch {
|
|
11848
|
+
return /* @__PURE__ */ new Map();
|
|
11746
11849
|
}
|
|
11850
|
+
return parseUserTitles(raw);
|
|
11851
|
+
}
|
|
11852
|
+
function parseUserTitles(raw) {
|
|
11853
|
+
const out = /* @__PURE__ */ new Map();
|
|
11747
11854
|
let parsed;
|
|
11748
11855
|
try {
|
|
11749
11856
|
parsed = JSON.parse(raw);
|
|
@@ -11763,20 +11870,34 @@ function loadUserTitles(accountDir) {
|
|
|
11763
11870
|
return out;
|
|
11764
11871
|
}
|
|
11765
11872
|
function readSidecarMeta(metaPath) {
|
|
11766
|
-
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
11767
11873
|
let raw;
|
|
11768
11874
|
try {
|
|
11769
11875
|
raw = readFileSync19(metaPath, "utf8");
|
|
11770
11876
|
} catch {
|
|
11771
|
-
return
|
|
11877
|
+
return emptySidecarMeta();
|
|
11878
|
+
}
|
|
11879
|
+
return parseSidecarMeta(raw);
|
|
11880
|
+
}
|
|
11881
|
+
function emptySidecarMeta() {
|
|
11882
|
+
return { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
11883
|
+
}
|
|
11884
|
+
async function readSidecarMetaAsync(metaPath) {
|
|
11885
|
+
let raw;
|
|
11886
|
+
try {
|
|
11887
|
+
raw = await readFile4(metaPath, "utf8");
|
|
11888
|
+
} catch {
|
|
11889
|
+
return emptySidecarMeta();
|
|
11772
11890
|
}
|
|
11891
|
+
return parseSidecarMeta(raw);
|
|
11892
|
+
}
|
|
11893
|
+
function parseSidecarMeta(raw) {
|
|
11773
11894
|
let parsed;
|
|
11774
11895
|
try {
|
|
11775
11896
|
parsed = JSON.parse(raw);
|
|
11776
11897
|
} catch {
|
|
11777
|
-
return
|
|
11898
|
+
return emptySidecarMeta();
|
|
11778
11899
|
}
|
|
11779
|
-
if (!parsed || typeof parsed !== "object") return
|
|
11900
|
+
if (!parsed || typeof parsed !== "object") return emptySidecarMeta();
|
|
11780
11901
|
const r = parsed;
|
|
11781
11902
|
const bridgeIds = Array.isArray(r.bridgeIds) ? r.bridgeIds.filter((b) => typeof b === "string" && b.length > 0) : [];
|
|
11782
11903
|
return {
|
|
@@ -11877,12 +11998,12 @@ async function computeSessionList(scopeAccountId) {
|
|
|
11877
11998
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
11878
11999
|
return { sessions: [], accountId: scopeAccountId };
|
|
11879
12000
|
}
|
|
11880
|
-
const projectsRoot =
|
|
12001
|
+
const projectsRoot = join20(configDir2, "projects");
|
|
11881
12002
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
11882
12003
|
const liveSessions = await fetchLiveSessions();
|
|
11883
12004
|
const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
|
|
11884
|
-
const userTitles =
|
|
11885
|
-
const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null :
|
|
12005
|
+
const userTitles = await loadUserTitlesAsync(accountDir);
|
|
12006
|
+
const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : validAccounts[0] ?? null;
|
|
11886
12007
|
let channelUsers = [];
|
|
11887
12008
|
if (account) {
|
|
11888
12009
|
try {
|
|
@@ -11921,8 +12042,8 @@ async function computeSessionList(scopeAccountId) {
|
|
|
11921
12042
|
let body;
|
|
11922
12043
|
let mtimeMs;
|
|
11923
12044
|
try {
|
|
11924
|
-
body =
|
|
11925
|
-
mtimeMs =
|
|
12045
|
+
body = await readFile4(path3, "utf8");
|
|
12046
|
+
mtimeMs = (await stat5(path3)).mtimeMs;
|
|
11926
12047
|
} catch {
|
|
11927
12048
|
continue;
|
|
11928
12049
|
}
|
|
@@ -11930,8 +12051,8 @@ async function computeSessionList(scopeAccountId) {
|
|
|
11930
12051
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
11931
12052
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
11932
12053
|
titleSourceCounts[resolved.source] += 1;
|
|
11933
|
-
const metaPath =
|
|
11934
|
-
const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } =
|
|
12054
|
+
const metaPath = join20(projectDir, `${sessionId}.meta.json`);
|
|
12055
|
+
const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } = await readSidecarMetaAsync(metaPath);
|
|
11935
12056
|
if (multiAccount) {
|
|
11936
12057
|
if (rowAccountId === null) untaggedCount += 1;
|
|
11937
12058
|
if (rowAccountId !== scopeAccountId) continue;
|
|
@@ -12333,7 +12454,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
12333
12454
|
|
|
12334
12455
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
12335
12456
|
import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync7, realpathSync as realpathSync5 } from "fs";
|
|
12336
|
-
import { basename as basename5, dirname as dirname6, join as
|
|
12457
|
+
import { basename as basename5, dirname as dirname6, join as join21, resolve as resolve16, sep as sep4 } from "path";
|
|
12337
12458
|
var ADMIN_UPLOAD_PATH = /\/uploads\/(?!public\/)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\//gi;
|
|
12338
12459
|
function adminAttachmentIds(text) {
|
|
12339
12460
|
const ids = [];
|
|
@@ -12346,7 +12467,7 @@ function adminAttachmentIds(text) {
|
|
|
12346
12467
|
function adminAttachmentsFromText(text, uploadsBase) {
|
|
12347
12468
|
const out = [];
|
|
12348
12469
|
for (const id of adminAttachmentIds(text)) {
|
|
12349
|
-
const meta = readAttachmentMeta(
|
|
12470
|
+
const meta = readAttachmentMeta(join21(uploadsBase, id));
|
|
12350
12471
|
if (meta) out.push(meta);
|
|
12351
12472
|
}
|
|
12352
12473
|
return out;
|
|
@@ -12396,7 +12517,7 @@ function claudeUploadAttachmentsFromText(text, sessionId) {
|
|
|
12396
12517
|
function readSidecar(dir, attachmentId) {
|
|
12397
12518
|
let parsed;
|
|
12398
12519
|
try {
|
|
12399
|
-
parsed = JSON.parse(readFileSync20(
|
|
12520
|
+
parsed = JSON.parse(readFileSync20(join21(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
12400
12521
|
} catch {
|
|
12401
12522
|
return null;
|
|
12402
12523
|
}
|
|
@@ -12425,7 +12546,7 @@ function listSessionAttachmentsInDir(dir) {
|
|
|
12425
12546
|
}
|
|
12426
12547
|
const sidecars = [];
|
|
12427
12548
|
for (const name of entries2) {
|
|
12428
|
-
const sidecar = readSidecar(
|
|
12549
|
+
const sidecar = readSidecar(join21(dir, name), name);
|
|
12429
12550
|
if (sidecar) sidecars.push(sidecar);
|
|
12430
12551
|
}
|
|
12431
12552
|
sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
|
|
@@ -12585,14 +12706,14 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
12585
12706
|
}
|
|
12586
12707
|
const cfg = claudeConfigDir();
|
|
12587
12708
|
if (!cfg) return c.json({ conversations: [] });
|
|
12588
|
-
const projectsRoot =
|
|
12709
|
+
const projectsRoot = join22(cfg, "projects");
|
|
12589
12710
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
12590
12711
|
const rows = [];
|
|
12591
12712
|
let sessionRowsExcludedUntagged = 0;
|
|
12592
12713
|
for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
|
|
12593
12714
|
const sessionId = basename6(path3).replace(/\.jsonl$/, "");
|
|
12594
12715
|
const projectDir = dirname7(path3);
|
|
12595
|
-
const meta = readSidecarMeta(
|
|
12716
|
+
const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
|
|
12596
12717
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
12597
12718
|
if (multiAccount) {
|
|
12598
12719
|
if (meta.accountId === null) sessionRowsExcludedUntagged += 1;
|
|
@@ -12723,7 +12844,7 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
12723
12844
|
const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
|
|
12724
12845
|
const cfg = claudeConfigDir();
|
|
12725
12846
|
if (!cfg) return { conversations: [] };
|
|
12726
|
-
const projectsRoot =
|
|
12847
|
+
const projectsRoot = join22(cfg, "projects");
|
|
12727
12848
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
12728
12849
|
const validAccounts = listValidAccounts();
|
|
12729
12850
|
const validIds = new Set(validAccounts.map((a) => a.accountId));
|
|
@@ -12732,7 +12853,7 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
12732
12853
|
for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
|
|
12733
12854
|
const sessionId = basename6(path3).replace(/\.jsonl$/, "");
|
|
12734
12855
|
const projectDir = dirname7(path3);
|
|
12735
|
-
const meta = readSidecarMeta(
|
|
12856
|
+
const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
|
|
12736
12857
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
12737
12858
|
if (meta.accountId === null || !validIds.has(meta.accountId)) continue;
|
|
12738
12859
|
let body = "";
|
|
@@ -12897,7 +13018,7 @@ function openTaskKey(turns) {
|
|
|
12897
13018
|
}
|
|
12898
13019
|
function readSubagentMeta(dir, hex) {
|
|
12899
13020
|
try {
|
|
12900
|
-
const m = JSON.parse(readFileSync21(
|
|
13021
|
+
const m = JSON.parse(readFileSync21(join22(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
12901
13022
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
12902
13023
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
12903
13024
|
}
|
|
@@ -12929,7 +13050,7 @@ function runActivityTick(c) {
|
|
|
12929
13050
|
let size = 0;
|
|
12930
13051
|
let mtimeMs = 0;
|
|
12931
13052
|
try {
|
|
12932
|
-
const st = statSync8(
|
|
13053
|
+
const st = statSync8(join22(c.subagentsDir, name));
|
|
12933
13054
|
size = st.size;
|
|
12934
13055
|
mtimeMs = st.mtimeMs;
|
|
12935
13056
|
} catch {
|
|
@@ -12974,11 +13095,11 @@ app5.get("/stream", requireAdminSession, (c) => {
|
|
|
12974
13095
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
12975
13096
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
12976
13097
|
const cfg = claudeConfigDir();
|
|
12977
|
-
const projectsRoot = cfg ? resolve17(
|
|
13098
|
+
const projectsRoot = cfg ? resolve17(join22(cfg, "projects")) : null;
|
|
12978
13099
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
12979
13100
|
return c.json({ error: "bad session reference" }, 400);
|
|
12980
13101
|
}
|
|
12981
|
-
const jsonlPath = resolve17(
|
|
13102
|
+
const jsonlPath = resolve17(join22(projectDir, `${sessionId}.jsonl`));
|
|
12982
13103
|
if (!jsonlPath.startsWith(projectsRoot + sep5)) {
|
|
12983
13104
|
return c.json({ error: "bad session reference" }, 400);
|
|
12984
13105
|
}
|
|
@@ -13005,7 +13126,7 @@ data: ${JSON.stringify(turn)}
|
|
|
13005
13126
|
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
13006
13127
|
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
13007
13128
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
13008
|
-
const subagentsDir = resolve17(
|
|
13129
|
+
const subagentsDir = resolve17(join22(projectDir, sessionId, "subagents"));
|
|
13009
13130
|
console.log(
|
|
13010
13131
|
`[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync17(subagentsDir)}`
|
|
13011
13132
|
);
|
|
@@ -13134,7 +13255,7 @@ app5.get("/directives", requireAdminSession, (c) => {
|
|
|
13134
13255
|
const pid = Number(pidPart);
|
|
13135
13256
|
let len = 0;
|
|
13136
13257
|
try {
|
|
13137
|
-
len = statSync8(
|
|
13258
|
+
len = statSync8(join22(dir, name)).size;
|
|
13138
13259
|
} catch {
|
|
13139
13260
|
}
|
|
13140
13261
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -13149,7 +13270,7 @@ app5.get("/directive", requireAdminSession, (c) => {
|
|
|
13149
13270
|
}
|
|
13150
13271
|
const dir = directiveStoreDir(sessionId);
|
|
13151
13272
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
13152
|
-
const path3 = resolve17(
|
|
13273
|
+
const path3 = resolve17(join22(dir, name));
|
|
13153
13274
|
if (!path3.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
|
|
13154
13275
|
let body;
|
|
13155
13276
|
try {
|
|
@@ -13207,7 +13328,7 @@ app5.get("/store-stream", requireAdminSession, (c) => {
|
|
|
13207
13328
|
console.log(`[wa-reader] op=store-quote msgId=${r.msgKeyId} quoted=${!!q2}`);
|
|
13208
13329
|
}
|
|
13209
13330
|
if (r.attachmentId) {
|
|
13210
|
-
const meta = readAttachmentMeta(
|
|
13331
|
+
const meta = readAttachmentMeta(join22(uploadsBase, r.attachmentId));
|
|
13211
13332
|
if (meta) return { ...turn, attachments: [meta] };
|
|
13212
13333
|
}
|
|
13213
13334
|
return turn;
|
|
@@ -13588,7 +13709,7 @@ var whatsapp_reader_default = app5;
|
|
|
13588
13709
|
|
|
13589
13710
|
// server/routes/public-reader.ts
|
|
13590
13711
|
import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
|
|
13591
|
-
import { basename as basename7, dirname as dirname8, join as
|
|
13712
|
+
import { basename as basename7, dirname as dirname8, join as join23, resolve as resolve18, sep as sep6 } from "path";
|
|
13592
13713
|
|
|
13593
13714
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
13594
13715
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -13662,10 +13783,10 @@ function enumeratePublicRows() {
|
|
|
13662
13783
|
const cfg = claudeConfigDir();
|
|
13663
13784
|
if (!cfg) return [];
|
|
13664
13785
|
const rows = [];
|
|
13665
|
-
for (const { path: path3 } of enumerateJsonls(
|
|
13786
|
+
for (const { path: path3 } of enumerateJsonls(join23(cfg, "projects"))) {
|
|
13666
13787
|
const sessionId = basename7(path3).replace(/\.jsonl$/, "");
|
|
13667
13788
|
const projectDir = dirname8(path3);
|
|
13668
|
-
const meta = readSidecarMeta(
|
|
13789
|
+
const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
|
|
13669
13790
|
rows.push({
|
|
13670
13791
|
sessionId,
|
|
13671
13792
|
projectDir,
|
|
@@ -13741,15 +13862,15 @@ app6.get("/stream", (c) => {
|
|
|
13741
13862
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
13742
13863
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
13743
13864
|
const cfg = claudeConfigDir();
|
|
13744
|
-
const projectsRoot = cfg ? resolve18(
|
|
13865
|
+
const projectsRoot = cfg ? resolve18(join23(cfg, "projects")) : null;
|
|
13745
13866
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
13746
13867
|
return c.json({ error: "bad session reference" }, 400);
|
|
13747
13868
|
}
|
|
13748
|
-
const jsonlPath = resolve18(
|
|
13869
|
+
const jsonlPath = resolve18(join23(projectDir, `${sessionId}.jsonl`));
|
|
13749
13870
|
if (!jsonlPath.startsWith(projectsRoot + sep6)) {
|
|
13750
13871
|
return c.json({ error: "bad session reference" }, 400);
|
|
13751
13872
|
}
|
|
13752
|
-
const meta = readSidecarMeta(
|
|
13873
|
+
const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
|
|
13753
13874
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
13754
13875
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
13755
13876
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -13886,16 +14007,16 @@ var public_reader_default = app6;
|
|
|
13886
14007
|
|
|
13887
14008
|
// server/routes/webchat.ts
|
|
13888
14009
|
import { basename as basename8, dirname as dirname9 } from "path";
|
|
13889
|
-
import { join as
|
|
14010
|
+
import { join as join26 } from "path";
|
|
13890
14011
|
import { existsSync as existsSync19, readdirSync as readdirSync17, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
13891
14012
|
|
|
13892
14013
|
// server/canonical-webchat-override.ts
|
|
13893
14014
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync7, renameSync as renameSync2 } from "fs";
|
|
13894
|
-
import { join as
|
|
14015
|
+
import { join as join24 } from "path";
|
|
13895
14016
|
var FILE = "canonical-webchat-session.json";
|
|
13896
14017
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
13897
14018
|
function canonicalOverridePath(accountDir) {
|
|
13898
|
-
return
|
|
14019
|
+
return join24(accountDir, FILE);
|
|
13899
14020
|
}
|
|
13900
14021
|
function readRaw(accountDir) {
|
|
13901
14022
|
try {
|
|
@@ -13931,6 +14052,31 @@ function writeCanonicalOverrideId(accountDir, userId, sessionId) {
|
|
|
13931
14052
|
renameSync2(tmp, path3);
|
|
13932
14053
|
}
|
|
13933
14054
|
|
|
14055
|
+
// server/routes/admin/_account-scope.ts
|
|
14056
|
+
function accountDirForSession(cacheKey) {
|
|
14057
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
14058
|
+
if (!accountId) return null;
|
|
14059
|
+
const match = listValidAccounts().find((a) => a.accountId === accountId);
|
|
14060
|
+
return match ? { accountId, accountDir: match.accountDir, config: match.config } : null;
|
|
14061
|
+
}
|
|
14062
|
+
function validateAccountId2(accountId) {
|
|
14063
|
+
if (!accountId) return null;
|
|
14064
|
+
const match = listValidAccounts().find((a) => a.accountId === accountId);
|
|
14065
|
+
return match ? { accountId, accountDir: match.accountDir, config: match.config } : null;
|
|
14066
|
+
}
|
|
14067
|
+
async function authorizeAccountWrite(c, accountId) {
|
|
14068
|
+
const remote = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
14069
|
+
const peerIsLoopback = remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1";
|
|
14070
|
+
if (peerIsLoopback && !c.req.header("x-forwarded-for")) return { ok: true, via: "on-device" };
|
|
14071
|
+
const { fingerprint, signedSessionToken } = await resolveCacheKey(c);
|
|
14072
|
+
if (!fingerprint || !validateSession(fingerprint, "admin", signedSessionToken).ok) {
|
|
14073
|
+
return { ok: false, reason: "no-session" };
|
|
14074
|
+
}
|
|
14075
|
+
const acct = accountDirForSession(fingerprint);
|
|
14076
|
+
if (!acct || acct.accountId !== accountId) return { ok: false, reason: "account-mismatch" };
|
|
14077
|
+
return { ok: true, via: "session" };
|
|
14078
|
+
}
|
|
14079
|
+
|
|
13934
14080
|
// ../lib/models/src/index.ts
|
|
13935
14081
|
var OPUS_MODEL = "claude-opus-5[1m]";
|
|
13936
14082
|
var SONNET_MODEL = "claude-sonnet-5";
|
|
@@ -13975,7 +14121,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
13975
14121
|
|
|
13976
14122
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
13977
14123
|
import { existsSync as existsSync18, mkdirSync as mkdirSync4, readdirSync as readdirSync16, readFileSync as readFileSync24, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
13978
|
-
import { join as
|
|
14124
|
+
import { join as join25 } from "path";
|
|
13979
14125
|
function escapeRegExp(s) {
|
|
13980
14126
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13981
14127
|
}
|
|
@@ -13983,7 +14129,7 @@ function createSidecarStore(config) {
|
|
|
13983
14129
|
const { suffix, validate: validate2 } = config;
|
|
13984
14130
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
13985
14131
|
function pathFor(sessionsDir, id) {
|
|
13986
|
-
return
|
|
14132
|
+
return join25(sessionsDir, `${id}${suffix}`);
|
|
13987
14133
|
}
|
|
13988
14134
|
function write(sessionsDir, id, record) {
|
|
13989
14135
|
mkdirSync4(sessionsDir, { recursive: true });
|
|
@@ -14027,7 +14173,7 @@ function createSidecarStore(config) {
|
|
|
14027
14173
|
const out = [];
|
|
14028
14174
|
for (const name of names) {
|
|
14029
14175
|
if (!suffixRe.test(name)) continue;
|
|
14030
|
-
const path3 =
|
|
14176
|
+
const path3 = join25(sessionsDir, name);
|
|
14031
14177
|
let raw;
|
|
14032
14178
|
try {
|
|
14033
14179
|
raw = readFileSync24(path3, "utf8");
|
|
@@ -14104,13 +14250,13 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
14104
14250
|
function locateSession(sessionId) {
|
|
14105
14251
|
const dir = findSessionProjectDir(sessionId);
|
|
14106
14252
|
if (!dir) return { projectDir: null, channel: null, accountId: null };
|
|
14107
|
-
const meta = readSidecarMeta(
|
|
14253
|
+
const meta = readSidecarMeta(join26(dir, `${sessionId}.meta.json`));
|
|
14108
14254
|
return { projectDir: dir, channel: meta.channel, accountId: meta.accountId };
|
|
14109
14255
|
}
|
|
14110
14256
|
function locateSidecar(sessionId) {
|
|
14111
14257
|
const cfg = claudeConfigDir();
|
|
14112
14258
|
if (!cfg) return null;
|
|
14113
|
-
const projectsRoot =
|
|
14259
|
+
const projectsRoot = join26(cfg, "projects");
|
|
14114
14260
|
let slugs;
|
|
14115
14261
|
try {
|
|
14116
14262
|
slugs = readdirSync17(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -14118,7 +14264,7 @@ function locateSidecar(sessionId) {
|
|
|
14118
14264
|
return null;
|
|
14119
14265
|
}
|
|
14120
14266
|
for (const slug of slugs) {
|
|
14121
|
-
const metaPath =
|
|
14267
|
+
const metaPath = join26(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
14122
14268
|
if (existsSync19(metaPath)) return readSidecarMeta(metaPath);
|
|
14123
14269
|
}
|
|
14124
14270
|
return null;
|
|
@@ -14128,7 +14274,7 @@ function readTargetOwner(sessionId) {
|
|
|
14128
14274
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
14129
14275
|
const { projectDir } = locateSession(sessionId);
|
|
14130
14276
|
if (projectDir !== null) {
|
|
14131
|
-
return { found: true, owner: readSidecarMeta(
|
|
14277
|
+
return { found: true, owner: readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
14132
14278
|
}
|
|
14133
14279
|
return { found: false, owner: null };
|
|
14134
14280
|
}
|
|
@@ -14136,7 +14282,7 @@ function readSourceRowMeta(sessionId) {
|
|
|
14136
14282
|
const sidecar = locateSidecar(sessionId);
|
|
14137
14283
|
if (sidecar !== null) return sidecar;
|
|
14138
14284
|
const { projectDir } = locateSession(sessionId);
|
|
14139
|
-
if (projectDir !== null) return readSidecarMeta(
|
|
14285
|
+
if (projectDir !== null) return readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`));
|
|
14140
14286
|
return null;
|
|
14141
14287
|
}
|
|
14142
14288
|
function ownedByRequester(owner, requesterUserId, primaryUserId) {
|
|
@@ -14149,7 +14295,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
14149
14295
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
14150
14296
|
if (projectDir === null) return null;
|
|
14151
14297
|
try {
|
|
14152
|
-
return statSync10(
|
|
14298
|
+
return statSync10(join26(projectDir, `${sessionId}.jsonl`)).size;
|
|
14153
14299
|
} catch {
|
|
14154
14300
|
return null;
|
|
14155
14301
|
}
|
|
@@ -14252,15 +14398,7 @@ async function managerInterrupt(sessionId, trigger, escalate = false) {
|
|
|
14252
14398
|
}
|
|
14253
14399
|
}
|
|
14254
14400
|
var MODEL_ID_PATTERN = /^claude-[a-z0-9][a-z0-9.-]*(\[1m\])?$/;
|
|
14255
|
-
function readLevers(
|
|
14256
|
-
let account = preResolved;
|
|
14257
|
-
if (account === void 0) {
|
|
14258
|
-
try {
|
|
14259
|
-
account = resolveAccount();
|
|
14260
|
-
} catch {
|
|
14261
|
-
return { leverModel: null, leverEffort: null, leverMode: null };
|
|
14262
|
-
}
|
|
14263
|
-
}
|
|
14401
|
+
function readLevers(account) {
|
|
14264
14402
|
if (!account) return { leverModel: null, leverEffort: null, leverMode: null };
|
|
14265
14403
|
const model = account.config.adminModel;
|
|
14266
14404
|
const effort = account.config.effort;
|
|
@@ -14285,10 +14423,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
|
|
|
14285
14423
|
const cfg = claudeConfigDir();
|
|
14286
14424
|
if (!cfg) return null;
|
|
14287
14425
|
let best = null;
|
|
14288
|
-
for (const { path: path3, isSubagent, archived } of enumerateJsonls(
|
|
14426
|
+
for (const { path: path3, isSubagent, archived } of enumerateJsonls(join26(cfg, "projects"))) {
|
|
14289
14427
|
if (isSubagent || archived) continue;
|
|
14290
14428
|
const id = basename8(path3).slice(0, -".jsonl".length);
|
|
14291
|
-
const meta = readSidecarMeta(
|
|
14429
|
+
const meta = readSidecarMeta(join26(dirname9(path3), `${id}.meta.json`));
|
|
14292
14430
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
14293
14431
|
if (multiAccount && meta.accountId !== scopeAccountId) continue;
|
|
14294
14432
|
let mtimeMs;
|
|
@@ -14526,12 +14664,7 @@ ${note}` : note;
|
|
|
14526
14664
|
const sendId = sendIdFromResolve ?? ++sendSeq;
|
|
14527
14665
|
let turnSessionId = deliverySessionId;
|
|
14528
14666
|
if (turnSessionId === void 0) {
|
|
14529
|
-
|
|
14530
|
-
try {
|
|
14531
|
-
canonAccount = resolveAccount();
|
|
14532
|
-
} catch {
|
|
14533
|
-
canonAccount = null;
|
|
14534
|
-
}
|
|
14667
|
+
const canonAccount = scopeAccountId ? validateAccountId2(scopeAccountId) : null;
|
|
14535
14668
|
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null, requesterUserId, primaryUserId, scopeAccountId, multiAccount).sessionId;
|
|
14536
14669
|
}
|
|
14537
14670
|
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
@@ -14591,17 +14724,13 @@ ${note}` : note;
|
|
|
14591
14724
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${JSON.stringify(value)} reason=invalid-value`);
|
|
14592
14725
|
return c.json({ error: `invalid ${op} value` }, 400);
|
|
14593
14726
|
}
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
account = resolveAccount();
|
|
14597
|
-
} catch {
|
|
14598
|
-
account = null;
|
|
14599
|
-
}
|
|
14727
|
+
const cacheKey = c.get("cacheKey");
|
|
14728
|
+
const account = cacheKey ? accountDirForSession(cacheKey) : null;
|
|
14600
14729
|
if (!account) {
|
|
14601
|
-
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-
|
|
14730
|
+
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} accountId=none reason=no-account-for-session`);
|
|
14602
14731
|
return c.json({ error: "account unresolved" }, 503);
|
|
14603
14732
|
}
|
|
14604
|
-
const accountJsonPath =
|
|
14733
|
+
const accountJsonPath = join26(account.accountDir, "account.json");
|
|
14605
14734
|
try {
|
|
14606
14735
|
const parsed = JSON.parse(readFileSync25(accountJsonPath, "utf8"));
|
|
14607
14736
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -14616,7 +14745,7 @@ ${note}` : note;
|
|
|
14616
14745
|
return c.json({ error: "persist failed" }, 500);
|
|
14617
14746
|
}
|
|
14618
14747
|
const settingsApplied = await reapplyLeversViaManager();
|
|
14619
|
-
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
14748
|
+
console.log(`[webchat:settings] op=${op} outcome=accepted accountId=${account.accountId.slice(0, 8)} value=${value} settingsApplied=${settingsApplied}`);
|
|
14620
14749
|
return c.json({ ok: true, settingsApplied });
|
|
14621
14750
|
});
|
|
14622
14751
|
app70.get("/session", requireAdminSession, async (c) => {
|
|
@@ -14649,7 +14778,7 @@ ${note}` : note;
|
|
|
14649
14778
|
const cfg2 = claudeConfigDir();
|
|
14650
14779
|
if (cfg2) {
|
|
14651
14780
|
const source2 = resolveBridgeSource(
|
|
14652
|
-
|
|
14781
|
+
join26(cfg2, "sessions"),
|
|
14653
14782
|
target,
|
|
14654
14783
|
(id) => locateSession(id).projectDir !== null
|
|
14655
14784
|
);
|
|
@@ -14662,14 +14791,9 @@ ${note}` : note;
|
|
|
14662
14791
|
}
|
|
14663
14792
|
const known = resolvedProjectDir !== null || sessionSidecarExists(target);
|
|
14664
14793
|
const indicators2 = await fetchComposerIndicators(target);
|
|
14665
|
-
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers() });
|
|
14666
|
-
}
|
|
14667
|
-
let account;
|
|
14668
|
-
try {
|
|
14669
|
-
account = resolveAccount();
|
|
14670
|
-
} catch {
|
|
14671
|
-
account = null;
|
|
14794
|
+
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers(scopeAccountId ? validateAccountId2(scopeAccountId) : null) });
|
|
14672
14795
|
}
|
|
14796
|
+
const account = scopeAccountId ? validateAccountId2(scopeAccountId) : null;
|
|
14673
14797
|
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null, requesterUserId, primaryUserId, scopeAccountId, multiAccount);
|
|
14674
14798
|
if (requesterUserId === null) {
|
|
14675
14799
|
console.error(`[webchat:inbound] op=session-resolve-no-identity key=${sessionId.slice(0, 8)}`);
|
|
@@ -14681,7 +14805,7 @@ ${note}` : note;
|
|
|
14681
14805
|
const cfg = claudeConfigDir();
|
|
14682
14806
|
let projectDir = null;
|
|
14683
14807
|
if (cfg) {
|
|
14684
|
-
for (const { path: path3 } of enumerateJsonls(
|
|
14808
|
+
for (const { path: path3 } of enumerateJsonls(join26(cfg, "projects"))) {
|
|
14685
14809
|
if (basename8(path3) === `${sessionId}.jsonl`) {
|
|
14686
14810
|
projectDir = dirname9(path3);
|
|
14687
14811
|
break;
|
|
@@ -14689,7 +14813,7 @@ ${note}` : note;
|
|
|
14689
14813
|
}
|
|
14690
14814
|
}
|
|
14691
14815
|
if (source === "latest" && requesterUserId !== null) {
|
|
14692
|
-
const owner = readSidecarMeta(
|
|
14816
|
+
const owner = readSidecarMeta(join26(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
14693
14817
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
14694
14818
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
14695
14819
|
}
|
|
@@ -14722,7 +14846,7 @@ import { resolve as resolve19 } from "path";
|
|
|
14722
14846
|
|
|
14723
14847
|
// app/lib/claude-agent/specialist-roster.ts
|
|
14724
14848
|
import { existsSync as existsSync20, readFileSync as readFileSync26, readdirSync as readdirSync18 } from "fs";
|
|
14725
|
-
import { join as
|
|
14849
|
+
import { join as join27 } from "path";
|
|
14726
14850
|
function field(fm, name) {
|
|
14727
14851
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
14728
14852
|
if (!m) return null;
|
|
@@ -14741,7 +14865,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
14741
14865
|
if (!file.endsWith(".md")) continue;
|
|
14742
14866
|
let raw;
|
|
14743
14867
|
try {
|
|
14744
|
-
raw = readFileSync26(
|
|
14868
|
+
raw = readFileSync26(join27(specialistsDir, file), "utf-8");
|
|
14745
14869
|
} catch (err) {
|
|
14746
14870
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
14747
14871
|
continue;
|
|
@@ -14858,7 +14982,7 @@ var webchat_greeting_default = app7;
|
|
|
14858
14982
|
|
|
14859
14983
|
// server/routes/telegram.ts
|
|
14860
14984
|
import { homedir as homedir2 } from "os";
|
|
14861
|
-
import { resolve as resolve20, join as
|
|
14985
|
+
import { resolve as resolve20, join as join28 } from "path";
|
|
14862
14986
|
import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
|
|
14863
14987
|
|
|
14864
14988
|
// app/lib/telegram/gateway/instance.ts
|
|
@@ -14918,7 +15042,7 @@ function routeTelegramUpdate(input) {
|
|
|
14918
15042
|
var TAG30 = "[telegram-inbound]";
|
|
14919
15043
|
function configDirName() {
|
|
14920
15044
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
14921
|
-
const brandPath =
|
|
15045
|
+
const brandPath = join28(platformRoot5, "config", "brand.json");
|
|
14922
15046
|
if (existsSync21(brandPath)) {
|
|
14923
15047
|
try {
|
|
14924
15048
|
return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -15007,16 +15131,16 @@ app8.post("/", async (c) => {
|
|
|
15007
15131
|
var telegram_default = app8;
|
|
15008
15132
|
|
|
15009
15133
|
// server/routes/quickbooks.ts
|
|
15010
|
-
import { join as
|
|
15134
|
+
import { join as join29 } from "path";
|
|
15011
15135
|
import { existsSync as existsSync22, readFileSync as readFileSync28, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5, rmSync, renameSync as renameSync5 } from "fs";
|
|
15012
15136
|
var TAG31 = "[quickbooks]";
|
|
15013
15137
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
15014
15138
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
15015
15139
|
function pendingPath(accountDir, state) {
|
|
15016
|
-
return
|
|
15140
|
+
return join29(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
15017
15141
|
}
|
|
15018
15142
|
function storePath(accountDir) {
|
|
15019
|
-
return
|
|
15143
|
+
return join29(accountDir, "secrets", "quickbooks.json");
|
|
15020
15144
|
}
|
|
15021
15145
|
async function completeConsent(args) {
|
|
15022
15146
|
const { accountDir, code, realmId } = args;
|
|
@@ -15083,7 +15207,7 @@ async function completeConsent(args) {
|
|
|
15083
15207
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
15084
15208
|
lastRefresh: now
|
|
15085
15209
|
};
|
|
15086
|
-
mkdirSync5(
|
|
15210
|
+
mkdirSync5(join29(accountDir, "secrets"), { recursive: true });
|
|
15087
15211
|
writeFileSync10(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
15088
15212
|
const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
15089
15213
|
console.error(`${TAG31} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
@@ -15125,7 +15249,7 @@ function claudeBin() {
|
|
|
15125
15249
|
}
|
|
15126
15250
|
|
|
15127
15251
|
// server/routes/onboarding.ts
|
|
15128
|
-
import { dirname as dirname11, join as
|
|
15252
|
+
import { dirname as dirname11, join as join31 } from "path";
|
|
15129
15253
|
|
|
15130
15254
|
// app/lib/claude-keychain.ts
|
|
15131
15255
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -15255,7 +15379,7 @@ function readHostCredsBlob(service) {
|
|
|
15255
15379
|
|
|
15256
15380
|
// ../lib/admins-write/src/index.ts
|
|
15257
15381
|
import { existsSync as existsSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync11, renameSync as renameSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync11, appendFileSync as appendFileSync3 } from "fs";
|
|
15258
|
-
import { dirname as dirname10, join as
|
|
15382
|
+
import { dirname as dirname10, join as join30 } from "path";
|
|
15259
15383
|
function id8(value) {
|
|
15260
15384
|
return value.slice(0, 8);
|
|
15261
15385
|
}
|
|
@@ -15328,7 +15452,7 @@ function writeAdminEntry(input) {
|
|
|
15328
15452
|
return result;
|
|
15329
15453
|
}
|
|
15330
15454
|
try {
|
|
15331
|
-
const accountJsonPath =
|
|
15455
|
+
const accountJsonPath = join30(input.accountDir, "account.json");
|
|
15332
15456
|
if (!existsSync23(accountJsonPath)) {
|
|
15333
15457
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
15334
15458
|
}
|
|
@@ -15376,13 +15500,13 @@ function computeAdminStoreDivergence(input) {
|
|
|
15376
15500
|
}
|
|
15377
15501
|
for (const entry of entries2) {
|
|
15378
15502
|
if (entry.startsWith(".")) continue;
|
|
15379
|
-
const accountDir =
|
|
15503
|
+
const accountDir = join30(input.accountsDir, entry);
|
|
15380
15504
|
try {
|
|
15381
15505
|
if (!statSync11(accountDir).isDirectory()) continue;
|
|
15382
15506
|
} catch {
|
|
15383
15507
|
continue;
|
|
15384
15508
|
}
|
|
15385
|
-
const accountJsonPath =
|
|
15509
|
+
const accountJsonPath = join30(accountDir, "account.json");
|
|
15386
15510
|
if (!existsSync23(accountJsonPath)) continue;
|
|
15387
15511
|
let admins = [];
|
|
15388
15512
|
try {
|
|
@@ -15560,7 +15684,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
15560
15684
|
});
|
|
15561
15685
|
persistKeychainService(
|
|
15562
15686
|
writebackResult,
|
|
15563
|
-
(service) => writeFileSync12(
|
|
15687
|
+
(service) => writeFileSync12(join31(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
15564
15688
|
(line) => console.log(line)
|
|
15565
15689
|
);
|
|
15566
15690
|
if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
|
|
@@ -15826,8 +15950,8 @@ var onboarding_default = app10;
|
|
|
15826
15950
|
|
|
15827
15951
|
// server/routes/client-error.ts
|
|
15828
15952
|
import { appendFileSync as appendFileSync4, existsSync as existsSync25, renameSync as renameSync8, statSync as statSync12 } from "fs";
|
|
15829
|
-
import { join as
|
|
15830
|
-
var CLIENT_ERRORS_LOG =
|
|
15953
|
+
import { join as join32 } from "path";
|
|
15954
|
+
var CLIENT_ERRORS_LOG = join32(LOG_DIR, "client-errors.log");
|
|
15831
15955
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
15832
15956
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
15833
15957
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -15971,7 +16095,7 @@ app11.post("/", async (c) => {
|
|
|
15971
16095
|
const safe = typeof v === "string" ? truncate(v, 200) : typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v).slice(0, 200);
|
|
15972
16096
|
return `${k}=${safe}`;
|
|
15973
16097
|
}).join(" ");
|
|
15974
|
-
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set(["stream-log-click", "pwa", "graph-settle"]);
|
|
16098
|
+
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set(["stream-log-click", "pwa", "graph-settle", "dashboard-load"]);
|
|
15975
16099
|
if (TAGGED_PREFIX_SOURCES.has(source)) {
|
|
15976
16100
|
console.log(
|
|
15977
16101
|
`[${source}] ts=${ts} ip=${ip} version=${version || "unknown"}${extra ? " " + extra : ""}`
|
|
@@ -16026,7 +16150,7 @@ async function resolveUserIdentity(accountId, userId) {
|
|
|
16026
16150
|
return { userName, avatar: null };
|
|
16027
16151
|
}
|
|
16028
16152
|
async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
|
|
16029
|
-
const account =
|
|
16153
|
+
const account = validateAccountId2(accountId);
|
|
16030
16154
|
const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
|
|
16031
16155
|
const signedSessionToken = randomUUID9();
|
|
16032
16156
|
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
@@ -16102,11 +16226,11 @@ app12.get("/", async (c) => {
|
|
|
16102
16226
|
if (!accountId) {
|
|
16103
16227
|
return c.json({ error: "Session has no account binding" }, 401);
|
|
16104
16228
|
}
|
|
16105
|
-
const account =
|
|
16229
|
+
const account = validateAccountId2(accountId);
|
|
16106
16230
|
const thinkingView = account?.config.thinkingView ?? "default";
|
|
16107
16231
|
const businessName = await fetchAccountName(accountId) || void 0;
|
|
16108
16232
|
const role = getRoleForSession(cacheKey);
|
|
16109
|
-
console.log(`[admin-session] role=${role ?? "null"} cacheKey=${cacheKey.slice(0, 8)} phase=restore`);
|
|
16233
|
+
console.log(`[admin-session] role=${role ?? "null"} accountId=${accountId.slice(0, 8)} cacheKey=${cacheKey.slice(0, 8)} phase=restore`);
|
|
16110
16234
|
const restoredUserId = getUserIdForSession(cacheKey);
|
|
16111
16235
|
let restoredUserName = getUserNameForSession(cacheKey);
|
|
16112
16236
|
let restoredAvatar = null;
|
|
@@ -16216,12 +16340,12 @@ import { resolve as resolve21, basename as basename9 } from "path";
|
|
|
16216
16340
|
|
|
16217
16341
|
// app/lib/logs-read-resolve.ts
|
|
16218
16342
|
import { existsSync as existsSync26 } from "fs";
|
|
16219
|
-
import { join as
|
|
16343
|
+
import { join as join33 } from "path";
|
|
16220
16344
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
16221
16345
|
const tried = [filename];
|
|
16222
16346
|
const hits = [];
|
|
16223
16347
|
for (const dir of logDirs) {
|
|
16224
|
-
const fullPath =
|
|
16348
|
+
const fullPath = join33(dir, filename);
|
|
16225
16349
|
if (existsSync26(fullPath)) {
|
|
16226
16350
|
hits.push({ path: fullPath, dir });
|
|
16227
16351
|
}
|
|
@@ -16238,10 +16362,7 @@ app14.get("/", async (c) => {
|
|
|
16238
16362
|
const sessionIdParam = c.req.query("sessionId");
|
|
16239
16363
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
16240
16364
|
const download = c.req.query("download") === "1";
|
|
16241
|
-
const
|
|
16242
|
-
const accountLogDir = account ? resolve21(account.accountDir, "logs") : null;
|
|
16243
|
-
const logDirs = [];
|
|
16244
|
-
if (accountLogDir) logDirs.push(accountLogDir);
|
|
16365
|
+
const logDirs = listValidAccounts().slice().sort((a, b) => a.accountId.localeCompare(b.accountId)).map((a) => resolve21(a.accountDir, "logs"));
|
|
16245
16366
|
logDirs.push(LOG_DIR);
|
|
16246
16367
|
if (fileParam) {
|
|
16247
16368
|
const safe = basename9(fileParam);
|
|
@@ -16257,7 +16378,7 @@ app14.get("/", async (c) => {
|
|
|
16257
16378
|
"Content-Length": String(buffer.byteLength)
|
|
16258
16379
|
};
|
|
16259
16380
|
if (download) headers["Content-Disposition"] = `attachment; filename="${safe}"`;
|
|
16260
|
-
console.info(`[stream-log-download] file=${safe} bytesServed=${buffer.byteLength} onDiskBytes=${onDiskBytes}`);
|
|
16381
|
+
console.info(`[stream-log-download] file=${safe} dir=${dir} bytesServed=${buffer.byteLength} onDiskBytes=${onDiskBytes}`);
|
|
16261
16382
|
return new Response(buffer, { headers });
|
|
16262
16383
|
} catch (err) {
|
|
16263
16384
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -16322,7 +16443,7 @@ app14.get("/", async (c) => {
|
|
|
16322
16443
|
"Content-Length": String(buffer.byteLength)
|
|
16323
16444
|
};
|
|
16324
16445
|
if (download) headers["Content-Disposition"] = `attachment; filename="${filename}"`;
|
|
16325
|
-
console.info(`[stream-log-download] file=${filename} bytesServed=${buffer.byteLength} onDiskBytes=${onDiskBytes}`);
|
|
16446
|
+
console.info(`[stream-log-download] file=${filename} dir=${hit.dir} bytesServed=${buffer.byteLength} onDiskBytes=${onDiskBytes}`);
|
|
16326
16447
|
return new Response(buffer, { headers });
|
|
16327
16448
|
} catch (err) {
|
|
16328
16449
|
const reason2 = err instanceof Error ? err.message : String(err);
|
|
@@ -16379,7 +16500,12 @@ var logs_default = app14;
|
|
|
16379
16500
|
// server/routes/admin/claude-info.ts
|
|
16380
16501
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
16381
16502
|
var app15 = new Hono();
|
|
16382
|
-
app15.get("/", (c) => {
|
|
16503
|
+
app15.get("/", requireAdminSession, (c) => {
|
|
16504
|
+
const account = accountDirForSession(c.var.cacheKey);
|
|
16505
|
+
if (!account) {
|
|
16506
|
+
console.error("[admin/claude-info] auth-rejected reason=no-account-for-session accountId=none");
|
|
16507
|
+
return c.json({ error: "no account for session", reason: "no-account-for-session" }, 401);
|
|
16508
|
+
}
|
|
16383
16509
|
const claudeEnv = { ...process.env };
|
|
16384
16510
|
let version = "unknown";
|
|
16385
16511
|
try {
|
|
@@ -16387,21 +16513,21 @@ app15.get("/", (c) => {
|
|
|
16387
16513
|
version = raw.trim().replace(" (Claude Code)", "");
|
|
16388
16514
|
} catch {
|
|
16389
16515
|
}
|
|
16390
|
-
let
|
|
16516
|
+
let claudeAccount = {};
|
|
16391
16517
|
try {
|
|
16392
16518
|
const raw = execFileSync5(claudeBin(), ["auth", "status"], { env: claudeEnv, encoding: "utf-8", timeout: 5e3 });
|
|
16393
|
-
|
|
16519
|
+
claudeAccount = JSON.parse(raw);
|
|
16394
16520
|
} catch {
|
|
16395
16521
|
}
|
|
16396
|
-
const
|
|
16397
|
-
const
|
|
16398
|
-
|
|
16399
|
-
return c.json({ version, account, model, thinkingView });
|
|
16522
|
+
const model = account.config.adminModel ?? "unknown";
|
|
16523
|
+
const thinkingView = account.config.thinkingView ?? "default";
|
|
16524
|
+
console.log(`[admin/claude-info] op=read accountId=${account.accountId.slice(0, 8)} model=${model}`);
|
|
16525
|
+
return c.json({ version, account: claudeAccount, model, thinkingView });
|
|
16400
16526
|
});
|
|
16401
16527
|
var claude_info_default = app15;
|
|
16402
16528
|
|
|
16403
16529
|
// server/routes/admin/attachment.ts
|
|
16404
|
-
import { readFile as
|
|
16530
|
+
import { readFile as readFile5, readdir as readdir2 } from "fs/promises";
|
|
16405
16531
|
import { existsSync as existsSync28 } from "fs";
|
|
16406
16532
|
import { resolve as resolve22 } from "path";
|
|
16407
16533
|
var app16 = new Hono();
|
|
@@ -16450,7 +16576,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16450
16576
|
}
|
|
16451
16577
|
let meta;
|
|
16452
16578
|
try {
|
|
16453
|
-
meta = JSON.parse(await
|
|
16579
|
+
meta = JSON.parse(await readFile5(metaPath, "utf-8"));
|
|
16454
16580
|
} catch {
|
|
16455
16581
|
return new Response("Not found", { status: 404 });
|
|
16456
16582
|
}
|
|
@@ -16460,7 +16586,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16460
16586
|
return new Response("Not found", { status: 404 });
|
|
16461
16587
|
}
|
|
16462
16588
|
const filePath = resolve22(dir, dataFile);
|
|
16463
|
-
const buffer = await
|
|
16589
|
+
const buffer = await readFile5(filePath);
|
|
16464
16590
|
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
16465
16591
|
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
16466
16592
|
if (!inlineSafe) {
|
|
@@ -16478,7 +16604,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16478
16604
|
var attachment_default = app16;
|
|
16479
16605
|
|
|
16480
16606
|
// server/routes/admin/session-upload.ts
|
|
16481
|
-
import { readFile as
|
|
16607
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
16482
16608
|
import { existsSync as existsSync29, statSync as statSync14 } from "fs";
|
|
16483
16609
|
var app17 = new Hono();
|
|
16484
16610
|
app17.get("/", requireAdminSession, async (c) => {
|
|
@@ -16508,7 +16634,7 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
16508
16634
|
const inlineSafe = isInlineSafeMime(mimeType);
|
|
16509
16635
|
const safeName = file.replace(/["\\\r\n]/g, "_");
|
|
16510
16636
|
console.log(`[session-upload] op=served session=${short2} file=${file} disposition=${inlineSafe ? "inline" : "attachment"} mime=${mimeType}`);
|
|
16511
|
-
const buffer = await
|
|
16637
|
+
const buffer = await readFile6(resolution.absolute);
|
|
16512
16638
|
return new Response(new Uint8Array(buffer), {
|
|
16513
16639
|
headers: {
|
|
16514
16640
|
"Content-Type": mimeType,
|
|
@@ -16524,35 +16650,10 @@ var session_upload_default = app17;
|
|
|
16524
16650
|
import { resolve as resolve23 } from "path";
|
|
16525
16651
|
import { readdirSync as readdirSync22, readFileSync as readFileSync33, existsSync as existsSync31, rmSync as rmSync2, renameSync as renameSync9, mkdirSync as mkdirSync7, writeFileSync as writeFileSync13 } from "fs";
|
|
16526
16652
|
|
|
16527
|
-
// server/routes/admin/_account-scope.ts
|
|
16528
|
-
function accountDirForSession(cacheKey) {
|
|
16529
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
16530
|
-
if (!accountId) return null;
|
|
16531
|
-
const match = listValidAccounts().find((a) => a.accountId === accountId);
|
|
16532
|
-
return match ? { accountId, accountDir: match.accountDir } : null;
|
|
16533
|
-
}
|
|
16534
|
-
function validateAccountId2(accountId) {
|
|
16535
|
-
if (!accountId) return null;
|
|
16536
|
-
const match = listValidAccounts().find((a) => a.accountId === accountId);
|
|
16537
|
-
return match ? { accountId, accountDir: match.accountDir } : null;
|
|
16538
|
-
}
|
|
16539
|
-
async function authorizeAccountWrite(c, accountId) {
|
|
16540
|
-
const remote = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
16541
|
-
const peerIsLoopback = remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1";
|
|
16542
|
-
if (peerIsLoopback && !c.req.header("x-forwarded-for")) return { ok: true, via: "on-device" };
|
|
16543
|
-
const { fingerprint, signedSessionToken } = await resolveCacheKey(c);
|
|
16544
|
-
if (!fingerprint || !validateSession(fingerprint, "admin", signedSessionToken).ok) {
|
|
16545
|
-
return { ok: false, reason: "no-session" };
|
|
16546
|
-
}
|
|
16547
|
-
const acct = accountDirForSession(fingerprint);
|
|
16548
|
-
if (!acct || acct.accountId !== accountId) return { ok: false, reason: "account-mismatch" };
|
|
16549
|
-
return { ok: true, via: "session" };
|
|
16550
|
-
}
|
|
16551
|
-
|
|
16552
16653
|
// ../services/claude-session-manager/src/tool-surface.ts
|
|
16553
16654
|
import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync15, existsSync as existsSync30 } from "fs";
|
|
16554
16655
|
import { createHash as createHash5 } from "crypto";
|
|
16555
|
-
import { join as
|
|
16656
|
+
import { join as join34 } from "path";
|
|
16556
16657
|
|
|
16557
16658
|
// ../services/claude-session-manager/src/canonical-tool-names.ts
|
|
16558
16659
|
function canonicalToolName(plugin, tool) {
|
|
@@ -16805,13 +16906,13 @@ function loadToolSurface(pluginsRoots) {
|
|
|
16805
16906
|
const riskByTool = /* @__PURE__ */ new Map();
|
|
16806
16907
|
const manifestPaths = /* @__PURE__ */ new Map();
|
|
16807
16908
|
const loadOne = (pluginsRoot, plugin) => {
|
|
16808
|
-
const pluginDir =
|
|
16909
|
+
const pluginDir = join34(pluginsRoot, plugin);
|
|
16809
16910
|
try {
|
|
16810
16911
|
if (!statSync15(pluginDir).isDirectory()) return;
|
|
16811
16912
|
} catch {
|
|
16812
16913
|
return;
|
|
16813
16914
|
}
|
|
16814
|
-
const manifestPath =
|
|
16915
|
+
const manifestPath = join34(pluginDir, "PLUGIN.md");
|
|
16815
16916
|
if (!existsSync30(manifestPath)) return;
|
|
16816
16917
|
const raw = readFileSync32(manifestPath, "utf-8");
|
|
16817
16918
|
const frontmatter = extractFrontmatter(raw, plugin);
|
|
@@ -16857,9 +16958,9 @@ function loadToolSurface(pluginsRoots) {
|
|
|
16857
16958
|
for (const root of roots) {
|
|
16858
16959
|
const entries2 = readdirSync21(root).sort();
|
|
16859
16960
|
for (const plugin of entries2) {
|
|
16860
|
-
const pluginDir =
|
|
16961
|
+
const pluginDir = join34(root, plugin);
|
|
16861
16962
|
loadOne(root, plugin);
|
|
16862
|
-
const subRoot =
|
|
16963
|
+
const subRoot = join34(pluginDir, "plugins");
|
|
16863
16964
|
let subEntries;
|
|
16864
16965
|
try {
|
|
16865
16966
|
if (!statSync15(subRoot).isDirectory()) continue;
|
|
@@ -16905,7 +17006,7 @@ function agentRiskClass(tools, riskByTool) {
|
|
|
16905
17006
|
const byTool = [];
|
|
16906
17007
|
const unresolved = [];
|
|
16907
17008
|
let worst = null;
|
|
16908
|
-
let
|
|
17009
|
+
let riskiestTool = null;
|
|
16909
17010
|
for (const tool of tools) {
|
|
16910
17011
|
const cls = BUILTIN_TOOL_RISK[tool] ?? riskByTool.get(tool) ?? null;
|
|
16911
17012
|
byTool.push({ tool, risk: cls });
|
|
@@ -16915,16 +17016,16 @@ function agentRiskClass(tools, riskByTool) {
|
|
|
16915
17016
|
}
|
|
16916
17017
|
if (worst === null || SEVERITY[cls] > SEVERITY[worst]) {
|
|
16917
17018
|
worst = cls;
|
|
16918
|
-
|
|
17019
|
+
riskiestTool = tool;
|
|
16919
17020
|
}
|
|
16920
17021
|
}
|
|
16921
17022
|
if (unresolved.length > 0) {
|
|
16922
|
-
return { risk: "red",
|
|
17023
|
+
return { risk: "red", riskiestTool: unresolved[0], unresolved, byTool };
|
|
16923
17024
|
}
|
|
16924
17025
|
if (worst === null) {
|
|
16925
|
-
return { risk: "red",
|
|
17026
|
+
return { risk: "red", riskiestTool: null, unresolved, byTool };
|
|
16926
17027
|
}
|
|
16927
|
-
return { risk: AGENT_CLASS[worst],
|
|
17028
|
+
return { risk: AGENT_CLASS[worst], riskiestTool, unresolved, byTool };
|
|
16928
17029
|
}
|
|
16929
17030
|
|
|
16930
17031
|
// server/routes/admin/agents.ts
|
|
@@ -17024,7 +17125,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed) {
|
|
|
17024
17125
|
plugin: "",
|
|
17025
17126
|
description: fm.description ?? "",
|
|
17026
17127
|
risk: r.risk,
|
|
17027
|
-
|
|
17128
|
+
riskiestTool: r.riskiestTool,
|
|
17028
17129
|
unresolved: r.unresolved,
|
|
17029
17130
|
toolCount: tools.length,
|
|
17030
17131
|
// The DIRECTORY is the ground truth, not the store. `spawn-context.ts`
|
|
@@ -17046,7 +17147,7 @@ function parseToolsLine(raw) {
|
|
|
17046
17147
|
}
|
|
17047
17148
|
function classify(tools, riskByTool, riskSurfaceFailed) {
|
|
17048
17149
|
if (riskSurfaceFailed) {
|
|
17049
|
-
return { risk: "red",
|
|
17150
|
+
return { risk: "red", riskiestTool: null, unresolved: [], byTool: tools.map((t) => ({ tool: t, risk: null })) };
|
|
17050
17151
|
}
|
|
17051
17152
|
return agentRiskClass(tools, riskByTool);
|
|
17052
17153
|
}
|
|
@@ -17082,7 +17183,7 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
17082
17183
|
plugin,
|
|
17083
17184
|
description: fm.description ?? "",
|
|
17084
17185
|
risk: r.risk,
|
|
17085
|
-
|
|
17186
|
+
riskiestTool: r.riskiestTool,
|
|
17086
17187
|
unresolved: r.unresolved,
|
|
17087
17188
|
toolCount: specialistTools.length,
|
|
17088
17189
|
// A user-created specialist lives under the account plugins tree,
|
|
@@ -17133,7 +17234,7 @@ app18.get("/", requireAdminSession, (c) => {
|
|
|
17133
17234
|
kind: "public",
|
|
17134
17235
|
origin: "public",
|
|
17135
17236
|
risk: null,
|
|
17136
|
-
|
|
17237
|
+
riskiestTool: null,
|
|
17137
17238
|
unresolved: [],
|
|
17138
17239
|
disabled: false
|
|
17139
17240
|
});
|
|
@@ -17153,7 +17254,7 @@ app18.get("/", requireAdminSession, (c) => {
|
|
|
17153
17254
|
for (const row of rows) {
|
|
17154
17255
|
if (row.risk === null) continue;
|
|
17155
17256
|
console.log(
|
|
17156
|
-
`[admin/agents] op=classify account=${acct} agent=${row.slug} origin=${row.origin} risk=${row.risk}
|
|
17257
|
+
`[admin/agents] op=classify account=${acct} agent=${row.slug} origin=${row.origin} risk=${row.risk} riskiestTool=${row.riskiestTool ?? "none"} tools=${row.toolCount} unresolved=${row.unresolved.length > 0 ? row.unresolved.join(",") : "none"} disabled=${row.disabled}`
|
|
17157
17258
|
);
|
|
17158
17259
|
}
|
|
17159
17260
|
console.log(`[admin/agents] op=list accountId=${acct} agents=${agents.length} specialists=${specialists.length} shipped=${shipped.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped} shippedSkipped=${shippedSkipped}`);
|
|
@@ -17196,7 +17297,7 @@ app18.get("/:slug", requireAdminSession, (c) => {
|
|
|
17196
17297
|
systemPrompt: body.trim(),
|
|
17197
17298
|
skills: [],
|
|
17198
17299
|
risk: r.risk,
|
|
17199
|
-
|
|
17300
|
+
riskiestTool: r.riskiestTool,
|
|
17200
17301
|
unresolved: r.unresolved,
|
|
17201
17302
|
byTool: r.byTool,
|
|
17202
17303
|
disabled: readDisabledStore(account.accountDir).has(`${slug}.md`)
|
|
@@ -17227,7 +17328,7 @@ app18.get("/:slug", requireAdminSession, (c) => {
|
|
|
17227
17328
|
systemPrompt: body.trim(),
|
|
17228
17329
|
skills,
|
|
17229
17330
|
risk: r.risk,
|
|
17230
|
-
|
|
17331
|
+
riskiestTool: r.riskiestTool,
|
|
17231
17332
|
unresolved: r.unresolved,
|
|
17232
17333
|
byTool: r.byTool,
|
|
17233
17334
|
disabled: false
|
|
@@ -18127,7 +18228,7 @@ var sessions_default = app19;
|
|
|
18127
18228
|
|
|
18128
18229
|
// app/lib/claude-agent/spawn-context.ts
|
|
18129
18230
|
import { existsSync as existsSync33, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync16 } from "fs";
|
|
18130
|
-
import { dirname as dirname12, resolve as resolve24, join as
|
|
18231
|
+
import { dirname as dirname12, resolve as resolve24, join as join35 } from "path";
|
|
18131
18232
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
18132
18233
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
18133
18234
|
try {
|
|
@@ -18168,8 +18269,8 @@ function frontmatterField(manifest, field2) {
|
|
|
18168
18269
|
function extractPluginToolDescriptions(pluginDir) {
|
|
18169
18270
|
const out = /* @__PURE__ */ new Map();
|
|
18170
18271
|
const candidates = [
|
|
18171
|
-
|
|
18172
|
-
|
|
18272
|
+
join35(pluginDir, "mcp/dist/index.js"),
|
|
18273
|
+
join35(pluginDir, "mcp/src/index.ts")
|
|
18173
18274
|
];
|
|
18174
18275
|
let raw = null;
|
|
18175
18276
|
for (const path3 of candidates) {
|
|
@@ -18227,7 +18328,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18227
18328
|
const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
|
|
18228
18329
|
if (existsSync33(platformPlugins)) {
|
|
18229
18330
|
for (const name of readdirSync23(platformPlugins)) {
|
|
18230
|
-
const dir =
|
|
18331
|
+
const dir = join35(platformPlugins, name);
|
|
18231
18332
|
try {
|
|
18232
18333
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18233
18334
|
} catch {
|
|
@@ -18237,11 +18338,11 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18237
18338
|
const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
|
|
18238
18339
|
if (existsSync33(premiumRoot)) {
|
|
18239
18340
|
for (const bundle of readdirSync23(premiumRoot)) {
|
|
18240
|
-
const bundlePlugins =
|
|
18341
|
+
const bundlePlugins = join35(premiumRoot, bundle, "plugins");
|
|
18241
18342
|
if (!existsSync33(bundlePlugins)) continue;
|
|
18242
18343
|
try {
|
|
18243
18344
|
for (const name of readdirSync23(bundlePlugins)) {
|
|
18244
|
-
const dir =
|
|
18345
|
+
const dir = join35(bundlePlugins, name);
|
|
18245
18346
|
try {
|
|
18246
18347
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18247
18348
|
} catch {
|
|
@@ -18255,7 +18356,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18255
18356
|
try {
|
|
18256
18357
|
for (const name of readdirSync23(accountPluginsDir)) {
|
|
18257
18358
|
if (out.has(name)) continue;
|
|
18258
|
-
const dir =
|
|
18359
|
+
const dir = join35(accountPluginsDir, name);
|
|
18259
18360
|
try {
|
|
18260
18361
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18261
18362
|
} catch {
|
|
@@ -18274,7 +18375,7 @@ function listAccountPluginNames(accountPluginsDir) {
|
|
|
18274
18375
|
try {
|
|
18275
18376
|
return readdirSync23(accountPluginsDir).filter((name) => {
|
|
18276
18377
|
try {
|
|
18277
|
-
return statSync16(
|
|
18378
|
+
return statSync16(join35(accountPluginsDir, name)).isDirectory();
|
|
18278
18379
|
} catch {
|
|
18279
18380
|
return false;
|
|
18280
18381
|
}
|
|
@@ -18317,7 +18418,7 @@ function computeActivePlugins(accountId) {
|
|
|
18317
18418
|
for (const name of emitNames) {
|
|
18318
18419
|
const dir = pluginDirs.get(name);
|
|
18319
18420
|
if (!dir) continue;
|
|
18320
|
-
const fm = readFrontmatter(
|
|
18421
|
+
const fm = readFrontmatter(join35(dir, "PLUGIN.md"));
|
|
18321
18422
|
if (!fm) continue;
|
|
18322
18423
|
const description = frontmatterField(`---
|
|
18323
18424
|
${fm}
|
|
@@ -18334,7 +18435,7 @@ ${fm}
|
|
|
18334
18435
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
18335
18436
|
);
|
|
18336
18437
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
18337
|
-
const hasSource = existsSync33(
|
|
18438
|
+
const hasSource = existsSync33(join35(dir, "mcp/dist/index.js")) || existsSync33(join35(dir, "mcp/src/index.ts"));
|
|
18338
18439
|
if (hasSource) {
|
|
18339
18440
|
console.warn(
|
|
18340
18441
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -18344,7 +18445,7 @@ ${fm}
|
|
|
18344
18445
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
18345
18446
|
const skills = [];
|
|
18346
18447
|
for (const relPath of skillPaths) {
|
|
18347
|
-
const skillPath =
|
|
18448
|
+
const skillPath = join35(dir, relPath);
|
|
18348
18449
|
const skillFm = readFrontmatter(skillPath);
|
|
18349
18450
|
if (!skillFm) continue;
|
|
18350
18451
|
const skillName = frontmatterField(`---
|
|
@@ -18388,7 +18489,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
18388
18489
|
const out = [];
|
|
18389
18490
|
for (const file of entries2.sort()) {
|
|
18390
18491
|
if (!file.endsWith(".md")) continue;
|
|
18391
|
-
const fm = readFrontmatter(
|
|
18492
|
+
const fm = readFrontmatter(join35(specialistsDir, file));
|
|
18392
18493
|
if (!fm) continue;
|
|
18393
18494
|
const wrapped = `---
|
|
18394
18495
|
${fm}
|
|
@@ -18784,10 +18885,10 @@ var events_default = app22;
|
|
|
18784
18885
|
|
|
18785
18886
|
// server/routes/admin/files.ts
|
|
18786
18887
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync35 } from "fs";
|
|
18787
|
-
import { readdir as readdir4, readFile as
|
|
18888
|
+
import { readdir as readdir4, readFile as readFile8, stat as stat7, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
|
|
18788
18889
|
import { realpathSync as realpathSync7 } from "fs";
|
|
18789
18890
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
18790
|
-
import { basename as basename11, dirname as dirname13, join as
|
|
18891
|
+
import { basename as basename11, dirname as dirname13, join as join37, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
|
|
18791
18892
|
import { Readable as Readable2 } from "stream";
|
|
18792
18893
|
|
|
18793
18894
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -19105,7 +19206,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
19105
19206
|
|
|
19106
19207
|
// app/lib/file-index.ts
|
|
19107
19208
|
import * as fsp from "fs/promises";
|
|
19108
|
-
import { resolve as resolve26, relative as relative4, join as
|
|
19209
|
+
import { resolve as resolve26, relative as relative4, join as join36, basename as basename10, extname as extname2, sep as sep7 } from "path";
|
|
19109
19210
|
import { tmpdir as tmpdir2 } from "os";
|
|
19110
19211
|
import { execFile as execFile2 } from "child_process";
|
|
19111
19212
|
import { promisify as promisify2 } from "util";
|
|
@@ -19187,7 +19288,7 @@ async function extractPdf(absolute) {
|
|
|
19187
19288
|
return stdout.trim();
|
|
19188
19289
|
}
|
|
19189
19290
|
async function ocrPdf(absolute) {
|
|
19190
|
-
const outPdf =
|
|
19291
|
+
const outPdf = join36(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
19191
19292
|
try {
|
|
19192
19293
|
await execFileAsync2(
|
|
19193
19294
|
"ocrmypdf",
|
|
@@ -19249,7 +19350,7 @@ async function readDisplayName(absolute) {
|
|
|
19249
19350
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
19250
19351
|
if (base === `${stem}.meta.json`) return null;
|
|
19251
19352
|
try {
|
|
19252
|
-
const raw = await fsp.readFile(
|
|
19353
|
+
const raw = await fsp.readFile(join36(dir, `${stem}.meta.json`), "utf-8");
|
|
19253
19354
|
const meta = JSON.parse(raw);
|
|
19254
19355
|
const dn = meta.displayName ?? meta.filename;
|
|
19255
19356
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -19270,7 +19371,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
19270
19371
|
for (const entry of entries2) {
|
|
19271
19372
|
if (entry.isSymbolicLink()) continue;
|
|
19272
19373
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
19273
|
-
const abs =
|
|
19374
|
+
const abs = join36(root, entry.name);
|
|
19274
19375
|
if (entry.isDirectory()) {
|
|
19275
19376
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
19276
19377
|
if (!sub.clean) clean = false;
|
|
@@ -19643,7 +19744,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
19643
19744
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
19644
19745
|
async function readMeta(absDir, baseName) {
|
|
19645
19746
|
try {
|
|
19646
|
-
const raw = await
|
|
19747
|
+
const raw = await readFile8(join37(absDir, `${baseName}.meta.json`), "utf8");
|
|
19647
19748
|
const parsed = JSON.parse(raw);
|
|
19648
19749
|
if (typeof parsed?.filename === "string") {
|
|
19649
19750
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -19665,7 +19766,7 @@ async function readAccountNames() {
|
|
|
19665
19766
|
if (!UUID_RE4.test(name)) continue;
|
|
19666
19767
|
const configPath2 = resolve27(accountsDir, name, "account.json");
|
|
19667
19768
|
try {
|
|
19668
|
-
const raw = await
|
|
19769
|
+
const raw = await readFile8(configPath2, "utf8");
|
|
19669
19770
|
const parsed = JSON.parse(raw);
|
|
19670
19771
|
if (typeof parsed?.name === "string" && parsed.name.length > 0) {
|
|
19671
19772
|
map.set(name, parsed.name);
|
|
@@ -19698,7 +19799,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
19698
19799
|
}
|
|
19699
19800
|
async function enrich(absolute, entry, accountNames) {
|
|
19700
19801
|
if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
|
|
19701
|
-
const dirAbs =
|
|
19802
|
+
const dirAbs = join37(absolute, entry.name);
|
|
19702
19803
|
const meta = await readMeta(dirAbs, entry.name);
|
|
19703
19804
|
if (meta?.filename) {
|
|
19704
19805
|
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
@@ -19707,7 +19808,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
19707
19808
|
let size = null;
|
|
19708
19809
|
let modifiedAt = entry.modifiedAt;
|
|
19709
19810
|
try {
|
|
19710
|
-
const st = await
|
|
19811
|
+
const st = await stat7(join37(dirAbs, innerName));
|
|
19711
19812
|
size = st.size;
|
|
19712
19813
|
modifiedAt = st.mtime.toISOString();
|
|
19713
19814
|
} catch {
|
|
@@ -19882,7 +19983,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
19882
19983
|
return c.json({ error: "Not found" }, 404);
|
|
19883
19984
|
}
|
|
19884
19985
|
try {
|
|
19885
|
-
const info = await
|
|
19986
|
+
const info = await stat7(absolute);
|
|
19886
19987
|
if (!info.isDirectory()) {
|
|
19887
19988
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
19888
19989
|
}
|
|
@@ -19900,8 +20001,8 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
19900
20001
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
19901
20002
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
19902
20003
|
try {
|
|
19903
|
-
const entryPath =
|
|
19904
|
-
const s = await
|
|
20004
|
+
const entryPath = join37(absolute, name);
|
|
20005
|
+
const s = await stat7(entryPath);
|
|
19905
20006
|
entries2.push({
|
|
19906
20007
|
name,
|
|
19907
20008
|
kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
|
|
@@ -19929,7 +20030,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
19929
20030
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
19930
20031
|
if (groupReq || isAccountRoot(relPath)) {
|
|
19931
20032
|
const acctId = relPath.split("/")[1] ?? accountId;
|
|
19932
|
-
const schemaMd = await
|
|
20033
|
+
const schemaMd = await readFile8(join37(absolute, "SCHEMA.md"), "utf8").catch(() => null);
|
|
19933
20034
|
const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
|
|
19934
20035
|
console.error(
|
|
19935
20036
|
`[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
|
|
@@ -19967,7 +20068,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
19967
20068
|
for (const name of homeDirs) {
|
|
19968
20069
|
const base = byName.get(name);
|
|
19969
20070
|
try {
|
|
19970
|
-
const dirents = await readdir4(
|
|
20071
|
+
const dirents = await readdir4(join37(absolute, name), { withFileTypes: true });
|
|
19971
20072
|
const visible = dirents.filter((d) => !d.name.startsWith("."));
|
|
19972
20073
|
visible.sort((a, b) => {
|
|
19973
20074
|
const ad = a.isDirectory() ? 0 : 1;
|
|
@@ -20032,7 +20133,7 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
20032
20133
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
20033
20134
|
return c.json({ error: "Not found" }, 404);
|
|
20034
20135
|
}
|
|
20035
|
-
const meta = readSidecarMeta(
|
|
20136
|
+
const meta = readSidecarMeta(join37(projectDir, `${sessionId}.meta.json`));
|
|
20036
20137
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
20037
20138
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
20038
20139
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -20059,7 +20160,7 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
20059
20160
|
return c.json({ error: "Not found" }, 404);
|
|
20060
20161
|
}
|
|
20061
20162
|
try {
|
|
20062
|
-
const info = await
|
|
20163
|
+
const info = await stat7(absolute);
|
|
20063
20164
|
if (!info.isFile()) {
|
|
20064
20165
|
return c.json({ error: "Path is not a file" }, 400);
|
|
20065
20166
|
}
|
|
@@ -20127,7 +20228,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
20127
20228
|
const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
|
|
20128
20229
|
for (const d of dirents) {
|
|
20129
20230
|
if (d.isSymbolicLink()) continue;
|
|
20130
|
-
const child =
|
|
20231
|
+
const child = join37(dirAbsolute, d.name);
|
|
20131
20232
|
if (d.isDirectory()) {
|
|
20132
20233
|
yield* walkRegularFiles(child);
|
|
20133
20234
|
continue;
|
|
@@ -20156,7 +20257,7 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
20156
20257
|
if (entries2.length >= maxFiles) return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
|
|
20157
20258
|
total += size;
|
|
20158
20259
|
if (total > maxTotalBytes) return c.json({ error: "Selection too large to zip" }, 413);
|
|
20159
|
-
entries2.push({ name: member, data: await
|
|
20260
|
+
entries2.push({ name: member, data: await readFile8(absolute) });
|
|
20160
20261
|
return null;
|
|
20161
20262
|
};
|
|
20162
20263
|
for (const rawPath of rawPaths) {
|
|
@@ -20173,7 +20274,7 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
20173
20274
|
return c.json({ error: "Not found" }, 404);
|
|
20174
20275
|
}
|
|
20175
20276
|
try {
|
|
20176
|
-
const info = await
|
|
20277
|
+
const info = await stat7(absolute);
|
|
20177
20278
|
if (info.isDirectory()) {
|
|
20178
20279
|
dirsWalked++;
|
|
20179
20280
|
const parentAbs = dirname13(absolute);
|
|
@@ -20181,7 +20282,7 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
20181
20282
|
const within = relative5(absolute, fileAbs).split(sep8).join("/");
|
|
20182
20283
|
const fileRel = relPath === "" || relPath === "." ? within : `${relPath}/${within}`;
|
|
20183
20284
|
if (crossesForeignAccountPartition(fileRel, accountId)) continue;
|
|
20184
|
-
const fileInfo = await
|
|
20285
|
+
const fileInfo = await stat7(fileAbs);
|
|
20185
20286
|
const member = relative5(parentAbs, fileAbs).split(sep8).join("/");
|
|
20186
20287
|
const over = await addFile(fileAbs, fileInfo.size, member);
|
|
20187
20288
|
if (over) return over;
|
|
@@ -20237,7 +20338,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
20237
20338
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
20238
20339
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
20239
20340
|
const relDir = relpath ? dirname13(relpath) : ".";
|
|
20240
|
-
const destRel = relDir === "." ? base.relative :
|
|
20341
|
+
const destRel = relDir === "." ? base.relative : join37(base.relative, relDir);
|
|
20241
20342
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
20242
20343
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
20243
20344
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -20252,7 +20353,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
20252
20353
|
const firstCreated = await mkdir4(destDir, { recursive: true });
|
|
20253
20354
|
if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
|
|
20254
20355
|
} else {
|
|
20255
|
-
const info = await
|
|
20356
|
+
const info = await stat7(destDir).catch(() => null);
|
|
20256
20357
|
if (!info || !info.isDirectory()) return { ok: false, status: 400, error: "Upload destination is not a directory" };
|
|
20257
20358
|
}
|
|
20258
20359
|
const dataRootReal = realpathSync7(DATA_ROOT);
|
|
@@ -20604,7 +20705,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
20604
20705
|
return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
|
|
20605
20706
|
}
|
|
20606
20707
|
try {
|
|
20607
|
-
const info = await
|
|
20708
|
+
const info = await stat7(absolute);
|
|
20608
20709
|
if (info.isDirectory()) {
|
|
20609
20710
|
return c.json({ error: "Directory deletion not supported" }, 400);
|
|
20610
20711
|
}
|
|
@@ -20614,7 +20715,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
20614
20715
|
const dot = base.lastIndexOf(".");
|
|
20615
20716
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
20616
20717
|
const containerDir = dirname13(absolute);
|
|
20617
|
-
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ?
|
|
20718
|
+
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join37(containerDir, `${stem}.meta.json`) : null;
|
|
20618
20719
|
const isAttachmentContainer = UUID_RE4.test(stem) && basename11(containerDir) === stem;
|
|
20619
20720
|
await unlink3(absolute);
|
|
20620
20721
|
if (sidecarPath) {
|
|
@@ -20624,7 +20725,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
20624
20725
|
}
|
|
20625
20726
|
}
|
|
20626
20727
|
if (isAttachmentContainer) {
|
|
20627
|
-
await unlink3(
|
|
20728
|
+
await unlink3(join37(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
20628
20729
|
});
|
|
20629
20730
|
await rmdir(containerDir).catch(() => {
|
|
20630
20731
|
});
|
|
@@ -20681,7 +20782,7 @@ app23.post("/folder", requireAdminSession, async (c) => {
|
|
|
20681
20782
|
const newAbs = resolve27(parent.absolute, name);
|
|
20682
20783
|
const newRel = `${parent.relative}/${name}`;
|
|
20683
20784
|
try {
|
|
20684
|
-
const info = await
|
|
20785
|
+
const info = await stat7(parent.absolute);
|
|
20685
20786
|
if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
|
|
20686
20787
|
await mkdir4(newAbs, { recursive: false });
|
|
20687
20788
|
} catch (err) {
|
|
@@ -20726,7 +20827,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
|
|
|
20726
20827
|
try {
|
|
20727
20828
|
let collision = true;
|
|
20728
20829
|
try {
|
|
20729
|
-
await
|
|
20830
|
+
await stat7(destAbs);
|
|
20730
20831
|
} catch (e) {
|
|
20731
20832
|
if (e.code === "ENOENT") collision = false;
|
|
20732
20833
|
}
|
|
@@ -21734,7 +21835,7 @@ function isHiddenByDefault(label) {
|
|
|
21734
21835
|
// server/lib/top-level-labels.ts
|
|
21735
21836
|
var import_dist5 = __toESM(require_dist4(), 1);
|
|
21736
21837
|
import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
|
|
21737
|
-
import { join as
|
|
21838
|
+
import { join as join38, resolve as resolve28 } from "path";
|
|
21738
21839
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
21739
21840
|
/* @__PURE__ */ new Set([
|
|
21740
21841
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -21838,7 +21939,7 @@ function parseTopLevelLabels(content) {
|
|
|
21838
21939
|
}
|
|
21839
21940
|
function resolveReferencesDir() {
|
|
21840
21941
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
21841
|
-
return
|
|
21942
|
+
return join38(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
21842
21943
|
}
|
|
21843
21944
|
return resolve28(import.meta.dirname, "../../../plugins/memory/references");
|
|
21844
21945
|
}
|
|
@@ -21848,7 +21949,7 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
21848
21949
|
try {
|
|
21849
21950
|
const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
21850
21951
|
for (const fileName of fileNames) {
|
|
21851
|
-
const content = readFileSync36(
|
|
21952
|
+
const content = readFileSync36(join38(referencesDir, fileName), "utf-8");
|
|
21852
21953
|
const parsed = parseTopLevelLabels(content);
|
|
21853
21954
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
21854
21955
|
for (const label of parsed) labels.add(label);
|
|
@@ -23004,7 +23105,7 @@ var WRITE_CYPHER = `
|
|
|
23004
23105
|
var graph_default_view_default = app29;
|
|
23005
23106
|
|
|
23006
23107
|
// server/routes/admin/sidebar-artefacts.ts
|
|
23007
|
-
import { readdir as readdir5, stat as
|
|
23108
|
+
import { readdir as readdir5, stat as stat8 } from "fs/promises";
|
|
23008
23109
|
import { resolve as resolve29, relative as relative6, isAbsolute as isAbsolute2, sep as sep9, basename as basename12 } from "path";
|
|
23009
23110
|
import { existsSync as existsSync36 } from "fs";
|
|
23010
23111
|
var LIMIT = 50;
|
|
@@ -23155,7 +23256,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
23155
23256
|
}
|
|
23156
23257
|
if (!chosenPath) return null;
|
|
23157
23258
|
try {
|
|
23158
|
-
const st = await
|
|
23259
|
+
const st = await stat8(chosenPath);
|
|
23159
23260
|
const dlPath = toDataRootRelPath(chosenPath);
|
|
23160
23261
|
return {
|
|
23161
23262
|
id: inp.id,
|
|
@@ -23187,11 +23288,11 @@ var sidebar_artefacts_default = app30;
|
|
|
23187
23288
|
|
|
23188
23289
|
// server/channel-session-override.ts
|
|
23189
23290
|
import { readFileSync as readFileSync37, writeFileSync as writeFileSync14, renameSync as renameSync10 } from "fs";
|
|
23190
|
-
import { join as
|
|
23291
|
+
import { join as join39 } from "path";
|
|
23191
23292
|
var FILE2 = "channel-session-override.json";
|
|
23192
23293
|
var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
23193
23294
|
function channelOverridePath(accountDir) {
|
|
23194
|
-
return
|
|
23295
|
+
return join39(accountDir, FILE2);
|
|
23195
23296
|
}
|
|
23196
23297
|
function senderKey(channel, senderId) {
|
|
23197
23298
|
return `${channel}:${senderId}`;
|
|
@@ -23587,24 +23688,24 @@ var session_rc_spawn_default = app36;
|
|
|
23587
23688
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
23588
23689
|
|
|
23589
23690
|
// server/wa-descriptor.ts
|
|
23590
|
-
import { resolve as resolve30, join as
|
|
23691
|
+
import { resolve as resolve30, join as join40 } from "path";
|
|
23591
23692
|
function waGatewayUrl() {
|
|
23592
23693
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
23593
23694
|
}
|
|
23594
23695
|
function waServerPath() {
|
|
23595
|
-
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ??
|
|
23696
|
+
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join40(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
|
|
23596
23697
|
}
|
|
23597
23698
|
function waChannelDescriptor(senderId) {
|
|
23598
23699
|
return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
|
|
23599
23700
|
}
|
|
23600
23701
|
|
|
23601
23702
|
// server/telegram-descriptor.ts
|
|
23602
|
-
import { resolve as resolve31, join as
|
|
23703
|
+
import { resolve as resolve31, join as join41 } from "path";
|
|
23603
23704
|
function telegramGatewayUrl() {
|
|
23604
23705
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
23605
23706
|
}
|
|
23606
23707
|
function telegramServerPath() {
|
|
23607
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
23708
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join41(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
23608
23709
|
}
|
|
23609
23710
|
function telegramChannelDescriptor(senderId) {
|
|
23610
23711
|
return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
|
|
@@ -23721,16 +23822,18 @@ app37.post("/", requireAdminSession, async (c) => {
|
|
|
23721
23822
|
return c.json(parsed ?? { error: text }, res.status);
|
|
23722
23823
|
}
|
|
23723
23824
|
try {
|
|
23724
|
-
const account =
|
|
23825
|
+
const account = cacheKey ? accountDirForSession(cacheKey) : null;
|
|
23725
23826
|
if (account && adminUserId) {
|
|
23726
|
-
const
|
|
23827
|
+
const platformAccountId = resolvePlatformAccountId();
|
|
23727
23828
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
23728
|
-
const canonicalId = adminSessionIdFor(
|
|
23829
|
+
const canonicalId = adminSessionIdFor(platformAccountId, WEBCHAT_ADMIN_KEY, adminUserId);
|
|
23729
23830
|
const currentOverride = readCanonicalOverrideId(account.accountDir, adminUserId, primaryUserId);
|
|
23730
23831
|
if (fromSessionId === canonicalId || fromSessionId === currentOverride) {
|
|
23731
23832
|
writeCanonicalOverrideId(account.accountDir, adminUserId, plan.sessionId);
|
|
23732
|
-
console.log(`[chat-reseat] op=canonical-forward reseatReqId=${reseatReqId} from=${fromSessionId} to=${plan.sessionId}`);
|
|
23833
|
+
console.log(`[chat-reseat] op=canonical-forward reseatReqId=${reseatReqId} accountId=${account.accountId.slice(0, 8)} from=${fromSessionId} to=${plan.sessionId}`);
|
|
23733
23834
|
}
|
|
23835
|
+
} else if (!account) {
|
|
23836
|
+
console.error(`[chat-reseat] op=canonical-forward-skipped reseatReqId=${reseatReqId} accountId=none reason=no-account-for-session`);
|
|
23734
23837
|
}
|
|
23735
23838
|
} catch (err) {
|
|
23736
23839
|
console.error(`[session-reseat] canonical-forward-failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -23767,7 +23870,7 @@ app37.post("/", requireAdminSession, async (c) => {
|
|
|
23767
23870
|
var session_reseat_default = app37;
|
|
23768
23871
|
|
|
23769
23872
|
// server/routes/admin/system-stats.ts
|
|
23770
|
-
import { readFile as
|
|
23873
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
23771
23874
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
23772
23875
|
function parseCpuStat(blob) {
|
|
23773
23876
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
@@ -23811,11 +23914,11 @@ function parseMeminfo(blob) {
|
|
|
23811
23914
|
}
|
|
23812
23915
|
var SAMPLE_DELAY_MS = 100;
|
|
23813
23916
|
async function sampleLinux() {
|
|
23814
|
-
const a = parseCpuStat(await
|
|
23917
|
+
const a = parseCpuStat(await readFile9("/proc/stat", "utf-8"));
|
|
23815
23918
|
await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
|
|
23816
|
-
const b = parseCpuStat(await
|
|
23817
|
-
const meminfo = parseMeminfo(await
|
|
23818
|
-
const loadavgRaw = (await
|
|
23919
|
+
const b = parseCpuStat(await readFile9("/proc/stat", "utf-8"));
|
|
23920
|
+
const meminfo = parseMeminfo(await readFile9("/proc/meminfo", "utf-8"));
|
|
23921
|
+
const loadavgRaw = (await readFile9("/proc/loadavg", "utf-8")).trim();
|
|
23819
23922
|
const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
|
|
23820
23923
|
if (![l1, l5, l15].every(Number.isFinite)) {
|
|
23821
23924
|
throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
|
|
@@ -23889,10 +23992,10 @@ var system_stats_default = app38;
|
|
|
23889
23992
|
|
|
23890
23993
|
// server/routes/admin/health.ts
|
|
23891
23994
|
import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
|
|
23892
|
-
import { resolve as resolve32, join as
|
|
23995
|
+
import { resolve as resolve32, join as join42 } from "path";
|
|
23893
23996
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
|
|
23894
23997
|
var brandHostname = "maxy";
|
|
23895
|
-
var brandJsonPath =
|
|
23998
|
+
var brandJsonPath = join42(PLATFORM_ROOT6, "config", "brand.json");
|
|
23896
23999
|
if (existsSync37(brandJsonPath)) {
|
|
23897
24000
|
try {
|
|
23898
24001
|
const brand = JSON.parse(readFileSync38(brandJsonPath, "utf-8"));
|
|
@@ -24682,7 +24785,7 @@ var browser_default = app46;
|
|
|
24682
24785
|
|
|
24683
24786
|
// server/routes/admin/calendar.ts
|
|
24684
24787
|
import { existsSync as existsSync38 } from "fs";
|
|
24685
|
-
import { join as
|
|
24788
|
+
import { join as join44 } from "path";
|
|
24686
24789
|
|
|
24687
24790
|
// server/lib/calendar-ics.ts
|
|
24688
24791
|
var CRLF = "\r\n";
|
|
@@ -24782,7 +24885,7 @@ function countVEvents(ics) {
|
|
|
24782
24885
|
|
|
24783
24886
|
// server/lib/calendar-availability.ts
|
|
24784
24887
|
import { readFileSync as readFileSync39 } from "fs";
|
|
24785
|
-
import { join as
|
|
24888
|
+
import { join as join43 } from "path";
|
|
24786
24889
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
24787
24890
|
var REQUIRED_KEYS = [
|
|
24788
24891
|
"timezone",
|
|
@@ -24791,7 +24894,7 @@ var REQUIRED_KEYS = [
|
|
|
24791
24894
|
"weekly"
|
|
24792
24895
|
];
|
|
24793
24896
|
function readAvailabilityConfig(accountDir) {
|
|
24794
|
-
const path3 =
|
|
24897
|
+
const path3 = join43(accountDir, AVAILABILITY_FILENAME);
|
|
24795
24898
|
let raw;
|
|
24796
24899
|
try {
|
|
24797
24900
|
raw = readFileSync39(path3, "utf-8");
|
|
@@ -25147,25 +25250,26 @@ app47.delete("/meetings/:id", requireAdminSession, async (c) => {
|
|
|
25147
25250
|
}
|
|
25148
25251
|
});
|
|
25149
25252
|
app47.get("/booking-link", requireAdminSession, (c) => {
|
|
25253
|
+
const account = accountDirForSession(c.var.cacheKey);
|
|
25254
|
+
if (!account) {
|
|
25255
|
+
console.error("[calendar] op=booking-link auth-rejected reason=no-account-for-session accountId=none");
|
|
25256
|
+
return c.json({ error: "no account for session", reason: "no-account-for-session" }, 401);
|
|
25257
|
+
}
|
|
25258
|
+
const id82 = account.accountId.slice(0, 8);
|
|
25150
25259
|
try {
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
25154
|
-
return c.json({ bookingDomain: null });
|
|
25155
|
-
}
|
|
25156
|
-
if (!existsSync38(join43(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
25157
|
-
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
25260
|
+
if (!existsSync38(join44(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
25261
|
+
console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
|
|
25158
25262
|
return c.json({ bookingDomain: null });
|
|
25159
25263
|
}
|
|
25160
25264
|
const config = readAvailabilityConfig(account.accountDir);
|
|
25161
25265
|
const bookingDomain = typeof config.bookingDomain === "string" && config.bookingDomain.trim() ? config.bookingDomain.trim() : null;
|
|
25162
25266
|
console.log(
|
|
25163
|
-
`[calendar] op=booking-link bookingDomain=${bookingDomain ?? "none"} source=availability-config`
|
|
25267
|
+
`[calendar] op=booking-link accountId=${id82} bookingDomain=${bookingDomain ?? "none"} source=availability-config`
|
|
25164
25268
|
);
|
|
25165
25269
|
return c.json({ bookingDomain });
|
|
25166
25270
|
} catch (err) {
|
|
25167
25271
|
const message = err instanceof Error ? err.message : String(err);
|
|
25168
|
-
console.error(`[calendar] op=booking-link-fail err="${message}"`);
|
|
25272
|
+
console.error(`[calendar] op=booking-link-fail accountId=${id82} err="${message}"`);
|
|
25169
25273
|
return c.json({ bookingDomain: null });
|
|
25170
25274
|
}
|
|
25171
25275
|
});
|
|
@@ -26550,13 +26654,13 @@ app62.get("/:rel{.*}", (c) => {
|
|
|
26550
26654
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
26551
26655
|
return c.text("Forbidden", 403);
|
|
26552
26656
|
}
|
|
26553
|
-
let
|
|
26657
|
+
let stat12;
|
|
26554
26658
|
try {
|
|
26555
|
-
|
|
26659
|
+
stat12 = existsSync41(filePath) ? statSync18(filePath) : null;
|
|
26556
26660
|
} catch {
|
|
26557
|
-
|
|
26661
|
+
stat12 = null;
|
|
26558
26662
|
}
|
|
26559
|
-
if (
|
|
26663
|
+
if (stat12?.isDirectory() && !reqPath.endsWith("/")) {
|
|
26560
26664
|
const search = new URL(c.req.url).search;
|
|
26561
26665
|
const target = `${reqPath}/${search}`;
|
|
26562
26666
|
console.log(
|
|
@@ -26564,7 +26668,7 @@ app62.get("/:rel{.*}", (c) => {
|
|
|
26564
26668
|
);
|
|
26565
26669
|
return c.redirect(target, 301);
|
|
26566
26670
|
}
|
|
26567
|
-
if (
|
|
26671
|
+
if (stat12?.isDirectory()) {
|
|
26568
26672
|
filePath = resolve36(filePath, "index.html");
|
|
26569
26673
|
}
|
|
26570
26674
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
@@ -26703,7 +26807,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
26703
26807
|
|
|
26704
26808
|
// app/lib/brand-config.ts
|
|
26705
26809
|
import { existsSync as existsSync42, readFileSync as readFileSync44 } from "fs";
|
|
26706
|
-
import { join as
|
|
26810
|
+
import { join as join45 } from "path";
|
|
26707
26811
|
var cached2 = null;
|
|
26708
26812
|
var cachedAttempted = false;
|
|
26709
26813
|
function readBrandConfig() {
|
|
@@ -26711,7 +26815,7 @@ function readBrandConfig() {
|
|
|
26711
26815
|
cachedAttempted = true;
|
|
26712
26816
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
26713
26817
|
if (!platformRoot5) return null;
|
|
26714
|
-
const brandPath =
|
|
26818
|
+
const brandPath = join45(platformRoot5, "config", "brand.json");
|
|
26715
26819
|
if (!existsSync42(brandPath)) return null;
|
|
26716
26820
|
try {
|
|
26717
26821
|
cached2 = JSON.parse(readFileSync44(brandPath, "utf-8"));
|
|
@@ -27555,8 +27659,8 @@ var calendar_public_default = app67;
|
|
|
27555
27659
|
|
|
27556
27660
|
// server/routes/portal-fetch.ts
|
|
27557
27661
|
import { createReadStream as createReadStream3 } from "fs";
|
|
27558
|
-
import { stat as
|
|
27559
|
-
import { join as
|
|
27662
|
+
import { stat as stat9, readFile as readFile10, realpath } from "fs/promises";
|
|
27663
|
+
import { join as join46, resolve as resolve38, sep as sep10 } from "path";
|
|
27560
27664
|
import { Readable as Readable3 } from "stream";
|
|
27561
27665
|
var app68 = new Hono();
|
|
27562
27666
|
var TAG50 = "[portal-fetch]";
|
|
@@ -27612,7 +27716,7 @@ async function readAccountSecret(accountId) {
|
|
|
27612
27716
|
const path3 = resolve38(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
|
|
27613
27717
|
let text;
|
|
27614
27718
|
try {
|
|
27615
|
-
text = await
|
|
27719
|
+
text = await readFile10(path3, "utf8");
|
|
27616
27720
|
} catch {
|
|
27617
27721
|
console.error(`${TAG50} op=no-secret account="${accountId}" path="${path3}"`);
|
|
27618
27722
|
return "";
|
|
@@ -27629,7 +27733,7 @@ function isValidAccountId2(value) {
|
|
|
27629
27733
|
}
|
|
27630
27734
|
async function readExposeFolders2(accountDir) {
|
|
27631
27735
|
try {
|
|
27632
|
-
const cfg = JSON.parse(await
|
|
27736
|
+
const cfg = JSON.parse(await readFile10(join46(accountDir, "data-portal.json"), "utf8"));
|
|
27633
27737
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
27634
27738
|
} catch {
|
|
27635
27739
|
return [];
|
|
@@ -27638,7 +27742,7 @@ async function readExposeFolders2(accountDir) {
|
|
|
27638
27742
|
async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
27639
27743
|
let schemaText = null;
|
|
27640
27744
|
try {
|
|
27641
|
-
schemaText = await
|
|
27745
|
+
schemaText = await readFile10(join46(accountDir, "SCHEMA.md"), "utf8");
|
|
27642
27746
|
} catch {
|
|
27643
27747
|
schemaText = null;
|
|
27644
27748
|
}
|
|
@@ -27664,7 +27768,7 @@ async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
|
27664
27768
|
return { ok: false, reason: "not-exposed" };
|
|
27665
27769
|
}
|
|
27666
27770
|
try {
|
|
27667
|
-
const st = await
|
|
27771
|
+
const st = await stat9(absolute);
|
|
27668
27772
|
if (!st.isFile()) return { ok: false, reason: "enoent" };
|
|
27669
27773
|
return { ok: true, absolute, sizeBytes: st.size };
|
|
27670
27774
|
} catch {
|
|
@@ -27809,7 +27913,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
27809
27913
|
|
|
27810
27914
|
// app/lib/ledger-census.ts
|
|
27811
27915
|
import { readdirSync as readdirSync28, readFileSync as readFileSync45, statSync as statSync19 } from "fs";
|
|
27812
|
-
import { join as
|
|
27916
|
+
import { join as join47 } from "path";
|
|
27813
27917
|
|
|
27814
27918
|
// ../lib/ledger-core/dist/reconcile.js
|
|
27815
27919
|
var LEDGER_INDEX_NAMES = [
|
|
@@ -27863,7 +27967,7 @@ function countWriteRejects24h(logDir, now) {
|
|
|
27863
27967
|
}
|
|
27864
27968
|
let total = 0;
|
|
27865
27969
|
for (const name of entries2) {
|
|
27866
|
-
const path3 =
|
|
27970
|
+
const path3 = join47(logDir, name);
|
|
27867
27971
|
try {
|
|
27868
27972
|
if (now - statSync19(path3).mtimeMs > DAY_MS) continue;
|
|
27869
27973
|
for (const line of readFileSync45(path3, "utf8").split("\n")) {
|
|
@@ -28360,9 +28464,9 @@ async function migrateUploads(opts = {}) {
|
|
|
28360
28464
|
}
|
|
28361
28465
|
|
|
28362
28466
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
28363
|
-
import { readdir as readdir7, readFile as
|
|
28467
|
+
import { readdir as readdir7, readFile as readFile11, rename as rename4, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
|
|
28364
28468
|
import { existsSync as existsSync44 } from "fs";
|
|
28365
|
-
import { join as
|
|
28469
|
+
import { join as join48 } from "path";
|
|
28366
28470
|
var ADMIN_ROLE2 = "admin";
|
|
28367
28471
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
28368
28472
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -28373,7 +28477,7 @@ var defaultResolveName = async (_accountId, userId) => {
|
|
|
28373
28477
|
async function readRaw3(path3) {
|
|
28374
28478
|
let raw;
|
|
28375
28479
|
try {
|
|
28376
|
-
raw = await
|
|
28480
|
+
raw = await readFile11(path3, "utf8");
|
|
28377
28481
|
} catch {
|
|
28378
28482
|
return null;
|
|
28379
28483
|
}
|
|
@@ -28407,7 +28511,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28407
28511
|
}
|
|
28408
28512
|
for (const slug of slugs) {
|
|
28409
28513
|
if (!slug.isDirectory()) continue;
|
|
28410
|
-
const slugDir =
|
|
28514
|
+
const slugDir = join48(projectsRoot, slug.name);
|
|
28411
28515
|
let entries2;
|
|
28412
28516
|
try {
|
|
28413
28517
|
entries2 = await readdir7(slugDir, { withFileTypes: true });
|
|
@@ -28416,9 +28520,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28416
28520
|
}
|
|
28417
28521
|
for (const entry of entries2) {
|
|
28418
28522
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
28419
|
-
out.push(
|
|
28523
|
+
out.push(join48(slugDir, entry.name));
|
|
28420
28524
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
28421
|
-
const subDir =
|
|
28525
|
+
const subDir = join48(slugDir, entry.name);
|
|
28422
28526
|
let subs;
|
|
28423
28527
|
try {
|
|
28424
28528
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -28426,7 +28530,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28426
28530
|
continue;
|
|
28427
28531
|
}
|
|
28428
28532
|
for (const s of subs) {
|
|
28429
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
28533
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join48(subDir, s.name));
|
|
28430
28534
|
}
|
|
28431
28535
|
}
|
|
28432
28536
|
}
|
|
@@ -28438,7 +28542,7 @@ function shortId(path3) {
|
|
|
28438
28542
|
return base.slice(0, 8);
|
|
28439
28543
|
}
|
|
28440
28544
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
28441
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
28545
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join48(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
28442
28546
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
28443
28547
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
28444
28548
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -30737,7 +30841,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
30737
30841
|
|
|
30738
30842
|
// app/lib/telegram/outbound/send-document.ts
|
|
30739
30843
|
import { realpathSync as realpathSync10 } from "fs";
|
|
30740
|
-
import { readFile as
|
|
30844
|
+
import { readFile as readFile12, stat as stat11 } from "fs/promises";
|
|
30741
30845
|
import { resolve as resolve42, basename as basename13 } from "path";
|
|
30742
30846
|
var TAG56 = "[telegram:outbound]";
|
|
30743
30847
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
@@ -30778,7 +30882,7 @@ async function sendTelegramDocument(input) {
|
|
|
30778
30882
|
console.error(`${TAG56} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
30779
30883
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
30780
30884
|
}
|
|
30781
|
-
const fileStat = await
|
|
30885
|
+
const fileStat = await stat11(resolvedPath);
|
|
30782
30886
|
if (fileStat.size > TELEGRAM_DOCUMENT_MAX_BYTES) {
|
|
30783
30887
|
return {
|
|
30784
30888
|
ok: false,
|
|
@@ -30787,7 +30891,7 @@ async function sendTelegramDocument(input) {
|
|
|
30787
30891
|
};
|
|
30788
30892
|
}
|
|
30789
30893
|
const filename = basename13(resolvedPath);
|
|
30790
|
-
const buffer = Buffer.from(await
|
|
30894
|
+
const buffer = Buffer.from(await readFile12(resolvedPath));
|
|
30791
30895
|
const form = new FormData();
|
|
30792
30896
|
form.append("chat_id", String(chatId));
|
|
30793
30897
|
if (caption) form.append("caption", caption);
|
|
@@ -31238,8 +31342,8 @@ function resolveEntitlement(brand, account) {
|
|
|
31238
31342
|
if (!existsSync46(entitlementPath)) {
|
|
31239
31343
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
31240
31344
|
}
|
|
31241
|
-
const
|
|
31242
|
-
const key = memoKey(
|
|
31345
|
+
const stat12 = statSync20(entitlementPath);
|
|
31346
|
+
const key = memoKey(stat12.mtimeMs, account);
|
|
31243
31347
|
if (memo && memo.key === key) {
|
|
31244
31348
|
return memo.result;
|
|
31245
31349
|
}
|
|
@@ -31426,7 +31530,7 @@ function clientFrom(c) {
|
|
|
31426
31530
|
}
|
|
31427
31531
|
installMediaDownloadGuard();
|
|
31428
31532
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
31429
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
31533
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join49(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
31430
31534
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
31431
31535
|
if (BRAND_JSON_PATH && !existsSync47(BRAND_JSON_PATH)) {
|
|
31432
31536
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -31465,7 +31569,7 @@ var brandLoginOpts = {
|
|
|
31465
31569
|
appleTouchIconPath: brandAppIcon512Path,
|
|
31466
31570
|
themeColor: BRAND.defaultColors?.primary
|
|
31467
31571
|
};
|
|
31468
|
-
var ALIAS_DOMAINS_PATH =
|
|
31572
|
+
var ALIAS_DOMAINS_PATH = join49(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
31469
31573
|
function loadAliasDomains() {
|
|
31470
31574
|
try {
|
|
31471
31575
|
if (!existsSync47(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -31544,7 +31648,7 @@ var waGateway = new WaGateway({
|
|
|
31544
31648
|
fetchStandingRules: fetchAccountStandingRules,
|
|
31545
31649
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
31546
31650
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
31547
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
31651
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
31548
31652
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
31549
31653
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
31550
31654
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -31559,7 +31663,7 @@ var waGateway = new WaGateway({
|
|
|
31559
31663
|
caption,
|
|
31560
31664
|
accountId,
|
|
31561
31665
|
maxyAccountId,
|
|
31562
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
31666
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."))
|
|
31563
31667
|
});
|
|
31564
31668
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
31565
31669
|
},
|
|
@@ -31677,7 +31781,7 @@ function runDuplicateSenderAudit() {
|
|
|
31677
31781
|
try {
|
|
31678
31782
|
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
31679
31783
|
if (!configDir2) return;
|
|
31680
|
-
const projectsRoot =
|
|
31784
|
+
const projectsRoot = join49(configDir2, "projects");
|
|
31681
31785
|
const records = [];
|
|
31682
31786
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
31683
31787
|
if (isSubagent || archived) continue;
|
|
@@ -32343,7 +32447,7 @@ var SW_SOURCE = (() => {
|
|
|
32343
32447
|
function readInstalledVersion() {
|
|
32344
32448
|
try {
|
|
32345
32449
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
32346
|
-
const versionFile =
|
|
32450
|
+
const versionFile = join49(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
32347
32451
|
if (!existsSync47(versionFile)) return "unknown";
|
|
32348
32452
|
const content = readFileSync48(versionFile, "utf-8").trim();
|
|
32349
32453
|
return content || "unknown";
|
|
@@ -32403,11 +32507,11 @@ ${clientErrorReporterScript}
|
|
|
32403
32507
|
return html;
|
|
32404
32508
|
}
|
|
32405
32509
|
function loadBrandingCache(agentSlug) {
|
|
32406
|
-
const configDir2 =
|
|
32510
|
+
const configDir2 = join49(homedir4(), BRAND.configDir);
|
|
32407
32511
|
try {
|
|
32408
32512
|
const accountId = getDefaultAccountId();
|
|
32409
32513
|
if (!accountId) return null;
|
|
32410
|
-
const cachePath =
|
|
32514
|
+
const cachePath = join49(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
32411
32515
|
if (!existsSync47(cachePath)) return null;
|
|
32412
32516
|
return JSON.parse(readFileSync48(cachePath, "utf-8"));
|
|
32413
32517
|
} catch {
|
|
@@ -32638,7 +32742,7 @@ if (brandFaviconPath !== "/favicon.ico") {
|
|
|
32638
32742
|
return c.redirect(brandFaviconPath, 302);
|
|
32639
32743
|
});
|
|
32640
32744
|
}
|
|
32641
|
-
app69
|
|
32745
|
+
mountStaticFiles(app69, "./public");
|
|
32642
32746
|
app69.all("*", (c) => {
|
|
32643
32747
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32644
32748
|
const path3 = c.req.path;
|
|
@@ -32656,7 +32760,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
32656
32760
|
var httpServer = serve({ fetch: app69.fetch, port, hostname });
|
|
32657
32761
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
32658
32762
|
{
|
|
32659
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32763
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32660
32764
|
const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
32661
32765
|
const runReconcile = (ctx) => {
|
|
32662
32766
|
if (!existsSync47(reconcileScript)) return;
|
|
@@ -32679,7 +32783,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32679
32783
|
detached: true,
|
|
32680
32784
|
run: runReconcile
|
|
32681
32785
|
});
|
|
32682
|
-
const reconcileStatePath =
|
|
32786
|
+
const reconcileStatePath = join49(MAXY_DIR, "booking-reconcile-state.json");
|
|
32683
32787
|
registerLoop({
|
|
32684
32788
|
name: "calendar-reconcile-liveness",
|
|
32685
32789
|
intervalMs: 6e5,
|
|
@@ -32697,7 +32801,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32697
32801
|
}
|
|
32698
32802
|
{
|
|
32699
32803
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
32700
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32804
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32701
32805
|
const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
32702
32806
|
registerLoop({
|
|
32703
32807
|
name: "dream-cycle-sweep",
|
|
@@ -32721,7 +32825,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32721
32825
|
});
|
|
32722
32826
|
}
|
|
32723
32827
|
{
|
|
32724
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32828
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32725
32829
|
const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
32726
32830
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
32727
32831
|
const runOutlookComplete = (ctx) => {
|
|
@@ -32747,7 +32851,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32747
32851
|
});
|
|
32748
32852
|
}
|
|
32749
32853
|
{
|
|
32750
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32854
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32751
32855
|
const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
|
|
32752
32856
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
32753
32857
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -32777,7 +32881,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32777
32881
|
});
|
|
32778
32882
|
}
|
|
32779
32883
|
{
|
|
32780
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32884
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32781
32885
|
const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
|
|
32782
32886
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
32783
32887
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -32821,7 +32925,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32821
32925
|
});
|
|
32822
32926
|
}
|
|
32823
32927
|
{
|
|
32824
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32928
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32825
32929
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
32826
32930
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
32827
32931
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -32867,7 +32971,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32867
32971
|
});
|
|
32868
32972
|
}
|
|
32869
32973
|
{
|
|
32870
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
32974
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32871
32975
|
const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
32872
32976
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
32873
32977
|
const bookingAccounts = () => {
|
|
@@ -32944,7 +33048,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32944
33048
|
startTimeEntryCensus(() => getSession());
|
|
32945
33049
|
startLedgerCensus(() => getSession());
|
|
32946
33050
|
{
|
|
32947
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33051
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
|
|
32948
33052
|
const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
32949
33053
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
32950
33054
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -32989,19 +33093,17 @@ startAuthHealthHeartbeat();
|
|
|
32989
33093
|
{
|
|
32990
33094
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
32991
33095
|
loopHist.enable();
|
|
32992
|
-
const
|
|
33096
|
+
const LOUD_THRESHOLD_MS = 1e3;
|
|
32993
33097
|
const WINDOW_MS2 = 3e4;
|
|
32994
33098
|
registerLoop({
|
|
32995
33099
|
name: "event-loop-lag",
|
|
32996
33100
|
intervalMs: WINDOW_MS2,
|
|
32997
33101
|
run: () => {
|
|
32998
|
-
const
|
|
32999
|
-
const
|
|
33000
|
-
|
|
33001
|
-
|
|
33002
|
-
|
|
33003
|
-
}
|
|
33004
|
-
return `p99 ${Math.round(p99Ms)}ms, max ${Math.round(maxMs)}ms`;
|
|
33102
|
+
const w = readAndResetWindow(loopHist, WINDOW_MS2);
|
|
33103
|
+
const line = formatLagWindow(w);
|
|
33104
|
+
if (w.maxMs >= LOUD_THRESHOLD_MS) console.error(line);
|
|
33105
|
+
else console.log(line);
|
|
33106
|
+
return `p99 ${w.p99Ms}ms, max ${w.maxMs}ms`;
|
|
33005
33107
|
}
|
|
33006
33108
|
});
|
|
33007
33109
|
}
|
|
@@ -33254,7 +33356,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
33254
33356
|
}
|
|
33255
33357
|
init({
|
|
33256
33358
|
configDir: configDirForWhatsApp,
|
|
33257
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
33359
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..")),
|
|
33258
33360
|
accountConfig: bootAccountConfig,
|
|
33259
33361
|
onMessage: async (msg) => {
|
|
33260
33362
|
if (isObserveAccount(msg.accountId)) {
|