termdock 1.4.299 → 1.4.301
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/README.en.md +1 -1
- package/README.md +2 -1
- package/dist/client/assets/App-BziVLy1b.js +179 -0
- package/dist/client/assets/App-BziVLy1b.js.br +0 -0
- package/dist/client/assets/App-BziVLy1b.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js +12 -0
- package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-2lXfrgk4.js → ChangeWalkthroughPanel-00oa0z6w.js} +2 -2
- package/dist/client/assets/ChangeWalkthroughPanel-00oa0z6w.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-00oa0z6w.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js +1 -0
- package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-B_mzpNuw.js +2 -0
- package/dist/client/assets/ComputerControlView-C9v1Ooc9.js +5 -0
- package/dist/client/assets/ComputerControlView-C9v1Ooc9.js.br +0 -0
- package/dist/client/assets/ComputerControlView-C9v1Ooc9.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-EFUb9S3u.js → DagPlayground-DfUpMALj.js} +1 -1
- package/dist/client/assets/DagPlayground-DfUpMALj.js.br +0 -0
- package/dist/client/assets/DagPlayground-DfUpMALj.js.gz +0 -0
- package/dist/client/assets/{DiffLab-CXWjSE2q.js → DiffLab-Cf_URhQt.js} +1 -1
- package/dist/client/assets/DiffLab-Cf_URhQt.js.br +0 -0
- package/dist/client/assets/DiffLab-Cf_URhQt.js.gz +0 -0
- package/dist/client/assets/{DiffReview-ByMkBaD9.js → DiffReview-DjG9vCpH.js} +1 -1
- package/dist/client/assets/DiffReview-DjG9vCpH.js.br +0 -0
- package/dist/client/assets/DiffReview-DjG9vCpH.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-DoWaKm94.js → DiffReviewLab-BKOvHdJY.js} +2 -2
- package/dist/client/assets/DiffReviewLab-BKOvHdJY.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-BKOvHdJY.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-B4hn9z0k.js → DiffViewer-6n3tgsdc.js} +8 -8
- package/dist/client/assets/DiffViewer-6n3tgsdc.js.br +0 -0
- package/dist/client/assets/DiffViewer-6n3tgsdc.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-C-LJZ8so.js → ModelPreview-BNs2sRct.js} +1 -1
- package/dist/client/assets/ModelPreview-BNs2sRct.js.br +0 -0
- package/dist/client/assets/ModelPreview-BNs2sRct.js.gz +0 -0
- package/dist/client/assets/RightSidebar-CcMSU1v8.js +1677 -0
- package/dist/client/assets/RightSidebar-CcMSU1v8.js.br +0 -0
- package/dist/client/assets/RightSidebar-CcMSU1v8.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-BY-pfYKk.js → abnfDiagram-VCTEODGH-DogjvRKp.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DogjvRKp.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DogjvRKp.js.gz +0 -0
- package/dist/client/assets/app-D6vN8PW-.js +35 -0
- package/dist/client/assets/app-D6vN8PW-.js.br +0 -0
- package/dist/client/assets/app-D6vN8PW-.js.gz +0 -0
- package/dist/client/assets/{arc-DIENgCZn.js → arc-Cqel4Ted.js} +1 -1
- package/dist/client/assets/arc-Cqel4Ted.js.br +0 -0
- package/dist/client/assets/arc-Cqel4Ted.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-C1h4e4az.js → architectureDiagram-5GKGNRK7-DgvPtgNb.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DgvPtgNb.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DgvPtgNb.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-B_yOr54K.js → blockDiagram-I7D4REHJ-BxbWO4x4.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-BxbWO4x4.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-BxbWO4x4.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-DRD4zxIo.js → c4Diagram-7LVT6UL2-gsA37gjL.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-gsA37gjL.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-gsA37gjL.js.gz +0 -0
- package/dist/client/assets/channel-CBc8-n7y.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CXytnjmD.js → chunk-2Q5K7J3B-ChC9yYOd.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-Bjmajkf7.js → chunk-5VM5RSS4-Bi4Hc8yL.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-CQCL8mJG.js → chunk-F27PBJKO-DvVWvQEk.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-DvVWvQEk.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-DvVWvQEk.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-ruHGCADe.js → chunk-IMKFNOWR-BnwQLR5S.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-BnwQLR5S.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BnwQLR5S.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-U18S7rxZ.js → chunk-JWPE2WC7-BkNnaDiR.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-DWnwssfL.js → chunk-POPQ4Y6H-BRzm6Uzi.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-DMHj3NSq.js → chunk-SVP7TREG-CDYm-dzk.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-CDYm-dzk.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CDYm-dzk.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-Dh_ekvFW.js → chunk-TICWLB2K-BKaW9Z9i.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-BKaW9Z9i.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-BKaW9Z9i.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-Bq5wD6iJ.js → chunk-XXDRQBXY-DcHZ_FHb.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-CNFc2dOc.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CNFc2dOc.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CsySWhYg.js → cose-bilkent-JH36ORCC-DCbbTNc6.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-DCbbTNc6.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-DCbbTNc6.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-9DKE5wV7.js → cynefin-OW5HDTMX-i23hD0Z2.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-i23hD0Z2.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-i23hD0Z2.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-B_8fvr9c.js → cynefinDiagram-5FMLGOSQ-CbyLYcqc.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbyLYcqc.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbyLYcqc.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-BOdsFNFT.js → dagre-GXQ25YYZ-iJ4VKzZm.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-iJ4VKzZm.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-iJ4VKzZm.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-6v_qvAvi.js → diagram-S7CK7UJ4-BNVZcdsO.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-BNVZcdsO.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-BNVZcdsO.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-c03oOGhD.js → diagram-UQ7AKVKN-1ghTvPiu.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-1ghTvPiu.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-1ghTvPiu.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-MMIhRYp_.js → diagram-VSXAHHWV-Ce_0nMd3.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-Ce_0nMd3.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-Ce_0nMd3.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-B_l-uebl.js → diagram-VX7I27RA-CLHEkhUt.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-CLHEkhUt.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CLHEkhUt.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-DKoBC5gn.js → diagram-Z3DM3KII-iyb5DkP6.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-iyb5DkP6.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-iyb5DkP6.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Bs3wu8Az.js → ebnfDiagram-PWID7BFC-Dxh2TzXm.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Dxh2TzXm.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Dxh2TzXm.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-mYnHYbKl.js → erDiagram-RLTQ6QDP-Cr8IkdCC.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-Cr8IkdCC.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Cr8IkdCC.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-CwCLWbib.js → flowDiagram-HODETNUW-B8ZF1bwr.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-B8ZF1bwr.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-B8ZF1bwr.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-mse8c-ni.js → ganttDiagram-EL5Y4UJY-zhdL10eM.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-zhdL10eM.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-zhdL10eM.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-BviL29ps.js → gestureArbiter-CXYHfU__.js} +1 -1
- package/dist/client/assets/gestureArbiter-CXYHfU__.js.br +0 -0
- package/dist/client/assets/gestureArbiter-CXYHfU__.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BVUfLjAX.js → gitGraphDiagram-WWUBYQGX-BQf2fHBo.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BQf2fHBo.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BQf2fHBo.js.gz +0 -0
- package/dist/client/assets/{index-C6ftfFlG.css → index-CNY7CTVa.css} +1 -1
- package/dist/client/assets/index-CNY7CTVa.css.br +0 -0
- package/dist/client/assets/index-CNY7CTVa.css.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-XjoFF4BC.js → infoDiagram-27XIBGKW-BT8xey7S.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-bH299bWL.js → ishikawaDiagram-5VMMS53U-DunPdwW9.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DunPdwW9.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DunPdwW9.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-BG0u_X1A.js → journeyDiagram-3NMN7TZE-B0y75iIg.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B0y75iIg.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B0y75iIg.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-DRoc9N-i.js → kanban-definition-UXKFOSKX-BfgA5WLo.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-BfgA5WLo.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BfgA5WLo.js.gz +0 -0
- package/dist/client/assets/{layout-mh0t6JpE.js → layout-BvjABLff.js} +1 -1
- package/dist/client/assets/layout-BvjABLff.js.br +0 -0
- package/dist/client/assets/layout-BvjABLff.js.gz +0 -0
- package/dist/client/assets/{linear-B9KTRuUV.js → linear-DgeFRliF.js} +1 -1
- package/dist/client/assets/linear-DgeFRliF.js.br +0 -0
- package/dist/client/assets/linear-DgeFRliF.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-Bu2G9zhK.js → mermaid.core-DM6Rlal9.js} +5 -5
- package/dist/client/assets/mermaid.core-DM6Rlal9.js.br +0 -0
- package/dist/client/assets/mermaid.core-DM6Rlal9.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-Go6Bg5xm.js → mindmap-definition-YA3MSWOX-DhEiABv6.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DhEiABv6.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DhEiABv6.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-C7-MUAHQ.js → passwordBootstrap-Dxv0I4wM.js} +1 -1
- package/dist/client/assets/passwordBootstrap-Dxv0I4wM.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Dxv0I4wM.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-DKUIl_U6.js → pegDiagram-XKGWAZYB-LTlVaJfm.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-LTlVaJfm.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-LTlVaJfm.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-aoDNlV7J.js → pieDiagram-E7YTZNPT-9bnryna3.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-9bnryna3.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-9bnryna3.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BKuuaF2s.js → quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BKuuaF2s.js.br → quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.br} +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-BwfCW2bp.js → railroadDiagram-O6MQD6OU-DTtXvKOu.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DTtXvKOu.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DTtXvKOu.js.gz +0 -0
- package/dist/client/assets/rdpSession-Ggo3N5s5.js +1 -0
- package/dist/client/assets/rdpSession-Ggo3N5s5.js.br +0 -0
- package/dist/client/assets/rdpSession-Ggo3N5s5.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-Df8W2cyP.js +1 -0
- package/dist/client/assets/referenceLongPress-Df8W2cyP.js.br +0 -0
- package/dist/client/assets/referenceLongPress-Df8W2cyP.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-DbpU9Uig.js → requirementDiagram-BXWQKSXE-BNia9zI0.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BNia9zI0.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BNia9zI0.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-Bxa22XVM.js → sankeyDiagram-P5KCCOFB-uvg5npfK.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-uvg5npfK.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-uvg5npfK.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-C4GvzT9z.js → sequenceDiagram-WJ2MYXX4-DpJNf2MD.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DpJNf2MD.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DpJNf2MD.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-B9zJJwQw.js → sizeCapture-INFHLROL-CkWB2AnF.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-CkWB2AnF.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CkWB2AnF.js.gz +0 -0
- package/dist/client/assets/{sparkles-BJbfT-v-.js → sparkles-DOuEtn62.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-fqbw6LZa.js → stateDiagram-D77RDMKH-CeMzMQq-.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-CeMzMQq-.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CeMzMQq-.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CNYUpLxt.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-Hpc28YZY.js → swimlanes-42K2YHIH-Bo9GejWo.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-Bo9GejWo.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-Bo9GejWo.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-EB7zBRFR.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-qDieK7Re.js → timeline-definition-24CTP7MA-cvWXYEZ4.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-cvWXYEZ4.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-cvWXYEZ4.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-YOCAWhtT.js → triangle-alert-DzV0gQXz.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BJpZlHao.js → vennDiagram-4TSXK5OY-CzleWcmk.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BJpZlHao.js.br → vennDiagram-4TSXK5OY-CzleWcmk.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CzleWcmk.js.gz +0 -0
- package/dist/client/assets/{videoCompression-DI9vP0dm.js → videoCompression-DCnzjEfU.js} +1 -1
- package/dist/client/assets/videoCompression-DCnzjEfU.js.br +0 -0
- package/dist/client/assets/videoCompression-DCnzjEfU.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-CQJfj6Ns.js → wardleyDiagram-VM6X3IG4-Cir1iutR.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cir1iutR.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cir1iutR.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-Cy-lkWBX.js → xychartDiagram-S5SC5T6Z-pNPcVJ1C.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.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 +56 -10
- package/dist/server/agent/collaborationGroupRoutes.js +10 -5
- package/dist/server/agent/collaborationLaunchProfiles.js +43 -0
- package/dist/server/agent/collaborationRoutes.js +6 -2
- package/dist/server/agent/collaborationService.js +8 -2
- package/dist/server/agent/collaborationStore.js +32 -1
- package/dist/server/agent/collaborationTaskCli.js +11 -3
- package/dist/server/agent/collaborationTaskService.js +16 -10
- package/dist/server/agent/collaborationTaskStore.js +70 -25
- package/dist/server/agent/collaborationTeam.js +3 -3
- package/dist/server/agent/integrationCli.js +243 -0
- package/dist/server/agent/integrationServer.js +331 -0
- package/dist/server/agent/integrationSessions.js +344 -0
- package/dist/server/agent/integrationStore.js +222 -0
- package/dist/server/cli.js +29 -0
- package/dist/server/entry.js +26 -7
- package/dist/server/routes/filesystem.js +120 -87
- package/dist/server/routes/terminal.js +196 -13
- package/dist/server/utils/localAccess.js +27 -7
- package/dist/server/utils/sessionDisplayName.js +53 -0
- package/docs/integrations.md +304 -0
- package/package.json +3 -2
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-DzuUkEI_.js +0 -179
- package/dist/client/assets/App-DzuUkEI_.js.br +0 -0
- package/dist/client/assets/App-DzuUkEI_.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-QodxiiCc.js +0 -7
- package/dist/client/assets/ArchitecturePanel-QodxiiCc.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-QodxiiCc.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-2lXfrgk4.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-2lXfrgk4.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js +0 -1
- package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-BJe9TUtZ.js +0 -2
- package/dist/client/assets/ComputerControlView-B5vigCoW.js +0 -5
- package/dist/client/assets/ComputerControlView-B5vigCoW.js.br +0 -0
- package/dist/client/assets/ComputerControlView-B5vigCoW.js.gz +0 -0
- package/dist/client/assets/DagPlayground-EFUb9S3u.js.br +0 -0
- package/dist/client/assets/DagPlayground-EFUb9S3u.js.gz +0 -0
- package/dist/client/assets/DiffLab-CXWjSE2q.js.br +0 -0
- package/dist/client/assets/DiffLab-CXWjSE2q.js.gz +0 -0
- package/dist/client/assets/DiffReview-ByMkBaD9.js.br +0 -0
- package/dist/client/assets/DiffReview-ByMkBaD9.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-DoWaKm94.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-DoWaKm94.js.gz +0 -0
- package/dist/client/assets/DiffViewer-B4hn9z0k.js.br +0 -0
- package/dist/client/assets/DiffViewer-B4hn9z0k.js.gz +0 -0
- package/dist/client/assets/ModelPreview-C-LJZ8so.js.br +0 -0
- package/dist/client/assets/ModelPreview-C-LJZ8so.js.gz +0 -0
- package/dist/client/assets/RightSidebar-EaMm4prW.js +0 -1678
- package/dist/client/assets/RightSidebar-EaMm4prW.js.br +0 -0
- package/dist/client/assets/RightSidebar-EaMm4prW.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BY-pfYKk.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BY-pfYKk.js.gz +0 -0
- package/dist/client/assets/app-Ch0UDtJ-.js +0 -35
- package/dist/client/assets/app-Ch0UDtJ-.js.br +0 -0
- package/dist/client/assets/app-Ch0UDtJ-.js.gz +0 -0
- package/dist/client/assets/arc-DIENgCZn.js.br +0 -0
- package/dist/client/assets/arc-DIENgCZn.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C1h4e4az.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C1h4e4az.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-B_yOr54K.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-B_yOr54K.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-DRD4zxIo.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-DRD4zxIo.js.gz +0 -0
- package/dist/client/assets/channel-MOXuUKM7.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-CQCL8mJG.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CQCL8mJG.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-ruHGCADe.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-ruHGCADe.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DMHj3NSq.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DMHj3NSq.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Dh_ekvFW.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Dh_ekvFW.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-CEXMdudw.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CEXMdudw.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CsySWhYg.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CsySWhYg.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-9DKE5wV7.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-9DKE5wV7.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B_8fvr9c.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B_8fvr9c.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BOdsFNFT.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BOdsFNFT.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-6v_qvAvi.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-6v_qvAvi.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-c03oOGhD.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-c03oOGhD.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-MMIhRYp_.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-MMIhRYp_.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-B_l-uebl.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-B_l-uebl.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DKoBC5gn.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DKoBC5gn.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bs3wu8Az.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bs3wu8Az.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-mYnHYbKl.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-mYnHYbKl.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CwCLWbib.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CwCLWbib.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-mse8c-ni.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-mse8c-ni.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-BviL29ps.js.br +0 -0
- package/dist/client/assets/gestureArbiter-BviL29ps.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVUfLjAX.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVUfLjAX.js.gz +0 -0
- package/dist/client/assets/index-C6ftfFlG.css.br +0 -0
- package/dist/client/assets/index-C6ftfFlG.css.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-bH299bWL.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-bH299bWL.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BG0u_X1A.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BG0u_X1A.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-DRoc9N-i.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-DRoc9N-i.js.gz +0 -0
- package/dist/client/assets/layout-mh0t6JpE.js.br +0 -0
- package/dist/client/assets/layout-mh0t6JpE.js.gz +0 -0
- package/dist/client/assets/linear-B9KTRuUV.js.br +0 -0
- package/dist/client/assets/linear-B9KTRuUV.js.gz +0 -0
- package/dist/client/assets/mermaid.core-Bu2G9zhK.js.br +0 -0
- package/dist/client/assets/mermaid.core-Bu2G9zhK.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Go6Bg5xm.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Go6Bg5xm.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-C7-MUAHQ.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-C7-MUAHQ.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DKUIl_U6.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DKUIl_U6.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-aoDNlV7J.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-aoDNlV7J.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BKuuaF2s.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BwfCW2bp.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BwfCW2bp.js.gz +0 -0
- package/dist/client/assets/rdpSession--y6Q98uo.js +0 -1
- package/dist/client/assets/rdpSession--y6Q98uo.js.br +0 -0
- package/dist/client/assets/rdpSession--y6Q98uo.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-BeG1PAdI.js +0 -1
- package/dist/client/assets/referenceLongPress-BeG1PAdI.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BeG1PAdI.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DbpU9Uig.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DbpU9Uig.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bxa22XVM.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bxa22XVM.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C4GvzT9z.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C4GvzT9z.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-B9zJJwQw.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-B9zJJwQw.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-fqbw6LZa.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-fqbw6LZa.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BO23Pbrn.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-Hpc28YZY.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-Hpc28YZY.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BLS7y4Di.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-qDieK7Re.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-qDieK7Re.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BJpZlHao.js.gz +0 -0
- package/dist/client/assets/videoCompression-DI9vP0dm.js.br +0 -0
- package/dist/client/assets/videoCompression-DI9vP0dm.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-CQJfj6Ns.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-CQJfj6Ns.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Cy-lkWBX.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Cy-lkWBX.js.gz +0 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { collaborationSessionDisplayName } from '../utils/sessionDisplayName.js';
|
|
2
|
+
import { integrationError } from '../agent/integrationStore.js';
|
|
3
|
+
import { integrationLaunchCommand } from '../agent/integrationSessions.js';
|
|
1
4
|
import { ensureTeam } from '../agent/collaborationTeam.js';
|
|
2
5
|
import { androidRecordings } from '../android/recording.js';
|
|
3
6
|
import { assertPeerRegistrationAuthority } from '../agent/collaborationPeerTransport.js';
|
|
@@ -26,7 +29,7 @@ import { gitStatusCache } from '../utils/gitStatus.js';
|
|
|
26
29
|
import { getPtyHostManager } from '../ptyhost/manager.js';
|
|
27
30
|
import { pathValidator } from '../utils/pathValidator.js';
|
|
28
31
|
import { TERMINAL, TMUX } from '../config.js';
|
|
29
|
-
import { localAccessManager } from '../utils/localAccess.js';
|
|
32
|
+
import { localAccessManager, localAccessInterfaceUrl } from '../utils/localAccess.js';
|
|
30
33
|
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, getGitIgnoreExceptionsSetting, setGitIgnoreExceptionsSetting, setHideGitIgnoredRootSetting, setFileSortModesSetting, setFileSortModeSetting, getNestedGitScanRootsSetting, setNestedGitScanRootSetting, getPinnedExplorerRootsSetting, setPinnedExplorerRootsSetting, setPinnedExplorerRootSetting, watchPinnedExplorerRootsSetting, getActiveGitReposSetting, setActiveGitRepoSetting, } from '../utils/settings.js';
|
|
31
34
|
import { loadContextDraft, saveContextDraft } from '../utils/contextDraft.js';
|
|
32
35
|
import { getOnboardingServerUrl } from '../onboardingServer.js';
|
|
@@ -51,6 +54,7 @@ import { CollaborationStore } from '../agent/collaborationStore.js';
|
|
|
51
54
|
import { COLLAB_NAME_FORBIDDEN, formatCollaborationDelivery } from '../agent/collaborationPrompt.js';
|
|
52
55
|
import { ambiguousIdMessage } from '../agent/collaborationProtocol.js';
|
|
53
56
|
import { buildCollaborationSpawnCommand, resolveCollaborationSpawnMode } from '../agent/collaborationSpawn.js';
|
|
57
|
+
import { resolveCollaborationLaunch, launchProfileKey } from '../agent/collaborationLaunchProfiles.js';
|
|
54
58
|
import { SessionSearchStore } from '../agent/sessionSearchStore.js';
|
|
55
59
|
import { NativeSessionSearch } from '../agent/nativeSessionSearch.js';
|
|
56
60
|
import { CollaborationError } from '../agent/collaborationProtocol.js';
|
|
@@ -435,7 +439,16 @@ async function flushClientStateBroadcast() {
|
|
|
435
439
|
}
|
|
436
440
|
}
|
|
437
441
|
}
|
|
442
|
+
const integrationSessionObservers = new Set();
|
|
443
|
+
let integrationDeliveryGuard;
|
|
444
|
+
function notifyIntegrationSessions() { for (const listener of integrationSessionObservers) {
|
|
445
|
+
try {
|
|
446
|
+
listener();
|
|
447
|
+
}
|
|
448
|
+
catch { /* Observation failure does not affect terminal clients. */ }
|
|
449
|
+
} }
|
|
438
450
|
function broadcastClientState() {
|
|
451
|
+
notifyIntegrationSessions();
|
|
439
452
|
if (broadcastClientStateTimer) {
|
|
440
453
|
return;
|
|
441
454
|
}
|
|
@@ -1401,7 +1414,12 @@ function orchestrationSessionSnapshot(record) {
|
|
|
1401
1414
|
sessionId: record.sessionId,
|
|
1402
1415
|
agentNativeSessionId: binding?.pane ? binding.pane.nativeSessionId : binding?.nativeSessionId ?? backend?.agentSession?.sessionId ?? record.agentResume?.sessionId ?? null,
|
|
1403
1416
|
backendSessionId: backendId ?? null,
|
|
1404
|
-
name: record
|
|
1417
|
+
name: collaborationSessionDisplayName({ ...record,
|
|
1418
|
+
activeProgram: backend?.activeProgram?.command ?? record.activeProgram,
|
|
1419
|
+
shellTitle: backend?.lastOscTitle ?? record.shellTitle,
|
|
1420
|
+
cwd: backend?.cwd ?? record.cwd,
|
|
1421
|
+
agent: agent ? { displayName: agent.displayName } : null,
|
|
1422
|
+
}),
|
|
1405
1423
|
cwd: backend?.cwd ?? record.cwd ?? '',
|
|
1406
1424
|
agent: agent ? { slug: agent.slug, displayName: agent.displayName } : null,
|
|
1407
1425
|
status: route.state === 'unchecked' && terminalConnected ? 'terminal-connected' : route.state,
|
|
@@ -1642,6 +1660,11 @@ async function resolveCollaborationRoute(frontendSessionId) {
|
|
|
1642
1660
|
let record = globalSessionState.sessions.find((candidate) => candidate.sessionId === frontendSessionId);
|
|
1643
1661
|
if (!record)
|
|
1644
1662
|
return { state: 'offline', reason: 'SESSION_REMOVED' };
|
|
1663
|
+
if (record.tmuxSessionName?.startsWith('wt-integration-') && !integrationDeliveryGuard)
|
|
1664
|
+
return { state: 'unavailable', reason: 'INTEGRATION_RUNTIME_UNAVAILABLE' };
|
|
1665
|
+
const startup = await integrationDeliveryGuard?.(frontendSessionId);
|
|
1666
|
+
if (startup && !startup.allowed)
|
|
1667
|
+
return { state: 'recovering', reason: startup.reason ?? 'SESSION_STARTUP_INPUT_PENDING' };
|
|
1645
1668
|
let backend = resolveOrchestrationBackend(record);
|
|
1646
1669
|
let binding = collaborationRouting.get(frontendSessionId) ?? {
|
|
1647
1670
|
sessionId: record.sessionId, backendSessionId: null, mode: record.mode, tmuxSessionName: record.tmuxSessionName,
|
|
@@ -1729,7 +1752,7 @@ function deliverCollaborationInboxWhenAgentReady(frontendSessionId) {
|
|
|
1729
1752
|
collaborationDeliveryWorker.wake(frontendSessionId);
|
|
1730
1753
|
}
|
|
1731
1754
|
async function spawnCollaborationAgentSession(req, group, sourceSessionId, input, bootstrapRole) {
|
|
1732
|
-
const agentSlug
|
|
1755
|
+
const { agentSlug, profile } = resolveCollaborationLaunch(group, input);
|
|
1733
1756
|
const launchers = await listDetectedAgentLaunchers();
|
|
1734
1757
|
const launcher = launchers.find((candidate) => candidate.slug === agentSlug);
|
|
1735
1758
|
if (!launcher)
|
|
@@ -1751,7 +1774,7 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1751
1774
|
}
|
|
1752
1775
|
const requestedCwd = typeof input.cwd === 'string' ? input.cwd.trim() : '';
|
|
1753
1776
|
const opened = await openInventorySession(req, {
|
|
1754
|
-
name: requestedName || `${launcher.displayName} · ${group.name}`,
|
|
1777
|
+
name: requestedName || `${profile?.name ?? launcher.displayName} · ${group.name}`,
|
|
1755
1778
|
customName: true,
|
|
1756
1779
|
mode,
|
|
1757
1780
|
cwd: requestedCwd || fallbackRecord?.cwd || undefined,
|
|
@@ -1780,7 +1803,9 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1780
1803
|
});
|
|
1781
1804
|
if (bootstrapRole)
|
|
1782
1805
|
collaborationStore.setRole({ groupId: group.id, sessionId: frontendSessionId, role: bootstrapRole });
|
|
1783
|
-
|
|
1806
|
+
if (profile)
|
|
1807
|
+
collaborationStore.setMemberLaunchProfile(group.id, frontendSessionId, profile);
|
|
1808
|
+
writeTerminalInput(backend, `${buildCollaborationSpawnCommand({ slug: launcher.slug, command: profile?.command ?? launcher.command })}\r`);
|
|
1784
1809
|
const requestedTask = typeof input.task === 'string' ? input.task.trim().slice(0, 20_000) : '';
|
|
1785
1810
|
collaborationStore.send({
|
|
1786
1811
|
groupId: updatedGroup.id,
|
|
@@ -1792,7 +1817,154 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1792
1817
|
setTimeout(() => {
|
|
1793
1818
|
deliverCollaborationInboxWhenAgentReady(frontendSessionId);
|
|
1794
1819
|
}, 300).unref?.();
|
|
1795
|
-
return { group:
|
|
1820
|
+
return { group: collaborationStore.getGroup(group.id), session: orchestrationSessionSnapshot(globalSessionState.sessions.find((candidate) => candidate.sessionId === frontendSessionId)) };
|
|
1821
|
+
}
|
|
1822
|
+
/** Restricted session adapter: only preconfigured argv and the exact owned
|
|
1823
|
+
* terminal can be launched; no remote drive or arbitrary shell commands. */
|
|
1824
|
+
async function integrationPaneIsIdleShell(pane) {
|
|
1825
|
+
if (!pane.isShell)
|
|
1826
|
+
return false;
|
|
1827
|
+
try {
|
|
1828
|
+
const { stdout } = await execFileAsync('ps', ['-p', String(pane.panePid), '-o', 'pgid=,tpgid=,args='], { timeout: 3000, maxBuffer: 16384 });
|
|
1829
|
+
const row = stdout.trim().match(/^(\d+)\s+(\d+)\s+(.+)$/);
|
|
1830
|
+
if (!row || row[1] !== row[2])
|
|
1831
|
+
return false;
|
|
1832
|
+
const argv = splitCommandToArgv(row[3]);
|
|
1833
|
+
const command = normalizeProgramName(argv[0]?.replace(/^-/, ''))?.toLowerCase();
|
|
1834
|
+
return !!command && shellNamesBackend.has(command) && argv.slice(1).every(arg => ['-l', '-i', '-il', '-li', '--login', '--interactive'].includes(arg));
|
|
1835
|
+
}
|
|
1836
|
+
catch {
|
|
1837
|
+
return false;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
function integrationTerminalRecord(record) {
|
|
1841
|
+
const terminal = globalSessionState.sessions.find(s => s.sessionId === record.session_id);
|
|
1842
|
+
if (terminal && (terminal.mode !== 'tmux' || terminal.tmuxSessionName !== `wt-integration-${record.session_id}`))
|
|
1843
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'Owned TD terminal binding changed', 409);
|
|
1844
|
+
return terminal;
|
|
1845
|
+
}
|
|
1846
|
+
export const integrationSessionAdapter = {
|
|
1847
|
+
subscribe(listener) { integrationSessionObservers.add(listener); return () => { integrationSessionObservers.delete(listener); }; },
|
|
1848
|
+
registerDeliveryGuard(guard) { integrationDeliveryGuard = guard; return () => { if (integrationDeliveryGuard === guard)
|
|
1849
|
+
integrationDeliveryGuard = undefined; }; },
|
|
1850
|
+
async capture(record) {
|
|
1851
|
+
const observed = await integrationSessionAdapter.inspect(record);
|
|
1852
|
+
if (!observed.exists || !observed.running || observed.agentSlug !== record.agent_slug || !record.terminal_binding
|
|
1853
|
+
|| record.agent_native_session_id && observed.nativeId && record.agent_native_session_id !== observed.nativeId) {
|
|
1854
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'Startup input observation requires the original Agent pane', 409);
|
|
1855
|
+
}
|
|
1856
|
+
return captureTmuxPaneText(runTmux, record.terminal_binding);
|
|
1857
|
+
},
|
|
1858
|
+
async inspect(record) {
|
|
1859
|
+
const terminal = integrationTerminalRecord(record);
|
|
1860
|
+
if (!terminal)
|
|
1861
|
+
return { exists: false, running: false, shell: false, agentSlug: null, nativeId: null };
|
|
1862
|
+
const binding = { sessionId: record.session_id, backendSessionId: terminal.backendSessionId,
|
|
1863
|
+
mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: record.agent_slug,
|
|
1864
|
+
nativeSessionId: record.agent_native_session_id, pane: record.terminal_binding ?? null };
|
|
1865
|
+
const inspected = await inspectCollaborationTmux(binding);
|
|
1866
|
+
if (inspected.state === 'offline')
|
|
1867
|
+
return { exists: false, running: false, shell: false, agentSlug: null, nativeId: null };
|
|
1868
|
+
if (inspected.state !== 'ready' || !inspected.pane)
|
|
1869
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'Owned tmux pane cannot be uniquely verified', 409);
|
|
1870
|
+
const pane = inspected.pane;
|
|
1871
|
+
const layout = await getTmuxLayout(terminal.tmuxSessionName);
|
|
1872
|
+
if (layout.windows.flatMap(window => window.panes).length !== 1 || layout.activePaneId !== pane.paneId)
|
|
1873
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'Integration native binding requires the single owned pane', 409);
|
|
1874
|
+
const backend = terminal.backendSessionId ? terminalSessions.get(terminal.backendSessionId) : null;
|
|
1875
|
+
// Hook evidence is fresh process evidence only on the single owned pane.
|
|
1876
|
+
// A recovered last-known UUID must not prove a new launch succeeded.
|
|
1877
|
+
const nativeId = pane.agentSlug ? pane.nativeSessionId ?? (backend?.agent?.slug === pane.agentSlug && backend.agentSession?.rich && !backend.agentResumeRecovered ? backend.agentSession.sessionId : null) ?? null : null;
|
|
1878
|
+
if (nativeId && (nativeId.length > 256 || /[\x00-\x1f\x7f]/.test(nativeId)))
|
|
1879
|
+
integrationError('NATIVE_SESSION_ID_INVALID', 'Observed native session id is invalid', 409);
|
|
1880
|
+
const route = collaborationRouting.get(record.session_id);
|
|
1881
|
+
if (nativeId && (!record.agent_native_session_id || record.agent_native_session_id === nativeId) && route?.pane
|
|
1882
|
+
&& route.pane.paneId === pane.paneId && route.pane.panePid === pane.panePid && route.pane.serverPid === pane.serverPid && route.pane.sessionId === pane.sessionId
|
|
1883
|
+
&& route.pane.nativeSessionId !== nativeId)
|
|
1884
|
+
collaborationRouting.bind({ ...route, nativeSessionId: nativeId, pane: { ...route.pane, nativeSessionId: nativeId } });
|
|
1885
|
+
return { exists: true, running: Boolean(pane.agentSlug), shell: await integrationPaneIsIdleShell(pane), agentSlug: pane.agentSlug || null, nativeId };
|
|
1886
|
+
},
|
|
1887
|
+
async create(record, prepared) {
|
|
1888
|
+
await listDetectedAgentLaunchers();
|
|
1889
|
+
if (!agentBySlug(record.agent_slug))
|
|
1890
|
+
integrationError('COLLAB_AGENT_UNAVAILABLE', 'Configured agent plugin is not installed');
|
|
1891
|
+
if (integrationTerminalRecord(record))
|
|
1892
|
+
integrationError('SESSION_CREATE_OUTCOME_UNKNOWN', 'Creation intent already has a terminal; inspect it instead of relaunching', 409);
|
|
1893
|
+
await launchIntegrationTerminal(record, false, prepared);
|
|
1894
|
+
},
|
|
1895
|
+
async restore(record, prepared) {
|
|
1896
|
+
await listDetectedAgentLaunchers();
|
|
1897
|
+
const agent = agentBySlug(record.agent_slug);
|
|
1898
|
+
if (!record.agent_native_session_id || !agent || !buildResumeCommand(agent, record.agent_native_session_id, null))
|
|
1899
|
+
integrationError('EXACT_RESUME_UNSUPPORTED', 'Agent plugin must support exact native resume');
|
|
1900
|
+
if (findActiveAgentResumeOwner('', { slug: record.agent_slug, nativeSessionId: record.agent_native_session_id, command: '' }))
|
|
1901
|
+
integrationError('NATIVE_SESSION_ALREADY_RUNNING', 'Native Agent conversation is already running', 409);
|
|
1902
|
+
await launchIntegrationTerminal(record, true, prepared);
|
|
1903
|
+
},
|
|
1904
|
+
};
|
|
1905
|
+
async function launchIntegrationTerminal(record, restoring, prepared) {
|
|
1906
|
+
await collaborationDeliveryWorker.reconfigure(record.session_id, async () => {
|
|
1907
|
+
const group = collaborationStore.getGroup(record.group_id);
|
|
1908
|
+
if (!group || group.deleted)
|
|
1909
|
+
integrationError('TASK_GROUP_NOT_FOUND', 'Integration group no longer exists', 404);
|
|
1910
|
+
const original = await integrationSessionAdapter.inspect(record);
|
|
1911
|
+
if (!original.exists) {
|
|
1912
|
+
let tmuxExists = false;
|
|
1913
|
+
try {
|
|
1914
|
+
await runTmux(['has-session', '-t', `=wt-integration-${record.session_id}`]);
|
|
1915
|
+
tmuxExists = true;
|
|
1916
|
+
}
|
|
1917
|
+
catch (error) {
|
|
1918
|
+
if (!/can't find session|no server running|no sessions|error connecting.*No such file/i.test(getErrorMessage(error)))
|
|
1919
|
+
throw error;
|
|
1920
|
+
}
|
|
1921
|
+
if (tmuxExists)
|
|
1922
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'A terminal with this name exists without the owned binding', 409);
|
|
1923
|
+
}
|
|
1924
|
+
const opened = await openInventorySession({}, { preferredFrontendSessionId: record.session_id,
|
|
1925
|
+
mode: 'tmux', tmuxSessionName: `wt-integration-${record.session_id}`, cwd: record.cwd,
|
|
1926
|
+
name: `${record.agent_slug} · ${group.name}`, customName: true });
|
|
1927
|
+
if (opened.session.sessionId !== record.session_id)
|
|
1928
|
+
integrationError('SESSION_IDENTITY_MISMATCH', 'Terminal id changed', 409);
|
|
1929
|
+
const terminal = integrationTerminalRecord(record);
|
|
1930
|
+
const backend = terminalSessions.get(opened.terminalSession.sessionId);
|
|
1931
|
+
if (!backend)
|
|
1932
|
+
integrationError('SESSION_BACKEND_UNAVAILABLE', 'Owned terminal backend is unavailable', 503);
|
|
1933
|
+
const inspected = await inspectCollaborationTmux({ sessionId: record.session_id, backendSessionId: opened.terminalSession.sessionId,
|
|
1934
|
+
mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: null, nativeSessionId: null,
|
|
1935
|
+
// A recreated tmux may get a new pane only during explicit exact resume.
|
|
1936
|
+
pane: original.exists ? record.terminal_binding ?? null : null }, null, true);
|
|
1937
|
+
if (inspected.state !== 'ready' || !inspected.pane || !await integrationPaneIsIdleShell(inspected.pane))
|
|
1938
|
+
integrationError('SESSION_TARGET_NOT_SHELL', 'Refusing to launch into an unverified shell', 409);
|
|
1939
|
+
const pane = inspected.pane;
|
|
1940
|
+
const pinned = { serverPid: pane.serverPid, sessionId: pane.sessionId,
|
|
1941
|
+
paneId: pane.paneId, panePid: pane.panePid, agentSlug: record.agent_slug, nativeSessionId: record.agent_native_session_id };
|
|
1942
|
+
prepared(pinned); // Must persist before the command enters the terminal.
|
|
1943
|
+
collaborationRouting.bind({ sessionId: record.session_id, backendSessionId: opened.terminalSession.sessionId,
|
|
1944
|
+
mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: record.agent_slug, nativeSessionId: record.agent_native_session_id, pane: pinned });
|
|
1945
|
+
const latest = collaborationStore.getGroup(group.id);
|
|
1946
|
+
if (!latest || latest.deleted)
|
|
1947
|
+
integrationError('TASK_GROUP_NOT_FOUND', 'Integration group changed', 409);
|
|
1948
|
+
collaborationStore.save({ id: latest.id, name: latest.name, sessionIds: [...new Set([...latest.sessionIds, record.session_id])] });
|
|
1949
|
+
if (restoring)
|
|
1950
|
+
upsertGlobalSessionRecord({ ...terminal, agentResume: { slug: record.agent_slug, sessionId: record.agent_native_session_id,
|
|
1951
|
+
launchArgv: [record.profile.executable, ...record.profile.argv], updatedAt: Date.now() } });
|
|
1952
|
+
await persistGlobalStateNow();
|
|
1953
|
+
// Recheck the actual pinned shell immediately before writing. This cannot
|
|
1954
|
+
// use an active-pane target which might have changed during preparation.
|
|
1955
|
+
const shell = await inspectCollaborationTmux({ sessionId: record.session_id, backendSessionId: opened.terminalSession.sessionId,
|
|
1956
|
+
mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: null, nativeSessionId: null, pane: pinned });
|
|
1957
|
+
if (shell.state !== 'ready' || !shell.pane || !await integrationPaneIsIdleShell(shell.pane))
|
|
1958
|
+
integrationError('SESSION_TARGET_NOT_SHELL', 'Owned shell changed before launch', 409);
|
|
1959
|
+
// This owned pane is a verified shell; clear stale rich state before a new
|
|
1960
|
+
// process starts, so its new SessionStart must supply the native binding.
|
|
1961
|
+
backend.agentSession = null;
|
|
1962
|
+
backend.agent = null;
|
|
1963
|
+
backend.agentResumeRecovered = false;
|
|
1964
|
+
await runTmux(['send-keys', '-t', pinned.paneId, '-l', integrationLaunchCommand(record, restoring)]);
|
|
1965
|
+
await runTmux(['send-keys', '-t', pinned.paneId, 'Enter']);
|
|
1966
|
+
broadcastClientState();
|
|
1967
|
+
});
|
|
1796
1968
|
}
|
|
1797
1969
|
const preparingTaskWorkers = new Map();
|
|
1798
1970
|
/** Dedicated persistent terminals leave existing member sessions and the user's checkout untouched. */
|
|
@@ -1806,10 +1978,16 @@ export function prepareCollaborationTaskWorker(task, template, dependencies, ser
|
|
|
1806
1978
|
if (!source || template.serviceId !== service.descriptor().serviceId)
|
|
1807
1979
|
throw new Error('执行成员当前不可用,请协调者重新分派');
|
|
1808
1980
|
const snapshot = orchestrationSessionSnapshot(source);
|
|
1981
|
+
const inheritedProfile = collaborationStore.getGroup(task.groupId)?.memberLaunchProfiles?.[template.sessionId];
|
|
1809
1982
|
const slug = snapshot.agent?.slug ?? source.agentResume?.slug;
|
|
1810
1983
|
const launcher = (await listDetectedAgentLaunchers()).find(a => a.slug === slug);
|
|
1811
1984
|
if (!launcher || !source.cwd)
|
|
1812
1985
|
throw new Error('独立代码任务需要有项目目录的 Agent 成员,请选择可用成员');
|
|
1986
|
+
if (inheritedProfile) {
|
|
1987
|
+
if (inheritedProfile.agentSlug !== launcher.slug)
|
|
1988
|
+
throw new Error('执行成员的启动方案与当前 Agent 不一致,请重新分派');
|
|
1989
|
+
resolveCollaborationLaunch({ launchProfiles: [inheritedProfile] }, { launchProfileId: inheritedProfile.id, agentSlug: launcher.slug });
|
|
1990
|
+
}
|
|
1813
1991
|
const workspace = await prepareTaskWorkspace(task, source.cwd, dependencies, (dependency, repository) => importTaskDependency(task, dependency, repository, service, readDependency));
|
|
1814
1992
|
await pathValidator.allowSessionCwd(workspace.cwd);
|
|
1815
1993
|
const existing = globalSessionState.sessions.find(s => s.cwd === workspace.cwd);
|
|
@@ -1835,7 +2013,7 @@ export function prepareCollaborationTaskWorker(task, template, dependencies, ser
|
|
|
1835
2013
|
const temporary = `${launchFile}.${process.pid}.tmp`;
|
|
1836
2014
|
await fs.promises.writeFile(temporary, JSON.stringify({ sessionId: record.sessionId, backendId: opened.terminalSession.sessionId }), { mode: 0o600 });
|
|
1837
2015
|
await fs.promises.rename(temporary, launchFile);
|
|
1838
|
-
writeTerminalInput(backend, `${buildCollaborationSpawnCommand({ slug: launcher.slug, command: launcher.command })}\r`);
|
|
2016
|
+
writeTerminalInput(backend, `${buildCollaborationSpawnCommand({ slug: launcher.slug, command: inheritedProfile?.command ?? launcher.command })}\r`);
|
|
1839
2017
|
}
|
|
1840
2018
|
const group = collaborationStore.getGroup(task.groupId);
|
|
1841
2019
|
if (!group || group.deleted)
|
|
@@ -1843,6 +2021,8 @@ export function prepareCollaborationTaskWorker(task, template, dependencies, ser
|
|
|
1843
2021
|
if (!group.sessionIds.includes(record.sessionId))
|
|
1844
2022
|
await service.save({ id: group.id, name: group.name,
|
|
1845
2023
|
sessionIds: [...group.sessionIds, record.sessionId], expectedUpdatedAt: group.updatedAt });
|
|
2024
|
+
if (inheritedProfile)
|
|
2025
|
+
collaborationStore.setMemberLaunchProfile(group.id, record.sessionId, inheritedProfile);
|
|
1846
2026
|
return { sessionId: record.sessionId, workspace };
|
|
1847
2027
|
})().finally(() => preparingTaskWorkers.delete(key));
|
|
1848
2028
|
preparingTaskWorkers.set(key, operation);
|
|
@@ -3192,6 +3372,7 @@ function broadcastAgentStatus(sessionId, session, force = false) {
|
|
|
3192
3372
|
if (!force && previousSnapshot === snapshot)
|
|
3193
3373
|
return;
|
|
3194
3374
|
lastAgentStatusSnapshots.set(sessionId, snapshot);
|
|
3375
|
+
notifyIntegrationSessions();
|
|
3195
3376
|
broadcastEvent(sessionId, payload);
|
|
3196
3377
|
const previous = previousSnapshot
|
|
3197
3378
|
? JSON.parse(previousSnapshot)
|
|
@@ -5802,26 +5983,28 @@ router.post('/operations/collaboration-groups/:groupId/team', async (req, res) =
|
|
|
5802
5983
|
return res.status(404).json({ error: '协作组不存在' });
|
|
5803
5984
|
if (group.federated)
|
|
5804
5985
|
throw new Error('跨服务组请先从成员设置添加 Agent');
|
|
5805
|
-
const agentSlug
|
|
5986
|
+
const { agentSlug, profile } = resolveCollaborationLaunch(group, req.body ?? {});
|
|
5806
5987
|
if (!(await listDetectedAgentLaunchers()).some(agent => agent.slug === agentSlug))
|
|
5807
5988
|
throw new Error('所选 Agent 当前不可用');
|
|
5808
5989
|
if (typeof req.body?.cwd !== 'string' || !req.body.cwd.trim())
|
|
5809
5990
|
throw new Error('请选择工作目录');
|
|
5810
5991
|
const cwd = await resolveWorkingDirectory(req, req.body.cwd);
|
|
5811
5992
|
const previous = preparingTeams.get(group.id) ?? Promise.resolve();
|
|
5812
|
-
const operation = previous.catch(() => { }).then(() => ensureTeam({ agentSlug, cwd,
|
|
5993
|
+
const operation = previous.catch(() => { }).then(() => ensureTeam({ agentSlug, cwd, launchProfileKey: launchProfileKey(profile),
|
|
5813
5994
|
members: () => {
|
|
5814
5995
|
const current = collaborationStore.getGroup(group.id);
|
|
5815
5996
|
if (!current || current.deleted)
|
|
5816
5997
|
throw new Error('协作组已删除');
|
|
5998
|
+
if (profile && launchProfileKey(current.launchProfiles?.find(p => p.id === profile.id)) !== launchProfileKey(profile))
|
|
5999
|
+
throw new Error('启动方案已变更,请重新开始协作');
|
|
5817
6000
|
return globalSessionState.sessions.filter(record => current.sessionIds.includes(record.sessionId))
|
|
5818
|
-
.map(record => ({ id: record.sessionId, cwd: record.cwd, role: current.roles?.[record.sessionId], agentSlug: orchestrationSessionSnapshot(record).agent?.slug }));
|
|
6001
|
+
.map(record => ({ id: record.sessionId, cwd: record.cwd, role: current.roles?.[record.sessionId], agentSlug: orchestrationSessionSnapshot(record).agent?.slug, launchProfileKey: launchProfileKey(current.memberLaunchProfiles?.[record.sessionId]) }));
|
|
5819
6002
|
},
|
|
5820
6003
|
spawn: async (role) => {
|
|
5821
6004
|
const current = collaborationStore.getGroup(group.id);
|
|
5822
6005
|
if (!current || current.deleted)
|
|
5823
6006
|
throw new Error('协作组已删除');
|
|
5824
|
-
const result = await spawnCollaborationAgentSession(req, current, null, { agentSlug, cwd, mode: 'tmux', name: role.startsWith('自动协调者') ? `协调 ${group.name}` : `执行与评审 ${group.name}` }, role);
|
|
6007
|
+
const result = await spawnCollaborationAgentSession(req, current, null, { agentSlug, launchProfileId: profile?.id ?? '', cwd, mode: 'tmux', name: role.startsWith('自动协调者') ? `协调 ${group.name}` : `执行与评审 ${group.name}` }, role);
|
|
5825
6008
|
return result.session.sessionId;
|
|
5826
6009
|
},
|
|
5827
6010
|
}));
|
|
@@ -6633,7 +6816,7 @@ router.put('/toolbar-presets', (req, res) => {
|
|
|
6633
6816
|
async function getSettingsPayload() {
|
|
6634
6817
|
const localAccess = localAccessManager.getState();
|
|
6635
6818
|
const interfaces = await Promise.all(localAccess.interfaces.map(async (entry) => {
|
|
6636
|
-
const url =
|
|
6819
|
+
const url = localAccessInterfaceUrl(localAccess.url, entry.address);
|
|
6637
6820
|
const qrDataUrl = await QRCode.toDataURL(url, {
|
|
6638
6821
|
margin: 1,
|
|
6639
6822
|
width: 132,
|
|
@@ -6669,7 +6852,7 @@ async function getSettingsPayload() {
|
|
|
6669
6852
|
localAccess: {
|
|
6670
6853
|
...localAccess,
|
|
6671
6854
|
interfaces,
|
|
6672
|
-
onboardingUrl: getOnboardingServerUrl() ?? null,
|
|
6855
|
+
onboardingUrl: localAccess.status === 'loopback-only' ? null : getOnboardingServerUrl() ?? null,
|
|
6673
6856
|
},
|
|
6674
6857
|
};
|
|
6675
6858
|
}
|
|
@@ -11,7 +11,26 @@ function normalizeQuestionName(name) {
|
|
|
11
11
|
return name.endsWith('.') ? name.slice(0, -1).toLowerCase() : name.toLowerCase();
|
|
12
12
|
}
|
|
13
13
|
export function isLoopbackHost(host) {
|
|
14
|
-
|
|
14
|
+
const normalized = host.replace(/^\[|\]$/g, '').toLowerCase();
|
|
15
|
+
return LOCALHOST_NAMES.has(normalized) || normalized.startsWith('127.') || normalized.startsWith('::ffff:127.');
|
|
16
|
+
}
|
|
17
|
+
export function localAccessOrigin(host, port, scheme) {
|
|
18
|
+
const hostname = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
|
|
19
|
+
return new URL(`${scheme}://${hostname}:${port}`).origin;
|
|
20
|
+
}
|
|
21
|
+
export function localAccessInterfaceUrl(serviceUrl, address) {
|
|
22
|
+
const origin = new URL(serviceUrl);
|
|
23
|
+
origin.hostname = address.includes(':') && !address.startsWith('[') ? `[${address}]` : address;
|
|
24
|
+
return origin.origin;
|
|
25
|
+
}
|
|
26
|
+
function getBoundLanIPv4Interfaces(host) {
|
|
27
|
+
if (isLoopbackHost(host))
|
|
28
|
+
return [];
|
|
29
|
+
const interfaces = getLanIPv4Interfaces();
|
|
30
|
+
if (host === '0.0.0.0' || host === '::' || host === '[::]')
|
|
31
|
+
return interfaces;
|
|
32
|
+
const address = host.replace(/^::ffff:/, '');
|
|
33
|
+
return interfaces.filter((entry) => entry.address === address);
|
|
15
34
|
}
|
|
16
35
|
function interfaceLabel(name) {
|
|
17
36
|
if (name === 'en0')
|
|
@@ -47,18 +66,19 @@ export function getLanIPv4Addresses() {
|
|
|
47
66
|
}
|
|
48
67
|
function buildState(setting, options, status, reason) {
|
|
49
68
|
const hostname = hostnameForName(setting.name);
|
|
50
|
-
const interfaces =
|
|
69
|
+
const interfaces = getBoundLanIPv4Interfaces(options.host);
|
|
51
70
|
const lanAddresses = interfaces.map((entry) => entry.address);
|
|
52
71
|
const onboardingHost = lanAddresses[0] ?? null;
|
|
53
|
-
const
|
|
72
|
+
const wildcardHost = options.host === '0.0.0.0' || options.host === '::' || options.host === '[::]';
|
|
73
|
+
const fallbackHostname = onboardingHost ?? (wildcardHost ? hostname : options.host);
|
|
54
74
|
return {
|
|
55
75
|
name: setting.name,
|
|
56
76
|
source: setting.source,
|
|
57
77
|
hostname,
|
|
58
78
|
fallbackHostname,
|
|
59
|
-
url:
|
|
60
|
-
fallbackUrl:
|
|
61
|
-
onboardingUrl: onboardingHost ?
|
|
79
|
+
url: localAccessOrigin(hostname, options.port, options.scheme),
|
|
80
|
+
fallbackUrl: localAccessOrigin(fallbackHostname, options.port, options.scheme),
|
|
81
|
+
onboardingUrl: onboardingHost ? `${localAccessOrigin(onboardingHost, options.onboardingPort ?? options.port, 'http')}/ca` : null,
|
|
62
82
|
status,
|
|
63
83
|
reason,
|
|
64
84
|
httpsEnabled: options.scheme === 'https',
|
|
@@ -84,7 +104,7 @@ export class LocalAccessManager {
|
|
|
84
104
|
this.options = options;
|
|
85
105
|
await this.stop();
|
|
86
106
|
let setting = await getLocalAccessSettingAsync();
|
|
87
|
-
const lanAddresses =
|
|
107
|
+
const lanAddresses = getBoundLanIPv4Interfaces(options.host).map((entry) => entry.address);
|
|
88
108
|
if (isLoopbackHost(options.host)) {
|
|
89
109
|
this.state = buildState(setting, options, 'loopback-only', 'Server is bound to loopback only.');
|
|
90
110
|
return this.state;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const DEFAULT_SESSION_DISPLAY_SHELL_NAMES = new Set([
|
|
2
|
+
'bash',
|
|
3
|
+
'zsh',
|
|
4
|
+
'fish',
|
|
5
|
+
'sh',
|
|
6
|
+
'dash',
|
|
7
|
+
'ksh',
|
|
8
|
+
'tcsh',
|
|
9
|
+
'csh',
|
|
10
|
+
'nu',
|
|
11
|
+
]);
|
|
12
|
+
export function getCwdLeafName(cwd) {
|
|
13
|
+
if (!cwd)
|
|
14
|
+
return null;
|
|
15
|
+
if (cwd === '/')
|
|
16
|
+
return '/';
|
|
17
|
+
const segments = cwd.replace(/\/+$/, '').split('/');
|
|
18
|
+
return segments[segments.length - 1] || cwd;
|
|
19
|
+
}
|
|
20
|
+
export function getSessionDisplayLines(session, activeProgram, cwd, shellNames = DEFAULT_SESSION_DISPLAY_SHELL_NAMES, shellTitle = null, promptState = null) {
|
|
21
|
+
if (session.customName)
|
|
22
|
+
return { primary: session.name, secondary: getCwdLeafName(cwd) };
|
|
23
|
+
// Shell integration (OSC 2) provides real-time title: command name when running,
|
|
24
|
+
// cwd when idle. This is faster and more accurate than server-side process polling.
|
|
25
|
+
if (shellTitle) {
|
|
26
|
+
const cwdLeaf = getCwdLeafName(cwd);
|
|
27
|
+
const titleLooksLikeCwd = shellTitle === cwd || shellTitle === cwdLeaf;
|
|
28
|
+
// If the shell reports a running state, the title is the command name.
|
|
29
|
+
if (promptState !== 'idle' && !shellNames.has(shellTitle) && !titleLooksLikeCwd) {
|
|
30
|
+
return { primary: shellTitle, secondary: cwdLeaf };
|
|
31
|
+
}
|
|
32
|
+
// If idle, the title is typically the cwd — fall through to show cwd leaf.
|
|
33
|
+
}
|
|
34
|
+
if (activeProgram && !shellNames.has(activeProgram)) {
|
|
35
|
+
return { primary: activeProgram, secondary: getCwdLeafName(cwd) };
|
|
36
|
+
}
|
|
37
|
+
const dir = getCwdLeafName(cwd);
|
|
38
|
+
if (dir)
|
|
39
|
+
return { primary: dir, secondary: null };
|
|
40
|
+
return { primary: session.name, secondary: null };
|
|
41
|
+
}
|
|
42
|
+
export function getSessionDisplayName(session, activeProgram, cwd, shellNames = DEFAULT_SESSION_DISPLAY_SHELL_NAMES, shellTitle = null, promptState = null) {
|
|
43
|
+
return getSessionDisplayLines(session, activeProgram, cwd, shellNames, shellTitle, promptState).primary;
|
|
44
|
+
}
|
|
45
|
+
/** Resolve the same title hints the session sidebar uses, without exposing route IDs. */
|
|
46
|
+
export function collaborationSessionDisplayName(session) {
|
|
47
|
+
const cwdLeaf = getCwdLeafName(session.cwd ?? null);
|
|
48
|
+
const title = session.shellTitle === session.cwd || session.shellTitle === cwdLeaf ? null : session.shellTitle ?? null;
|
|
49
|
+
const name = getSessionDisplayName(session, session.activeProgram ?? null, null, DEFAULT_SESSION_DISPLAY_SHELL_NAMES, title);
|
|
50
|
+
return !name.trim() || /^(?:tmux:|remote:|wt-)/i.test(name) || name === session.sessionId
|
|
51
|
+
? session.agent?.displayName || cwdLeaf || '终端会话'
|
|
52
|
+
: name;
|
|
53
|
+
}
|