termdock 1.4.284 → 1.4.285
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/client/assets/App--hZmWk-u.js +157 -0
- package/dist/client/assets/App--hZmWk-u.js.br +0 -0
- package/dist/client/assets/App--hZmWk-u.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-Bvg7jZNw.js → ChangeWalkthroughPanel-BQ1hdwzt.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-BQ1hdwzt.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BQ1hdwzt.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-DSM5oYq3.js → DagPlayground-BERXHwib.js} +1 -1
- package/dist/client/assets/DagPlayground-BERXHwib.js.br +0 -0
- package/dist/client/assets/DagPlayground-BERXHwib.js.gz +0 -0
- package/dist/client/assets/{DiffLab-CgI11xY5.js → DiffLab-DF14_TAz.js} +1 -1
- package/dist/client/assets/DiffLab-DF14_TAz.js.br +0 -0
- package/dist/client/assets/DiffLab-DF14_TAz.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DOmoMEgC.js → DiffReview-BQcIn0zl.js} +1 -1
- package/dist/client/assets/DiffReview-BQcIn0zl.js.br +0 -0
- package/dist/client/assets/DiffReview-BQcIn0zl.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CEdM0rim.js → DiffReviewLab-CgChwzQr.js} +1 -1
- package/dist/client/assets/DiffReviewLab-CgChwzQr.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CgChwzQr.js.gz +0 -0
- package/dist/client/assets/DiffViewer-hDpe-wvG.js +37 -0
- package/dist/client/assets/DiffViewer-hDpe-wvG.js.br +0 -0
- package/dist/client/assets/DiffViewer-hDpe-wvG.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-DNiQACGL.js → ModelPreview-vg3vRIhx.js} +1 -1
- package/dist/client/assets/ModelPreview-vg3vRIhx.js.br +0 -0
- package/dist/client/assets/ModelPreview-vg3vRIhx.js.gz +0 -0
- package/dist/client/assets/RightSidebar-5H4vhn3k.js +1678 -0
- package/dist/client/assets/RightSidebar-5H4vhn3k.js.br +0 -0
- package/dist/client/assets/RightSidebar-5H4vhn3k.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-ByazGh0D.js → abnfDiagram-VCTEODGH-DI7938HB.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DI7938HB.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DI7938HB.js.gz +0 -0
- package/dist/client/assets/app-BeVXUQb-.js +35 -0
- package/dist/client/assets/app-BeVXUQb-.js.br +0 -0
- package/dist/client/assets/app-BeVXUQb-.js.gz +0 -0
- package/dist/client/assets/{arc-DMO5fEDY.js → arc-D4qDm5Yn.js} +1 -1
- package/dist/client/assets/arc-D4qDm5Yn.js.br +0 -0
- package/dist/client/assets/arc-D4qDm5Yn.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-c6WktFDt.js → architectureDiagram-5GKGNRK7-C4IZCNC9.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C4IZCNC9.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C4IZCNC9.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-CN0lQ7zu.js → blockDiagram-I7D4REHJ-DHVOr_jQ.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-DHVOr_jQ.js.br +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-CN0lQ7zu.js.gz → blockDiagram-I7D4REHJ-DHVOr_jQ.js.gz} +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-CALO2K48.js → c4Diagram-7LVT6UL2-kQqkOkIe.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-kQqkOkIe.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-kQqkOkIe.js.gz +0 -0
- package/dist/client/assets/channel-DNlwrmA4.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CcQPyBbp.js → chunk-2Q5K7J3B-D2kOR60I.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-CEp2aHuN.js → chunk-5VM5RSS4-CxaDg0nL.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-gRP8AiSl.js → chunk-F27PBJKO-Bxf7XPNj.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-Bxf7XPNj.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-Bxf7XPNj.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-BZewY7aF.js → chunk-IMKFNOWR-BTifpaB5.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-BTifpaB5.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BTifpaB5.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-C4S_lg0B.js → chunk-JWPE2WC7-Deieql_u.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-BgYxXL0V.js → chunk-POPQ4Y6H-CqZwUpjK.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-rjbdtq2C.js → chunk-SVP7TREG-Bm1spPMb.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-Bm1spPMb.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-Bm1spPMb.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-CxU1tNuL.js → chunk-TICWLB2K-BGLj-zGP.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-BGLj-zGP.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-BGLj-zGP.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-CSSO11_4.js → chunk-XXDRQBXY-CR77bUfc.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-CUt4JCwJ.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CUt4JCwJ.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-BiO-E-0q.js → cose-bilkent-JH36ORCC-GTawhnoV.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-GTawhnoV.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-GTawhnoV.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-DUC3zzns.js → cynefin-OW5HDTMX-DHdRkQdW.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-DHdRkQdW.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DHdRkQdW.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CR1RnhbU.js → cynefinDiagram-5FMLGOSQ-Cj2ytLun.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Cj2ytLun.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Cj2ytLun.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-d1joyB5v.js → dagre-GXQ25YYZ-BdFZmtIj.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-BdFZmtIj.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BdFZmtIj.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-izL3GdCu.js → diagram-S7CK7UJ4-D5WQNuKI.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-D5WQNuKI.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-D5WQNuKI.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-CjoFV2sD.js → diagram-UQ7AKVKN-ChwjfMce.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-ChwjfMce.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-ChwjfMce.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-BgHmsnTZ.js → diagram-VSXAHHWV-DT4FET5f.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-DT4FET5f.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-DT4FET5f.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-DMzRLNbg.js → diagram-VX7I27RA-BLJsAGx6.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-BLJsAGx6.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BLJsAGx6.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-kgWacykR.js → diagram-Z3DM3KII-C1ofLllK.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-C1ofLllK.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-C1ofLllK.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-XzSXtFGS.js → ebnfDiagram-PWID7BFC-apxDEeqe.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-apxDEeqe.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-apxDEeqe.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-Bu67_rUZ.js → erDiagram-RLTQ6QDP-Dq9hBYpH.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dq9hBYpH.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dq9hBYpH.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-BsK_b_G_.js → flowDiagram-HODETNUW-Juk-Qv9f.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-Juk-Qv9f.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-Juk-Qv9f.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-gCSBItav.js → ganttDiagram-EL5Y4UJY-mmwd0mxs.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-mmwd0mxs.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-mmwd0mxs.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-BOikQWZ8.js → gestureArbiter-CM_xJnCS.js} +1 -1
- package/dist/client/assets/gestureArbiter-CM_xJnCS.js.br +0 -0
- package/dist/client/assets/gestureArbiter-CM_xJnCS.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-DL0NSPPn.js → gitGraphDiagram-WWUBYQGX--UL7HV4P.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX--UL7HV4P.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX--UL7HV4P.js.gz +0 -0
- package/dist/client/assets/index-pZsldTFS.css +1 -0
- package/dist/client/assets/index-pZsldTFS.css.br +0 -0
- package/dist/client/assets/index-pZsldTFS.css.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-Cwevdubr.js → infoDiagram-27XIBGKW-CcsxyqYJ.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-pz1lzDd4.js → ishikawaDiagram-5VMMS53U-CNVFPx1_.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CNVFPx1_.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CNVFPx1_.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-BrUnjTGd.js → journeyDiagram-3NMN7TZE-BtIuJLUp.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BtIuJLUp.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BtIuJLUp.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-BKf4UYyB.js → kanban-definition-UXKFOSKX-gOFjuFZV.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-gOFjuFZV.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-gOFjuFZV.js.gz +0 -0
- package/dist/client/assets/{layout-Dd_yzBVh.js → layout-KEP24zEE.js} +1 -1
- package/dist/client/assets/layout-KEP24zEE.js.br +0 -0
- package/dist/client/assets/layout-KEP24zEE.js.gz +0 -0
- package/dist/client/assets/{linear-iY7daKXS.js → linear-BwUXWDLn.js} +1 -1
- package/dist/client/assets/linear-BwUXWDLn.js.br +0 -0
- package/dist/client/assets/linear-BwUXWDLn.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-CYNb258G.js → mermaid.core-DkzJYwWa.js} +5 -5
- package/dist/client/assets/mermaid.core-DkzJYwWa.js.br +0 -0
- package/dist/client/assets/mermaid.core-DkzJYwWa.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-ctnc7JBK.js → mindmap-definition-YA3MSWOX-BE1H8WPd.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BE1H8WPd.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BE1H8WPd.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-Bth6QB9C.js → passwordBootstrap-Dhzj9-U2.js} +1 -1
- package/dist/client/assets/passwordBootstrap-Dhzj9-U2.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Dhzj9-U2.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-DVKAZXxP.js → pegDiagram-XKGWAZYB-CorBwvfP.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-CorBwvfP.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-CorBwvfP.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-C0u6lfoS.js → pieDiagram-E7YTZNPT-A017Uk-W.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-A017Uk-W.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-A017Uk-W.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DXFDUoYJ.js → quadrantDiagram-AXDQQJYC-CNNywvhG.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CNNywvhG.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CNNywvhG.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-Cz-wrQ4E.js → railroadDiagram-O6MQD6OU-DIxiWn5A.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DIxiWn5A.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DIxiWn5A.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-BMcpaynk.js → referenceLongPress-Bp8q50sv.js} +1 -1
- package/dist/client/assets/referenceLongPress-Bp8q50sv.js.br +0 -0
- package/dist/client/assets/referenceLongPress-Bp8q50sv.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-DdFhwbqd.js → requirementDiagram-BXWQKSXE-Ob4lS23U.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Ob4lS23U.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Ob4lS23U.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DIEO7iin.js → sankeyDiagram-P5KCCOFB-Cc5e7umb.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Cc5e7umb.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Cc5e7umb.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-0Jq8ZpjE.js → sequenceDiagram-WJ2MYXX4-CLTRKFht.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CLTRKFht.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CLTRKFht.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CzkB3_L-.js → sizeCapture-INFHLROL-h6hFhQw6.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-h6hFhQw6.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-h6hFhQw6.js.gz +0 -0
- package/dist/client/assets/{sparkles-OssC7CZI.js → sparkles-9OJtJfyK.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-B1UZvmmJ.js → stateDiagram-D77RDMKH-DSaJxX_r.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-DSaJxX_r.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DSaJxX_r.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CQ9iS9Nl.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-CwBFrD7Q.js → swimlanes-42K2YHIH-CP7ABWyE.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-CP7ABWyE.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-CP7ABWyE.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BbfCRvRt.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-Cgrwm9y7.js → timeline-definition-24CTP7MA-CdwVIVF6.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-CdwVIVF6.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-CdwVIVF6.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-gfowObfL.js → triangle-alert-BvT4KSYf.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-JVQ9D_hy.js → vennDiagram-4TSXK5OY-BXGgQFVY.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-JVQ9D_hy.js.br → vennDiagram-4TSXK5OY-BXGgQFVY.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BXGgQFVY.js.gz +0 -0
- package/dist/client/assets/{videoCompression-D1SrM0Eo.js → videoCompression-BFXJyhpz.js} +1 -1
- package/dist/client/assets/videoCompression-BFXJyhpz.js.br +0 -0
- package/dist/client/assets/videoCompression-BFXJyhpz.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-BsmpGt9d.js → wardleyDiagram-VM6X3IG4-CtLophqU.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-CtLophqU.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-CtLophqU.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-C33-nORD.js → xychartDiagram-S5SC5T6Z-YZ9bnI1e.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-YZ9bnI1e.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-YZ9bnI1e.js.gz +0 -0
- package/dist/client/index.html +2 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/agent/collaborationCli.js +11 -3
- package/dist/server/agent/collaborationGroupRoutes.js +18 -0
- package/dist/server/agent/collaborationPeerTransport.js +19 -1
- package/dist/server/agent/collaborationRoutes.js +12 -0
- package/dist/server/agent/collaborationService.js +83 -8
- package/dist/server/agent/nativeSessionSearch.js +84 -0
- package/dist/server/agent/sessionSearchStore.js +2 -1
- package/dist/server/federation/trustedCa.js +9 -2
- package/dist/server/routes/filesystem.js +43 -1
- package/dist/server/routes/terminal.js +118 -10
- package/dist/server/utils/settings.js +14 -0
- package/dist/server/workers/nativeSessionSearchWorker.js +416 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-BgEYOR8Z.js +0 -157
- package/dist/client/assets/App-BgEYOR8Z.js.br +0 -0
- package/dist/client/assets/App-BgEYOR8Z.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-Bvg7jZNw.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-Bvg7jZNw.js.gz +0 -0
- package/dist/client/assets/DagPlayground-DSM5oYq3.js.br +0 -0
- package/dist/client/assets/DagPlayground-DSM5oYq3.js.gz +0 -0
- package/dist/client/assets/DiffLab-CgI11xY5.js.br +0 -0
- package/dist/client/assets/DiffLab-CgI11xY5.js.gz +0 -0
- package/dist/client/assets/DiffReview-DOmoMEgC.js.br +0 -0
- package/dist/client/assets/DiffReview-DOmoMEgC.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CEdM0rim.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CEdM0rim.js.gz +0 -0
- package/dist/client/assets/DiffViewer-CI3JmNyq.js +0 -37
- package/dist/client/assets/DiffViewer-CI3JmNyq.js.br +0 -0
- package/dist/client/assets/DiffViewer-CI3JmNyq.js.gz +0 -0
- package/dist/client/assets/ModelPreview-DNiQACGL.js.br +0 -0
- package/dist/client/assets/ModelPreview-DNiQACGL.js.gz +0 -0
- package/dist/client/assets/RightSidebar-CpPgHZEU.js +0 -1678
- package/dist/client/assets/RightSidebar-CpPgHZEU.js.br +0 -0
- package/dist/client/assets/RightSidebar-CpPgHZEU.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-ByazGh0D.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-ByazGh0D.js.gz +0 -0
- package/dist/client/assets/app-UpvbJ3fT.js +0 -35
- package/dist/client/assets/app-UpvbJ3fT.js.br +0 -0
- package/dist/client/assets/app-UpvbJ3fT.js.gz +0 -0
- package/dist/client/assets/arc-DMO5fEDY.js.br +0 -0
- package/dist/client/assets/arc-DMO5fEDY.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-c6WktFDt.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-c6WktFDt.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CN0lQ7zu.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CALO2K48.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CALO2K48.js.gz +0 -0
- package/dist/client/assets/channel-DcmoMLL-.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-gRP8AiSl.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-gRP8AiSl.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BZewY7aF.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BZewY7aF.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-rjbdtq2C.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-rjbdtq2C.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CxU1tNuL.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CxU1tNuL.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-VSirHVcP.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-VSirHVcP.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-BiO-E-0q.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BiO-E-0q.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DUC3zzns.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DUC3zzns.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CR1RnhbU.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CR1RnhbU.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-d1joyB5v.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-d1joyB5v.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-izL3GdCu.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-izL3GdCu.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-CjoFV2sD.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-CjoFV2sD.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-BgHmsnTZ.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-BgHmsnTZ.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DMzRLNbg.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DMzRLNbg.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-kgWacykR.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-kgWacykR.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-XzSXtFGS.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-XzSXtFGS.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Bu67_rUZ.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Bu67_rUZ.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BsK_b_G_.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BsK_b_G_.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-gCSBItav.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-gCSBItav.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-BOikQWZ8.js.br +0 -0
- package/dist/client/assets/gestureArbiter-BOikQWZ8.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DL0NSPPn.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DL0NSPPn.js.gz +0 -0
- package/dist/client/assets/index-Bv-r5mB7.css +0 -1
- package/dist/client/assets/index-Bv-r5mB7.css.br +0 -0
- package/dist/client/assets/index-Bv-r5mB7.css.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-pz1lzDd4.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-pz1lzDd4.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BrUnjTGd.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BrUnjTGd.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BKf4UYyB.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BKf4UYyB.js.gz +0 -0
- package/dist/client/assets/layout-Dd_yzBVh.js.br +0 -0
- package/dist/client/assets/layout-Dd_yzBVh.js.gz +0 -0
- package/dist/client/assets/linear-iY7daKXS.js.br +0 -0
- package/dist/client/assets/linear-iY7daKXS.js.gz +0 -0
- package/dist/client/assets/mermaid.core-CYNb258G.js.br +0 -0
- package/dist/client/assets/mermaid.core-CYNb258G.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-ctnc7JBK.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-ctnc7JBK.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-Bth6QB9C.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Bth6QB9C.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DVKAZXxP.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DVKAZXxP.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-C0u6lfoS.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-C0u6lfoS.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DXFDUoYJ.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DXFDUoYJ.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Cz-wrQ4E.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Cz-wrQ4E.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-BMcpaynk.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BMcpaynk.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DdFhwbqd.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DdFhwbqd.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-DIEO7iin.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-DIEO7iin.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-0Jq8ZpjE.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-0Jq8ZpjE.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CzkB3_L-.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CzkB3_L-.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-B1UZvmmJ.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-B1UZvmmJ.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-Cmg877fp.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-CwBFrD7Q.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-CwBFrD7Q.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CjR47hdK.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-Cgrwm9y7.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-Cgrwm9y7.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-JVQ9D_hy.js.gz +0 -0
- package/dist/client/assets/videoCompression-D1SrM0Eo.js.br +0 -0
- package/dist/client/assets/videoCompression-D1SrM0Eo.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BsmpGt9d.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BsmpGt9d.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-C33-nORD.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-C33-nORD.js.gz +0 -0
|
@@ -33,6 +33,15 @@ export class CollaborationService {
|
|
|
33
33
|
throw new Error('INVALID_DIRECTORY');
|
|
34
34
|
for (const peer of data.peers)
|
|
35
35
|
validateCollaborationNode(peer);
|
|
36
|
+
if (data.removedPeers !== undefined) {
|
|
37
|
+
if (!Array.isArray(data.removedPeers) || data.removedPeers.length > 768)
|
|
38
|
+
throw new Error('INVALID_DIRECTORY');
|
|
39
|
+
for (const peer of data.removedPeers) {
|
|
40
|
+
validateCollaborationNode(peer);
|
|
41
|
+
if (peer.scope && !/^12D3KooW[a-zA-Z0-9]{30,60}$/.test(peer.scope.device))
|
|
42
|
+
throw new Error('INVALID_DIRECTORY');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
36
45
|
if (data.scoped !== undefined) {
|
|
37
46
|
if (!data.scoped || typeof data.scoped !== 'object' || Array.isArray(data.scoped))
|
|
38
47
|
throw new Error('INVALID_DIRECTORY');
|
|
@@ -61,10 +70,12 @@ export class CollaborationService {
|
|
|
61
70
|
throw new Error('COLLABORATION_ORIGIN_REQUIRED'); const node = { ...this.options.node(), origin }; validateCollaborationNode(node); return node; }
|
|
62
71
|
setOrigin(origin) { this.node(origin); if (this.document.origin && this.document.origin !== origin)
|
|
63
72
|
throw new Error('COLLABORATION_ORIGIN_MISMATCH'); this.document.origin = origin; }
|
|
64
|
-
remember(node) {
|
|
73
|
+
remember(node, explicitPair = false) {
|
|
65
74
|
validateCollaborationNode(node);
|
|
66
75
|
if (node.serviceId === this.options.node().serviceId || node.origin === this.document.origin)
|
|
67
76
|
throw new Error('CANNOT_PAIR_SELF');
|
|
77
|
+
if (this.document.removedPeers?.some(peer => peer.serviceId === node.serviceId) && !explicitPair)
|
|
78
|
+
throw new Error('COLLABORATION_PEER_REMOVED');
|
|
68
79
|
const old = this.document.peers.find(peer => peer.serviceId === node.serviceId || peer.origin === node.origin);
|
|
69
80
|
if (old && (old.serviceId !== node.serviceId || old.origin !== node.origin || old.caFingerprint256 !== node.caFingerprint256))
|
|
70
81
|
throw new Error('PEER_IDENTITY_CHANGED');
|
|
@@ -73,6 +84,8 @@ export class CollaborationService {
|
|
|
73
84
|
throw new Error('PEER_LIMIT');
|
|
74
85
|
this.document.peers.push(node);
|
|
75
86
|
}
|
|
87
|
+
if (explicitPair)
|
|
88
|
+
this.document.removedPeers = this.document.removedPeers?.filter(peer => peer.serviceId !== node.serviceId);
|
|
76
89
|
this.persist();
|
|
77
90
|
}
|
|
78
91
|
descriptor() { return { ...this.options.node(), ...(this.document.origin ? { origin: this.document.origin } : {}) }; }
|
|
@@ -96,14 +109,72 @@ export class CollaborationService {
|
|
|
96
109
|
if (old && (old.serviceId !== node.serviceId || old.origin !== node.origin || old.caFingerprint256 !== node.caFingerprint256))
|
|
97
110
|
throw new Error('PEER_IDENTITY_CHANGED');
|
|
98
111
|
}
|
|
99
|
-
|
|
112
|
+
const removed = new Set(this.document.removedPeers?.map(peer => peer.serviceId));
|
|
113
|
+
const eligible = nodes.filter(node => node.serviceId !== self.serviceId && !removed.has(node.serviceId));
|
|
114
|
+
if (new Set([...this.document.peers.map(peer => peer.serviceId), ...eligible.map(node => node.serviceId)]).size > 63)
|
|
100
115
|
throw new Error('PEER_LIMIT');
|
|
101
116
|
this.setOrigin(origin);
|
|
102
|
-
this.document.peers = [...new Map([...this.document.peers, ...
|
|
117
|
+
this.document.peers = [...new Map([...this.document.peers, ...eligible].map(node => [node.serviceId, node])).values()];
|
|
103
118
|
this.persist();
|
|
104
119
|
void this.refresh();
|
|
105
120
|
return { ok: true, registered: this.document.peers.map(peer => peer.serviceId) };
|
|
106
121
|
}
|
|
122
|
+
groupsUsing(peer) {
|
|
123
|
+
return this.options.store.list().filter(group => group.sessionIds.some(id => address(id)?.origin === peer.origin)
|
|
124
|
+
|| group.federated && this.document.replicas?.[group.id]?.includes(peer.origin)).map(group => ({ id: group.id, name: group.name }));
|
|
125
|
+
}
|
|
126
|
+
/** Explicit removal is durable: other open clients may still enroll their
|
|
127
|
+
* stale saved catalogs, but only a deliberate restore or pairing re-adds it. */
|
|
128
|
+
removePeer(serviceId) {
|
|
129
|
+
const peer = this.document.peers.find(item => item.serviceId === serviceId);
|
|
130
|
+
if (!peer)
|
|
131
|
+
throw new CollaborationError('PEER_NOT_FOUND', '该协作服务已移除,请刷新列表', 404);
|
|
132
|
+
const groups = this.groupsUsing(peer);
|
|
133
|
+
if (groups.length)
|
|
134
|
+
throw new CollaborationError('PEER_IN_USE', `该服务仍用于协作组「${groups.map(group => group.name).join('」「')}」,请先移出对应成员或删除协作组`, 409, { groups });
|
|
135
|
+
this.options.transport.forgetUnusedPeer(serviceId);
|
|
136
|
+
const previous = this.document;
|
|
137
|
+
const scope = previous.scoped?.[serviceId];
|
|
138
|
+
this.document = { ...previous, peers: previous.peers.filter(item => item.serviceId !== serviceId),
|
|
139
|
+
scoped: Object.fromEntries(Object.entries(previous.scoped ?? {}).filter(([id]) => id !== serviceId)),
|
|
140
|
+
removedPeers: [...(previous.removedPeers ?? []).filter(item => item.serviceId !== serviceId), { ...peer, ...(scope ? { scope } : {}) }].slice(-768) };
|
|
141
|
+
try {
|
|
142
|
+
this.persist();
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.document = previous;
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
const client = this.clients.get(serviceId);
|
|
149
|
+
this.clients.delete(serviceId);
|
|
150
|
+
this.observations.delete(serviceId);
|
|
151
|
+
if (client)
|
|
152
|
+
void client.then(rpc => rpc.close()).catch(() => { });
|
|
153
|
+
return { ok: true, origin: peer.origin };
|
|
154
|
+
}
|
|
155
|
+
restorePeer(serviceId) {
|
|
156
|
+
const removed = this.document.removedPeers?.find(item => item.serviceId === serviceId);
|
|
157
|
+
if (!removed)
|
|
158
|
+
throw new CollaborationError('PEER_NOT_FOUND', '找不到这条已移除的协作连接', 404);
|
|
159
|
+
const { scope, ...node } = removed;
|
|
160
|
+
validateCollaborationNode(node);
|
|
161
|
+
if (this.document.peers.some(peer => peer.serviceId === node.serviceId || peer.origin === node.origin))
|
|
162
|
+
throw new CollaborationError('PEER_IDENTITY_CHANGED', '该地址已属于另一条服务连接,请重新配对', 409);
|
|
163
|
+
if (this.document.peers.length >= 63)
|
|
164
|
+
throw new CollaborationError('PEER_LIMIT', '协作服务数量已达上限', 400);
|
|
165
|
+
const previous = this.document;
|
|
166
|
+
this.document = { ...previous, peers: [...previous.peers, node], removedPeers: previous.removedPeers?.filter(item => item.serviceId !== serviceId),
|
|
167
|
+
scoped: { ...previous.scoped, ...(scope ? { [serviceId]: scope } : {}) } };
|
|
168
|
+
try {
|
|
169
|
+
this.persist();
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
this.document = previous;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
void this.refresh();
|
|
176
|
+
return { ok: true, origin: node.origin };
|
|
177
|
+
}
|
|
107
178
|
/** Effective local sessions a peer may touch. `undefined` means a fully
|
|
108
179
|
* authorized directory peer; an array (possibly empty) means a peer that
|
|
109
180
|
* exists only because a device shared a write invitation for those sessions. */
|
|
@@ -157,7 +228,7 @@ export class CollaborationService {
|
|
|
157
228
|
const rpc = await (this.options.pairConnect ?? this.options.connect)(invitation.node);
|
|
158
229
|
try {
|
|
159
230
|
await rpc.request({ type: 'collaboration-service', action: 'pair', code: invitation.code, node: this.node() });
|
|
160
|
-
this.remember(invitation.node);
|
|
231
|
+
this.remember(invitation.node, true);
|
|
161
232
|
void this.refresh();
|
|
162
233
|
return { ok: true, peer: invitation.node };
|
|
163
234
|
}
|
|
@@ -178,7 +249,7 @@ export class CollaborationService {
|
|
|
178
249
|
if (offer.acceptedBy && !this.document.peers.some(peer => peer.serviceId === subject))
|
|
179
250
|
throw new Error('PAIRING_REVOKED');
|
|
180
251
|
offer.acceptedBy = subject;
|
|
181
|
-
this.remember(node);
|
|
252
|
+
this.remember(node, true);
|
|
182
253
|
void this.refresh();
|
|
183
254
|
return { ok: true };
|
|
184
255
|
}
|
|
@@ -298,6 +369,8 @@ export class CollaborationService {
|
|
|
298
369
|
try {
|
|
299
370
|
const client = await this.client(peer);
|
|
300
371
|
const data = await client.request({ type: 'collaboration-service', action: 'directory' });
|
|
372
|
+
if (!this.document.peers.some(item => item.serviceId === peer.serviceId))
|
|
373
|
+
return;
|
|
301
374
|
if (!Array.isArray(data.sessions) || data.sessions.length > 5000 || !Array.isArray(data.groups))
|
|
302
375
|
throw new Error('INVALID_DIRECTORY');
|
|
303
376
|
const sessions = data.sessions.filter((s) => s && typeof s.sessionId === 'string' && !s.sessionId.startsWith('remote:'));
|
|
@@ -318,7 +391,8 @@ export class CollaborationService {
|
|
|
318
391
|
}
|
|
319
392
|
}
|
|
320
393
|
catch (error) {
|
|
321
|
-
this.
|
|
394
|
+
if (this.document.peers.some(item => item.serviceId === peer.serviceId))
|
|
395
|
+
this.observations.set(peer.serviceId, { sessions: this.observations.get(peer.serviceId)?.sessions ?? [], checkedAt: Date.now(), error: error instanceof Error ? error.message.slice(0, 240) : 'PEER_UNAVAILABLE' });
|
|
322
396
|
}
|
|
323
397
|
})).then(() => { }).finally(() => { this.inFlight = undefined; });
|
|
324
398
|
}
|
|
@@ -328,12 +402,13 @@ export class CollaborationService {
|
|
|
328
402
|
const services = this.document.peers.map(peer => {
|
|
329
403
|
const observed = this.observations.get(peer.serviceId);
|
|
330
404
|
return { origin: peer.origin, serviceId: peer.serviceId, label: peer.origin,
|
|
331
|
-
connected: !!observed && !observed.error && Date.now() - observed.checkedAt < 15_000, error: observed?.error ?? (!observed ? 'CONNECTING' : undefined) };
|
|
405
|
+
groups: this.groupsUsing(peer), connected: !!observed && !observed.error && Date.now() - observed.checkedAt < 15_000, error: observed?.error ?? (!observed ? 'CONNECTING' : undefined) };
|
|
332
406
|
});
|
|
333
407
|
return { protocolVersion: 2, sessions: this.document.peers.flatMap(peer => this.document.scoped?.[peer.serviceId] ? [] : (this.observations.get(peer.serviceId)?.sessions ?? []).map(session => ({ ...session,
|
|
334
408
|
sessionId: remoteSession(peer.origin, session.sessionId), backendSessionId: null, agentNativeSessionId: null, serviceOrigin: peer.origin, serviceLabel: peer.origin,
|
|
335
409
|
serviceConnected: services.find(s => s.origin === peer.origin).connected, serviceCheckedAt: this.observations.get(peer.serviceId)?.checkedAt }))),
|
|
336
|
-
services: [...services, ...missing.map(origin => ({ origin, label: origin, connected: false, error: '服务连接授权尚未同步;在已授权服务页面连接后会自动完成' }))]
|
|
410
|
+
services: [...services, ...missing.map(origin => ({ origin, label: origin, connected: false, error: '服务连接授权尚未同步;在已授权服务页面连接后会自动完成' }))],
|
|
411
|
+
removedServices: this.document.removedPeers?.map(peer => ({ serviceId: peer.serviceId, origin: peer.origin, label: peer.origin, connected: false })) ?? [] };
|
|
337
412
|
}
|
|
338
413
|
async save(input) {
|
|
339
414
|
const existing = input.id ? this.options.store.getGroup(input.id) : null;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { Worker } from 'node:worker_threads';
|
|
5
|
+
/** Keep transcript parsing and text scans off the terminal server's event loop.
|
|
6
|
+
* The worker and its private, incremental cache start only when search is used.
|
|
7
|
+
*/
|
|
8
|
+
export class NativeSessionSearch {
|
|
9
|
+
directory;
|
|
10
|
+
worker = null;
|
|
11
|
+
sequence = 0;
|
|
12
|
+
pending = new Map();
|
|
13
|
+
constructor(directory) {
|
|
14
|
+
this.directory = directory;
|
|
15
|
+
}
|
|
16
|
+
search(query, limit, titles, signal) {
|
|
17
|
+
return this.request({ type: 'search', query, limit, titles }, signal);
|
|
18
|
+
}
|
|
19
|
+
get(key) {
|
|
20
|
+
return this.request({ type: 'get', key });
|
|
21
|
+
}
|
|
22
|
+
request(input, signal) {
|
|
23
|
+
if (signal?.aborted)
|
|
24
|
+
return Promise.reject(new Error('搜索已取消'));
|
|
25
|
+
if (!this.worker) {
|
|
26
|
+
const compiled = new URL('../workers/nativeSessionSearchWorker.js', import.meta.url);
|
|
27
|
+
// tsx development runs source files; production always uses compiled JS.
|
|
28
|
+
const url = fs.existsSync(compiled) ? compiled : new URL('../workers/nativeSessionSearchWorker.ts', import.meta.url);
|
|
29
|
+
this.worker = new Worker(url, { workerData: {
|
|
30
|
+
directory: this.directory,
|
|
31
|
+
codexHome: process.env.CODEX_HOME || path.join(os.homedir(), '.codex'),
|
|
32
|
+
claudeHome: process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude'),
|
|
33
|
+
} });
|
|
34
|
+
const worker = this.worker;
|
|
35
|
+
worker.unref();
|
|
36
|
+
worker.on('message', (message) => {
|
|
37
|
+
const entry = this.pending.get(message.id);
|
|
38
|
+
if (!entry)
|
|
39
|
+
return;
|
|
40
|
+
clearTimeout(entry.timer);
|
|
41
|
+
entry.cleanup();
|
|
42
|
+
this.pending.delete(message.id);
|
|
43
|
+
if (message.error)
|
|
44
|
+
entry.reject(new Error(message.error));
|
|
45
|
+
else
|
|
46
|
+
entry.resolve(message.value);
|
|
47
|
+
});
|
|
48
|
+
const fail = (error) => {
|
|
49
|
+
if (this.worker !== worker)
|
|
50
|
+
return;
|
|
51
|
+
this.worker = null;
|
|
52
|
+
for (const entry of this.pending.values()) {
|
|
53
|
+
clearTimeout(entry.timer);
|
|
54
|
+
entry.cleanup();
|
|
55
|
+
entry.reject(error);
|
|
56
|
+
}
|
|
57
|
+
this.pending.clear();
|
|
58
|
+
void worker.terminate();
|
|
59
|
+
};
|
|
60
|
+
worker.on('error', fail);
|
|
61
|
+
worker.on('exit', () => fail(new Error('历史会话索引服务已退出,请重新搜索')));
|
|
62
|
+
}
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
const id = ++this.sequence;
|
|
65
|
+
const worker = this.worker;
|
|
66
|
+
const cancel = () => {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
this.pending.delete(id);
|
|
69
|
+
signal?.removeEventListener('abort', cancel);
|
|
70
|
+
worker.postMessage({ id, type: 'cancel' });
|
|
71
|
+
reject(new Error('搜索已取消'));
|
|
72
|
+
};
|
|
73
|
+
const timer = setTimeout(() => {
|
|
74
|
+
this.pending.delete(id);
|
|
75
|
+
signal?.removeEventListener('abort', cancel);
|
|
76
|
+
worker.postMessage({ id, type: 'cancel' });
|
|
77
|
+
reject(new Error('历史会话搜索超时,请缩短关键词后重试'));
|
|
78
|
+
}, 60_000);
|
|
79
|
+
this.pending.set(id, { resolve, reject, timer, cleanup: () => signal?.removeEventListener('abort', cancel) });
|
|
80
|
+
signal?.addEventListener('abort', cancel, { once: true });
|
|
81
|
+
worker.postMessage({ id, ...input });
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -53,7 +53,8 @@ export class SessionSearchStore {
|
|
|
53
53
|
this.flush();
|
|
54
54
|
const needle = query.trim().toLocaleLowerCase();
|
|
55
55
|
if (!needle)
|
|
56
|
-
return []
|
|
56
|
+
return [...this.metadata.values()].sort((a, b) => b.updatedAt - a.updatedAt)
|
|
57
|
+
.slice(0, Math.max(1, Math.min(limit, 100))).map(metadata => ({ ...metadata, snippet: '', matchCount: 0 }));
|
|
57
58
|
const results = [];
|
|
58
59
|
for (const metadata of this.metadata.values()) {
|
|
59
60
|
const text = this.readLog(metadata.sessionId);
|
|
@@ -14,7 +14,8 @@ export function readPinnedCertificateAuthority(origin, fingerprint) {
|
|
|
14
14
|
if (cached && cached.expires > Date.now())
|
|
15
15
|
return cached.value;
|
|
16
16
|
const value = new Promise((resolve, reject) => {
|
|
17
|
-
const
|
|
17
|
+
const signal = AbortSignal.timeout(5000);
|
|
18
|
+
const request = get(url, { agent: false, rejectUnauthorized: false, signal }, response => {
|
|
18
19
|
if (response.statusCode !== 200) {
|
|
19
20
|
response.resume();
|
|
20
21
|
reject(new Error('Pinned certificate authority unavailable'));
|
|
@@ -44,7 +45,13 @@ export function readPinnedCertificateAuthority(origin, fingerprint) {
|
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
});
|
|
47
|
-
request.on('error',
|
|
48
|
+
request.on('error', error => {
|
|
49
|
+
if (signal.aborted && signal.reason?.name === 'TimeoutError') {
|
|
50
|
+
reject(new Error(`连接 ${url.origin} 超时(5 秒):未能读取远端服务证书,请确认远端服务已启动且网络可达`, { cause: error }));
|
|
51
|
+
}
|
|
52
|
+
else
|
|
53
|
+
reject(error);
|
|
54
|
+
});
|
|
48
55
|
});
|
|
49
56
|
if (cache.size >= 64)
|
|
50
57
|
cache.delete(cache.keys().next().value);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getHideGitIgnoredRootsSetting } from '../utils/settings.js';
|
|
1
2
|
import { readRecentCommitHistory } from '../utils/recentCommitHistory.js';
|
|
2
3
|
import { AUTH_COOKIE, isSessionValid } from '../utils/authProtection.js';
|
|
3
4
|
import { Router } from 'express';
|
|
@@ -2703,6 +2704,35 @@ async function getCachedNestedGitRoots(workspaceRoot, options = {}) {
|
|
|
2703
2704
|
}
|
|
2704
2705
|
return promise;
|
|
2705
2706
|
}
|
|
2707
|
+
// Ask Git in one batch so nested .gitignore, .git/info/exclude and global
|
|
2708
|
+
// exclusions follow Git semantics; NUL separators preserve unusual filenames.
|
|
2709
|
+
function getGitIgnoredPaths(directory, entries, signal) {
|
|
2710
|
+
if (entries.length === 0)
|
|
2711
|
+
return Promise.resolve(new Set());
|
|
2712
|
+
return new Promise((resolve, reject) => {
|
|
2713
|
+
const proc = execFile('git', ['check-ignore', '-z', '--stdin'], {
|
|
2714
|
+
cwd: directory,
|
|
2715
|
+
timeout: GIT_TIMEOUT_MS,
|
|
2716
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
2717
|
+
signal,
|
|
2718
|
+
}, (error, stdout, stderr) => {
|
|
2719
|
+
if (error && error.code !== 1) {
|
|
2720
|
+
// Ordinary non-repository directories remain browsable with the filter.
|
|
2721
|
+
if (error.code === 'ENOENT' || /not a git repository/i.test(stderr)) {
|
|
2722
|
+
resolve(new Set());
|
|
2723
|
+
}
|
|
2724
|
+
else {
|
|
2725
|
+
reject(error);
|
|
2726
|
+
}
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
resolve(new Set(stdout.split('\0').filter(Boolean)));
|
|
2730
|
+
});
|
|
2731
|
+
// Git may exit before consuming stdin (e.g. outside a repository).
|
|
2732
|
+
proc.stdin?.on('error', () => undefined);
|
|
2733
|
+
proc.stdin?.end(entries.map((entry) => path.join(directory, entry.name)).join('\0') + '\0');
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2706
2736
|
// Directory listing
|
|
2707
2737
|
router.get('/list', async (req, res) => {
|
|
2708
2738
|
const requestId = ++fsIoRequestSeq;
|
|
@@ -2735,7 +2765,19 @@ router.get('/list', async (req, res) => {
|
|
|
2735
2765
|
const sortMode = req.query.sort === 'modified' ? 'modified' : 'name';
|
|
2736
2766
|
const allEntries = await fs.promises.readdir(resolvedPath, { withFileTypes: true });
|
|
2737
2767
|
throwIfAborted(controller.signal, 'fs.list');
|
|
2738
|
-
|
|
2768
|
+
let visibleDirents = allEntries.filter(dirent => showHidden || !dirent.name.startsWith('.'));
|
|
2769
|
+
const gitIgnoreRoot = typeof req.query.gitIgnoreRoot === 'string' ? req.query.gitIgnoreRoot : null;
|
|
2770
|
+
if (gitIgnoreRoot && getHideGitIgnoredRootsSetting()[gitIgnoreRoot]) {
|
|
2771
|
+
const resolvedRoot = await pathValidator.validatePathAsync(gitIgnoreRoot);
|
|
2772
|
+
const relative = path.relative(resolvedRoot, resolvedPath);
|
|
2773
|
+
if (relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))) {
|
|
2774
|
+
const ignored = await getGitIgnoredPaths(resolvedPath, visibleDirents, controller.signal);
|
|
2775
|
+
throwIfAborted(controller.signal, 'fs.list');
|
|
2776
|
+
// Filter before sorting and capping so ignored folders don't crowd
|
|
2777
|
+
// useful files out of the first page of a large directory.
|
|
2778
|
+
visibleDirents = visibleDirents.filter((entry) => entry.name !== '.git' && !ignored.has(path.join(resolvedPath, entry.name)));
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2739
2781
|
const entries = sortMode === 'modified'
|
|
2740
2782
|
? (await loadDirectoryEntriesWithModified(resolvedPath, visibleDirents, controller.signal))
|
|
2741
2783
|
.sort(compareDirectoryEntriesByModified)
|
|
@@ -25,7 +25,7 @@ import { getPtyHostManager } from '../ptyhost/manager.js';
|
|
|
25
25
|
import { pathValidator } from '../utils/pathValidator.js';
|
|
26
26
|
import { TERMINAL, TMUX } from '../config.js';
|
|
27
27
|
import { localAccessManager } from '../utils/localAccess.js';
|
|
28
|
-
import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, getAutoRenamePromptPayloadCharsSetting, setAutoRenamePromptPayloadCharsSetting, getNewSessionAgentSlugSetting, setNewSessionAgentSlugSetting, getRunningSessionButtonEnabledSetting, getAttentionButtonEnabledSetting, getCollaborationPanelsSetting, setCollaborationPanelSetting, getAndroidPanelSetting, setAndroidPanelSetting, normalizeAndroidPanel, getCollaborationFloatingGroupIdSetting, setCollaborationFloatingGroupIdSetting, getServiceSwitcherExpandedSetting, setServiceSwitcherExpandedSetting, setRunningSessionButtonEnabledSetting, setAttentionButtonEnabledSetting, getFileSortModesSetting, setFileSortModesSetting, setFileSortModeSetting, getNestedGitScanRootsSetting, setNestedGitScanRootSetting, getPinnedExplorerRootsSetting, setPinnedExplorerRootsSetting, setPinnedExplorerRootSetting, watchPinnedExplorerRootsSetting, getActiveGitReposSetting, setActiveGitRepoSetting, } from '../utils/settings.js';
|
|
28
|
+
import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, getAutoRenamePromptPayloadCharsSetting, setAutoRenamePromptPayloadCharsSetting, getNewSessionAgentSlugSetting, setNewSessionAgentSlugSetting, getRunningSessionButtonEnabledSetting, getAttentionButtonEnabledSetting, getCollaborationPanelsSetting, setCollaborationPanelSetting, getAndroidPanelSetting, setAndroidPanelSetting, normalizeAndroidPanel, getCollaborationFloatingGroupIdSetting, setCollaborationFloatingGroupIdSetting, getServiceSwitcherExpandedSetting, setServiceSwitcherExpandedSetting, setRunningSessionButtonEnabledSetting, setAttentionButtonEnabledSetting, getFileSortModesSetting, getHideGitIgnoredRootsSetting, setHideGitIgnoredRootSetting, setFileSortModesSetting, setFileSortModeSetting, getNestedGitScanRootsSetting, setNestedGitScanRootSetting, getPinnedExplorerRootsSetting, setPinnedExplorerRootsSetting, setPinnedExplorerRootSetting, watchPinnedExplorerRootsSetting, getActiveGitReposSetting, setActiveGitRepoSetting, } from '../utils/settings.js';
|
|
29
29
|
import { loadContextDraft, saveContextDraft } from '../utils/contextDraft.js';
|
|
30
30
|
import { getOnboardingServerUrl } from '../onboardingServer.js';
|
|
31
31
|
import { inspectLinuxInotifyUsage, isWatchResourceExhaustion } from '../utils/fileWatchPolicy.js';
|
|
@@ -48,6 +48,8 @@ import { COLLAB_NAME_FORBIDDEN, formatCollaborationDelivery } from '../agent/col
|
|
|
48
48
|
import { ambiguousIdMessage } from '../agent/collaborationProtocol.js';
|
|
49
49
|
import { buildCollaborationSpawnCommand, resolveCollaborationSpawnMode } from '../agent/collaborationSpawn.js';
|
|
50
50
|
import { SessionSearchStore } from '../agent/sessionSearchStore.js';
|
|
51
|
+
import { NativeSessionSearch } from '../agent/nativeSessionSearch.js';
|
|
52
|
+
import { CollaborationError } from '../agent/collaborationProtocol.js';
|
|
51
53
|
import { resolveCollaborationBackend, resolveCollaborationSessionId } from '../agent/sessionBindingRecovery.js';
|
|
52
54
|
import { CollaborationRoutingStore, selectCollaborationPane, selectDrivePane } from '../agent/collaborationRouting.js';
|
|
53
55
|
import { CollaborationDeliveryWorker } from '../agent/collaborationDeliveryWorker.js';
|
|
@@ -82,6 +84,7 @@ const collaborationDeliveryWorker = new CollaborationDeliveryWorker({
|
|
|
82
84
|
onError: (error) => console.warn('[collaboration] background delivery failed:', getErrorMessage(error)),
|
|
83
85
|
});
|
|
84
86
|
const sessionSearchStore = new SessionSearchStore(`${TERMDOCK_DIR}/session-search`);
|
|
87
|
+
const nativeSessionSearch = new NativeSessionSearch(`${TERMDOCK_DIR}/session-search/native`);
|
|
85
88
|
let atomicJsonWriteSequence = 0;
|
|
86
89
|
async function readJsonFileIfExists(filePath) {
|
|
87
90
|
try {
|
|
@@ -3415,8 +3418,8 @@ async function findCodexSessionFile(nativeSessionId) {
|
|
|
3415
3418
|
return cachedPath;
|
|
3416
3419
|
if (!/^[a-zA-Z0-9._-]{8,160}$/.test(nativeSessionId))
|
|
3417
3420
|
return null;
|
|
3418
|
-
const
|
|
3419
|
-
const pending = [
|
|
3421
|
+
const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
3422
|
+
const pending = [path.join(codexHome, 'sessions'), path.join(codexHome, 'archived_sessions')];
|
|
3420
3423
|
let visited = 0;
|
|
3421
3424
|
while (pending.length > 0 && visited < 20_000) {
|
|
3422
3425
|
const directory = pending.pop();
|
|
@@ -3448,7 +3451,9 @@ async function findExternalCodexWriter(target) {
|
|
|
3448
3451
|
return null;
|
|
3449
3452
|
try {
|
|
3450
3453
|
const { stdout } = await execFileAsync('lsof', ['-t', '--', sessionFile], { timeout: 2500, maxBuffer: 64 * 1024 });
|
|
3451
|
-
|
|
3454
|
+
// Our search worker reads these files in this process; that read-only
|
|
3455
|
+
// descriptor must not be mistaken for an external Codex conversation owner.
|
|
3456
|
+
const pid = stdout.split(/\s+/).map(Number).find((value) => Number.isInteger(value) && value > 1 && value !== process.pid);
|
|
3452
3457
|
return pid ?? null;
|
|
3453
3458
|
}
|
|
3454
3459
|
catch {
|
|
@@ -5588,6 +5593,31 @@ router.get('/operations/collaboration-directory', (req, res) => {
|
|
|
5588
5593
|
void service.refresh();
|
|
5589
5594
|
res.json(service.directory());
|
|
5590
5595
|
});
|
|
5596
|
+
router.delete('/operations/collaboration-connections/:serviceId', (req, res) => {
|
|
5597
|
+
try {
|
|
5598
|
+
assertPeerRegistrationAuthority(req);
|
|
5599
|
+
const service = req.app.locals.collaborationService;
|
|
5600
|
+
if (!service)
|
|
5601
|
+
return res.status(503).json({ error: '协作服务正在启动' });
|
|
5602
|
+
res.json(service.removePeer(req.params.serviceId));
|
|
5603
|
+
}
|
|
5604
|
+
catch (error) {
|
|
5605
|
+
res.status(error instanceof CollaborationError ? error.httpStatus : getErrorMessage(error) === 'AUTHORIZATION_DENIED' ? 403 : 400)
|
|
5606
|
+
.json({ error: getErrorMessage(error), ...(error instanceof CollaborationError ? { code: error.code, ...error.details } : {}) });
|
|
5607
|
+
}
|
|
5608
|
+
});
|
|
5609
|
+
router.post('/operations/collaboration-connections/:serviceId/restore', (req, res) => {
|
|
5610
|
+
try {
|
|
5611
|
+
assertPeerRegistrationAuthority(req);
|
|
5612
|
+
const service = req.app.locals.collaborationService;
|
|
5613
|
+
if (!service)
|
|
5614
|
+
return res.status(503).json({ error: '协作服务正在启动' });
|
|
5615
|
+
res.json(service.restorePeer(req.params.serviceId));
|
|
5616
|
+
}
|
|
5617
|
+
catch (error) {
|
|
5618
|
+
res.status(error instanceof CollaborationError ? error.httpStatus : getErrorMessage(error) === 'AUTHORIZATION_DENIED' ? 403 : 400).json({ error: getErrorMessage(error) });
|
|
5619
|
+
}
|
|
5620
|
+
});
|
|
5591
5621
|
export function collaborationDirectorySessions() { return globalSessionState.sessions.map(orchestrationSessionSnapshot); }
|
|
5592
5622
|
export function collaborationLocalActivity() {
|
|
5593
5623
|
return globalSessionState.sessions.map(record => {
|
|
@@ -5987,16 +6017,81 @@ router.use('/operations/orchestration', collaborationRoutes({ store: collaborati
|
|
|
5987
6017
|
broadcastClientState();
|
|
5988
6018
|
return { ok: true };
|
|
5989
6019
|
} }));
|
|
5990
|
-
router.get('/operations/session-search', (req, res) => {
|
|
5991
|
-
const query = typeof req.query.q === 'string' ? req.query.q : '';
|
|
5992
|
-
const
|
|
6020
|
+
router.get('/operations/session-search', async (req, res) => {
|
|
6021
|
+
const query = typeof req.query.q === 'string' ? req.query.q.trim().slice(0, 512) : '';
|
|
6022
|
+
const limit = Math.max(1, Math.min(5000, Math.floor(Number(req.query.limit)) || 50));
|
|
6023
|
+
const controller = new AbortController();
|
|
6024
|
+
const disconnected = () => { if (!res.writableEnded)
|
|
6025
|
+
controller.abort(); };
|
|
6026
|
+
res.once('close', disconnected);
|
|
6027
|
+
const terminalResults = sessionSearchStore.search(query, 100).map((result) => {
|
|
5993
6028
|
const live = globalSessionState.sessions.some((candidate) => candidate.sessionId === result.sessionId);
|
|
5994
6029
|
const resumeEntry = result.agentNativeSessionId
|
|
5995
|
-
? agentResumeHistory.list().find((entry) => entry.agent.sessionId === result.agentNativeSessionId)
|
|
6030
|
+
? agentResumeHistory.list().find((entry) => entry.agent.slug === result.agentSlug && entry.agent.sessionId === result.agentNativeSessionId)
|
|
5996
6031
|
: null;
|
|
5997
|
-
return { ...result, live, resumeHistoryId: resumeEntry?.id ?? null };
|
|
6032
|
+
return { ...result, source: 'terminal', nativeKey: null, live, resumeHistoryId: resumeEntry?.id ?? null };
|
|
5998
6033
|
});
|
|
5999
|
-
|
|
6034
|
+
try {
|
|
6035
|
+
// Preserve the names users see in Termdock as searchable aliases, including
|
|
6036
|
+
// custom titles for conversations that have already been closed.
|
|
6037
|
+
const titles = [
|
|
6038
|
+
...sessionSearchStore.search('', 100).flatMap(entry => entry.agentSlug && entry.agentNativeSessionId ? [{ agentSlug: entry.agentSlug, agentNativeSessionId: entry.agentNativeSessionId, title: entry.title }] : []),
|
|
6039
|
+
...agentResumeHistory.list().reverse().map(entry => ({ agentSlug: entry.agent.slug, agentNativeSessionId: entry.agent.sessionId, title: entry.title })),
|
|
6040
|
+
...globalSessionState.sessions.flatMap(entry => entry.customName && entry.agentResume?.sessionId ? [{ agentSlug: entry.agentResume.slug, agentNativeSessionId: entry.agentResume.sessionId, title: entry.name }] : []),
|
|
6041
|
+
];
|
|
6042
|
+
const native = await nativeSessionSearch.search(query, limit + terminalResults.length, titles, controller.signal);
|
|
6043
|
+
if (controller.signal.aborted)
|
|
6044
|
+
return;
|
|
6045
|
+
const matched = new Set(native.matchedSessions);
|
|
6046
|
+
const additional = terminalResults.filter(result => !result.agentNativeSessionId || !matched.has(`${result.agentSlug}:${result.agentNativeSessionId}`));
|
|
6047
|
+
const results = native.results.map(result => {
|
|
6048
|
+
const owner = findActiveAgentResumeOwner('', { slug: result.agentSlug, nativeSessionId: result.agentNativeSessionId, command: '' });
|
|
6049
|
+
const liveRecord = owner ? globalSessionState.sessions.find(candidate => candidate.backendSessionId === owner) : null;
|
|
6050
|
+
return { ...result, source: result.agentSlug, nativeKey: result.key, sessionId: liveRecord?.sessionId || `native:${result.key}`,
|
|
6051
|
+
live: Boolean(liveRecord), resumeHistoryId: null };
|
|
6052
|
+
});
|
|
6053
|
+
res.json({ query, results: [...results, ...additional].sort((a, b) => b.updatedAt - a.updatedAt).slice(0, limit), total: native.total + additional.length, index: native.index });
|
|
6054
|
+
}
|
|
6055
|
+
catch (error) {
|
|
6056
|
+
if (controller.signal.aborted)
|
|
6057
|
+
return;
|
|
6058
|
+
res.json({ query, results: terminalResults.slice(0, limit), total: terminalResults.length,
|
|
6059
|
+
index: { total: 0, indexed: 0, building: false, failed: 0, warning: `历史会话暂时无法搜索:${getErrorMessage(error)}` } });
|
|
6060
|
+
}
|
|
6061
|
+
finally {
|
|
6062
|
+
res.off('close', disconnected);
|
|
6063
|
+
}
|
|
6064
|
+
});
|
|
6065
|
+
router.post('/operations/session-search/prepare', async (req, res) => {
|
|
6066
|
+
const key = typeof req.body?.nativeKey === 'string' ? req.body.nativeKey : '';
|
|
6067
|
+
if (!/^[a-f0-9]{64}$/.test(key))
|
|
6068
|
+
return res.status(400).json({ error: '无效的历史会话' });
|
|
6069
|
+
try {
|
|
6070
|
+
// Resolve the original file and command on the server; never accept a
|
|
6071
|
+
// transcript path, working directory or shell command from search clients.
|
|
6072
|
+
const entry = await nativeSessionSearch.get(key);
|
|
6073
|
+
if (!entry)
|
|
6074
|
+
return res.status(404).json({ error: '这条历史会话已不存在,请重新搜索' });
|
|
6075
|
+
const agent = agentBySlug(entry.agentSlug);
|
|
6076
|
+
const history = agentResumeHistory.list().find(candidate => candidate.agent.slug === entry.agentSlug && candidate.agent.sessionId === entry.agentNativeSessionId);
|
|
6077
|
+
const command = agent ? buildResumeCommand(agent, entry.agentNativeSessionId, history?.agent.launchArgv) : null;
|
|
6078
|
+
if (!command)
|
|
6079
|
+
return res.status(410).json({ error: '当前 Agent 不支持恢复这条历史会话' });
|
|
6080
|
+
const target = { slug: entry.agentSlug, nativeSessionId: entry.agentNativeSessionId, command };
|
|
6081
|
+
const owner = findActiveAgentResumeOwner('', target);
|
|
6082
|
+
const liveRecord = owner ? globalSessionState.sessions.find(candidate => candidate.backendSessionId === owner) : null;
|
|
6083
|
+
if (liveRecord)
|
|
6084
|
+
return res.json({ sessionId: liveRecord.sessionId });
|
|
6085
|
+
if (owner || await findExternalCodexWriter(target))
|
|
6086
|
+
return res.status(409).json({ error: '这条会话已在其他终端运行,请先切换到原终端或关闭后恢复', code: 'AGENT_SESSION_ACTIVE_ELSEWHERE' });
|
|
6087
|
+
if (!entry.cwd)
|
|
6088
|
+
return res.status(409).json({ error: '尚未找到这条会话的项目目录,请等待索引完成后重试' });
|
|
6089
|
+
const cwd = await resolveWorkingDirectory(req, entry.cwd);
|
|
6090
|
+
res.json({ command, cwd, title: entry.title, agent });
|
|
6091
|
+
}
|
|
6092
|
+
catch (error) {
|
|
6093
|
+
res.status(400).json({ error: `无法恢复会话:${getErrorMessage(error)}` });
|
|
6094
|
+
}
|
|
6000
6095
|
});
|
|
6001
6096
|
router.get('/agent-resume-history', (_req, res) => {
|
|
6002
6097
|
const entries = agentResumeHistory.list().flatMap((entry) => {
|
|
@@ -6238,6 +6333,7 @@ async function getSettingsPayload() {
|
|
|
6238
6333
|
collaborationFloatingGroupId: getCollaborationFloatingGroupIdSetting(),
|
|
6239
6334
|
serviceSwitcherExpanded: getServiceSwitcherExpandedSetting(),
|
|
6240
6335
|
fileSortModes: getFileSortModesSetting(),
|
|
6336
|
+
hideGitIgnoredRoots: getHideGitIgnoredRootsSetting(),
|
|
6241
6337
|
nestedGitScanRoots: getNestedGitScanRootsSetting(),
|
|
6242
6338
|
activeGitRepos: getActiveGitReposSetting(),
|
|
6243
6339
|
pinnedExplorerRoots: getPinnedExplorerRootsSetting(),
|
|
@@ -6427,6 +6523,18 @@ router.put('/settings', async (req, res) => {
|
|
|
6427
6523
|
}
|
|
6428
6524
|
setFileSortModeSetting(preference.path, preference.mode);
|
|
6429
6525
|
}
|
|
6526
|
+
if (body.hideGitIgnoredRoot && typeof body.hideGitIgnoredRoot === 'object') {
|
|
6527
|
+
const preference = body.hideGitIgnoredRoot;
|
|
6528
|
+
const validPath = typeof preference.rootPath === 'string'
|
|
6529
|
+
&& preference.rootPath.length > 0
|
|
6530
|
+
&& preference.rootPath.length <= 4096
|
|
6531
|
+
&& (preference.rootPath.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(preference.rootPath));
|
|
6532
|
+
if (!validPath || typeof preference.enabled !== 'boolean') {
|
|
6533
|
+
res.status(400).json({ error: 'Invalid Git ignore visibility preference', code: 'GIT_IGNORE_VISIBILITY_INVALID' });
|
|
6534
|
+
return;
|
|
6535
|
+
}
|
|
6536
|
+
setHideGitIgnoredRootSetting(preference.rootPath, preference.enabled);
|
|
6537
|
+
}
|
|
6430
6538
|
if (body.nestedGitScanRoot && typeof body.nestedGitScanRoot === 'object') {
|
|
6431
6539
|
const preference = body.nestedGitScanRoot;
|
|
6432
6540
|
const isAbsoluteRootPath = (value) => typeof value === 'string'
|
|
@@ -235,6 +235,7 @@ function normalizeSettings(value) {
|
|
|
235
235
|
collaborationFloatingGroupId: typeof raw.collaborationFloatingGroupId === 'string' && raw.collaborationFloatingGroupId.trim() ? raw.collaborationFloatingGroupId.trim() : null,
|
|
236
236
|
serviceSwitcherExpanded: raw.serviceSwitcherExpanded === true,
|
|
237
237
|
fileSortModes: normalizeFileSortModes(raw.fileSortModes),
|
|
238
|
+
hideGitIgnoredRoots: normalizeNestedGitScanRoots(raw.hideGitIgnoredRoots),
|
|
238
239
|
nestedGitScanRoots: normalizeNestedGitScanRoots(raw.nestedGitScanRoots),
|
|
239
240
|
pinnedExplorerRoots: normalizePinnedExplorerRoots(raw.pinnedExplorerRoots),
|
|
240
241
|
activeGitRepos: normalizeActiveGitRepos(raw.activeGitRepos),
|
|
@@ -580,6 +581,19 @@ export function setFileSortModeSetting(filePath, mode) {
|
|
|
580
581
|
settings.fileSortModes = normalizeFileSortModes(next);
|
|
581
582
|
});
|
|
582
583
|
}
|
|
584
|
+
export function getHideGitIgnoredRootsSetting() {
|
|
585
|
+
return { ...loadSettings().hideGitIgnoredRoots };
|
|
586
|
+
}
|
|
587
|
+
export function setHideGitIgnoredRootSetting(rootPath, enabled) {
|
|
588
|
+
return updateSettings((settings) => {
|
|
589
|
+
const next = { ...settings.hideGitIgnoredRoots };
|
|
590
|
+
if (enabled)
|
|
591
|
+
next[rootPath] = true;
|
|
592
|
+
else
|
|
593
|
+
delete next[rootPath];
|
|
594
|
+
settings.hideGitIgnoredRoots = normalizeNestedGitScanRoots(next);
|
|
595
|
+
});
|
|
596
|
+
}
|
|
583
597
|
export function getNestedGitScanRootsSetting() {
|
|
584
598
|
return { ...loadSettings().nestedGitScanRoots };
|
|
585
599
|
}
|