termdock 1.4.294 → 1.4.296
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-BiLjlrk-.js +171 -0
- package/dist/client/assets/App-BiLjlrk-.js.br +0 -0
- package/dist/client/assets/App-BiLjlrk-.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-D2hm-GX-.js → ChangeWalkthroughPanel-DXprT-7m.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-DXprT-7m.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-DXprT-7m.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-DLmKJylJ.js → DagPlayground-DZcUunT5.js} +1 -1
- package/dist/client/assets/DagPlayground-DZcUunT5.js.br +0 -0
- package/dist/client/assets/DagPlayground-DZcUunT5.js.gz +0 -0
- package/dist/client/assets/{DiffLab-Bje07ujV.js → DiffLab-Brv4DCTb.js} +1 -1
- package/dist/client/assets/DiffLab-Brv4DCTb.js.br +0 -0
- package/dist/client/assets/DiffLab-Brv4DCTb.js.gz +0 -0
- package/dist/client/assets/{DiffReview-CcLHnQu-.js → DiffReview-BuLu1qCi.js} +1 -1
- package/dist/client/assets/DiffReview-BuLu1qCi.js.br +0 -0
- package/dist/client/assets/DiffReview-BuLu1qCi.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CIieaScN.js → DiffReviewLab-DSGamuAD.js} +1 -1
- package/dist/client/assets/DiffReviewLab-DSGamuAD.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-DSGamuAD.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-0nWShFhC.js → DiffViewer-BUCYxg27.js} +1 -1
- package/dist/client/assets/DiffViewer-BUCYxg27.js.br +0 -0
- package/dist/client/assets/DiffViewer-BUCYxg27.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-B2Hrizox.js → ModelPreview-Bnlo-oVE.js} +1 -1
- package/dist/client/assets/ModelPreview-Bnlo-oVE.js.br +0 -0
- package/dist/client/assets/ModelPreview-Bnlo-oVE.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-CiYxOpjs.js → RightSidebar-r_3Lk5Rp.js} +48 -52
- package/dist/client/assets/RightSidebar-r_3Lk5Rp.js.br +0 -0
- package/dist/client/assets/RightSidebar-r_3Lk5Rp.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-BvhG-Int.js → abnfDiagram-VCTEODGH-K6Ppkrbt.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-K6Ppkrbt.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-K6Ppkrbt.js.gz +0 -0
- package/dist/client/assets/app-CATnTUZF.js +35 -0
- package/dist/client/assets/app-CATnTUZF.js.br +0 -0
- package/dist/client/assets/app-CATnTUZF.js.gz +0 -0
- package/dist/client/assets/{arc-Cfd1r0w4.js → arc-Co2OQqtH.js} +1 -1
- package/dist/client/assets/arc-Co2OQqtH.js.br +0 -0
- package/dist/client/assets/arc-Co2OQqtH.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-CYcaAY_y.js → architectureDiagram-5GKGNRK7-BQnl7tVF.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BQnl7tVF.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BQnl7tVF.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-uGZowYBC.js → blockDiagram-I7D4REHJ-Bm5D5-qq.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bm5D5-qq.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bm5D5-qq.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-BuAjHXw2.js → c4Diagram-7LVT6UL2-B9oPpey8.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-B9oPpey8.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-B9oPpey8.js.gz +0 -0
- package/dist/client/assets/channel-Czv2W4qA.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-DpblcTaf.js → chunk-2Q5K7J3B-TMaWHH0U.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-9DQ9Xhrj.js → chunk-5VM5RSS4-CH7XpknV.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-C99DgtYa.js → chunk-F27PBJKO-CJ1rotBe.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-CJ1rotBe.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CJ1rotBe.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-CJs2LWtE.js → chunk-IMKFNOWR-UYKZ5uOG.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-UYKZ5uOG.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-UYKZ5uOG.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-Bi6NDDYZ.js → chunk-JWPE2WC7-BYL8aXjQ.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-EDihZ7ei.js → chunk-POPQ4Y6H-C3E8yfU2.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-Deb_Pzwv.js → chunk-SVP7TREG-DCTDYa1E.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-DCTDYa1E.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DCTDYa1E.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-C6wEoKIF.js → chunk-TICWLB2K-wHiaOsBh.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-wHiaOsBh.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-wHiaOsBh.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DkhA8D3i.js → chunk-XXDRQBXY-D_d479hK.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-BdvOOL9k.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BdvOOL9k.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CAImJ8rh.js → cose-bilkent-JH36ORCC-DnhlPBLr.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-DnhlPBLr.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-DnhlPBLr.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-D3Egll3y.js → cynefin-OW5HDTMX-BsjzNqJZ.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-BsjzNqJZ.js.br +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-D3Egll3y.js.gz → cynefin-OW5HDTMX-BsjzNqJZ.js.gz} +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-MjvCZkx7.js → cynefinDiagram-5FMLGOSQ-sVUb0zY5.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-sVUb0zY5.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-sVUb0zY5.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-CrJn07Be.js → dagre-GXQ25YYZ-YErk8S-c.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-YErk8S-c.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-YErk8S-c.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-x2YTsmxU.js → diagram-S7CK7UJ4-BaHbV5ho.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-BaHbV5ho.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-BaHbV5ho.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-D98MzrbS.js → diagram-UQ7AKVKN-BocCYx3V.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-BocCYx3V.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BocCYx3V.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-DB_ACbg-.js → diagram-VSXAHHWV-ZMTYwWOQ.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-ZMTYwWOQ.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-ZMTYwWOQ.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-Drt4iWsQ.js → diagram-VX7I27RA-xmk_EY1h.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-xmk_EY1h.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-xmk_EY1h.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-D8mGxerZ.js → diagram-Z3DM3KII-DKDY_cG6.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-DKDY_cG6.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DKDY_cG6.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-DTYnrl_Q.js → ebnfDiagram-PWID7BFC-C_0z-Jx9.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-C_0z-Jx9.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-C_0z-Jx9.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-ChsNovQf.js → erDiagram-RLTQ6QDP-DHUaG7mt.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-DHUaG7mt.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DHUaG7mt.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-DsFiio6_.js → flowDiagram-HODETNUW-BMNsdMBD.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-BMNsdMBD.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BMNsdMBD.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-BbHyLMqr.js → ganttDiagram-EL5Y4UJY-BH1AiKuF.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BH1AiKuF.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BH1AiKuF.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-3rZyzlwR.js → gestureArbiter-DvupkPra.js} +1 -1
- package/dist/client/assets/gestureArbiter-DvupkPra.js.br +0 -0
- package/dist/client/assets/gestureArbiter-DvupkPra.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-CTPZoYHy.js → gitGraphDiagram-WWUBYQGX-DAgV0MV-.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DAgV0MV-.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DAgV0MV-.js.gz +0 -0
- package/dist/client/assets/{index-DxhkHH1u.css → index-Bi9A6QUP.css} +1 -1
- package/dist/client/assets/index-Bi9A6QUP.css.br +0 -0
- package/dist/client/assets/index-Bi9A6QUP.css.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-DqG9-3Dv.js → infoDiagram-27XIBGKW-C7iSg0cB.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-C7BUr6Q1.js → ishikawaDiagram-5VMMS53U-BpZwsQvw.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-BpZwsQvw.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-BpZwsQvw.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-DeKgSie7.js → journeyDiagram-3NMN7TZE-DXEeFLvw.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DXEeFLvw.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DXEeFLvw.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-BXLMRLCs.js → kanban-definition-UXKFOSKX-CV9ivL5u.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-CV9ivL5u.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CV9ivL5u.js.gz +0 -0
- package/dist/client/assets/{layout-BIGVsIVB.js → layout-DsKKsJKX.js} +1 -1
- package/dist/client/assets/layout-DsKKsJKX.js.br +0 -0
- package/dist/client/assets/layout-DsKKsJKX.js.gz +0 -0
- package/dist/client/assets/{linear-BhqHS_Ls.js → linear-Dl9MDNV3.js} +1 -1
- package/dist/client/assets/linear-Dl9MDNV3.js.br +0 -0
- package/dist/client/assets/linear-Dl9MDNV3.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DYTWj2Pu.js → mermaid.core-CxZFe3as.js} +5 -5
- package/dist/client/assets/mermaid.core-CxZFe3as.js.br +0 -0
- package/dist/client/assets/mermaid.core-CxZFe3as.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-BKVI5pEJ.js → mindmap-definition-YA3MSWOX-C3ormYdL.js} +2 -2
- package/dist/client/assets/mindmap-definition-YA3MSWOX-C3ormYdL.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-C3ormYdL.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-DyrBaUP8.js → passwordBootstrap-a8z6jJNY.js} +2 -2
- package/dist/client/assets/passwordBootstrap-a8z6jJNY.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-a8z6jJNY.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-DdRPwDgf.js → pegDiagram-XKGWAZYB-CG0wNylH.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-CG0wNylH.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-CG0wNylH.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-KzblsFOl.js → pieDiagram-E7YTZNPT-D2-ydqyX.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-D2-ydqyX.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-D2-ydqyX.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Co2Mu1vo.js → quadrantDiagram-AXDQQJYC-CK3fRC18.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CK3fRC18.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CK3fRC18.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-DjvJ0Ysn.js → railroadDiagram-O6MQD6OU-V4EFlydu.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-V4EFlydu.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-V4EFlydu.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-VL4F6lii.js → referenceLongPress-BjmYd1vB.js} +1 -1
- package/dist/client/assets/referenceLongPress-BjmYd1vB.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BjmYd1vB.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-QJ6afxsR.js → requirementDiagram-BXWQKSXE-Di1_tyAX.js} +1 -1
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-QJ6afxsR.js.br → requirementDiagram-BXWQKSXE-Di1_tyAX.js.br} +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Di1_tyAX.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CYd9OO8p.js → sankeyDiagram-P5KCCOFB-D-qpWNza.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-D-qpWNza.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-D-qpWNza.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Cau471RQ.js → sequenceDiagram-WJ2MYXX4-DmIxafrB.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DmIxafrB.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DmIxafrB.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CWBvI9Ex.js → sizeCapture-INFHLROL-4MTh3tTt.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-4MTh3tTt.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-4MTh3tTt.js.gz +0 -0
- package/dist/client/assets/{sparkles-BpYEa9ns.js → sparkles-Dk93lHg0.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-ih47Vg8d.js → stateDiagram-D77RDMKH-CgYgneIv.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-CgYgneIv.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CgYgneIv.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CvPf0fxf.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-Cks23MF4.js → swimlanes-42K2YHIH-OWA9HFVf.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-OWA9HFVf.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-OWA9HFVf.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CZ_OauyW.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-C3Z6mGRy.js → timeline-definition-24CTP7MA-BAzx5DyO.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BAzx5DyO.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BAzx5DyO.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-onS3H-d9.js → triangle-alert-CUIBOwqW.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-9GLhPNes.js → vennDiagram-4TSXK5OY-CBZ-PhTQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-9GLhPNes.js.br → vennDiagram-4TSXK5OY-CBZ-PhTQ.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CBZ-PhTQ.js.gz +0 -0
- package/dist/client/assets/{videoCompression-KoXLuxZT.js → videoCompression-BCnqCkRK.js} +1 -1
- package/dist/client/assets/videoCompression-BCnqCkRK.js.br +0 -0
- package/dist/client/assets/videoCompression-BCnqCkRK.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-BsZeAlBb.js → wardleyDiagram-VM6X3IG4-DbWzC6l5.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DbWzC6l5.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DbWzC6l5.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-BRT0eEuC.js → xychartDiagram-S5SC5T6Z-BmApnTWE.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmApnTWE.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmApnTWE.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 +45 -4
- package/dist/server/agent/collaborationDeliveryWorker.js +1 -1
- package/dist/server/agent/collaborationPeerTransport.js +8 -2
- package/dist/server/agent/collaborationRoutes.js +18 -2
- package/dist/server/agent/collaborationService.js +43 -1
- package/dist/server/agent/collaborationTaskBundles.js +121 -0
- package/dist/server/agent/collaborationTaskCli.js +54 -0
- package/dist/server/agent/collaborationTaskRoutes.js +58 -0
- package/dist/server/agent/collaborationTaskService.js +355 -0
- package/dist/server/agent/collaborationTaskStore.js +773 -0
- package/dist/server/agent/collaborationTaskTypes.js +1 -0
- package/dist/server/agent/collaborationTaskWorkspace.js +100 -0
- package/dist/server/entry.js +11 -1
- package/dist/server/federation/runtime.js +6 -1
- package/dist/server/routes/terminal.js +66 -2
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-CDGrOo_r.js +0 -158
- package/dist/client/assets/App-CDGrOo_r.js.br +0 -0
- package/dist/client/assets/App-CDGrOo_r.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-D2hm-GX-.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-D2hm-GX-.js.gz +0 -0
- package/dist/client/assets/DagPlayground-DLmKJylJ.js.br +0 -0
- package/dist/client/assets/DagPlayground-DLmKJylJ.js.gz +0 -0
- package/dist/client/assets/DiffLab-Bje07ujV.js.br +0 -0
- package/dist/client/assets/DiffLab-Bje07ujV.js.gz +0 -0
- package/dist/client/assets/DiffReview-CcLHnQu-.js.br +0 -0
- package/dist/client/assets/DiffReview-CcLHnQu-.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CIieaScN.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CIieaScN.js.gz +0 -0
- package/dist/client/assets/DiffViewer-0nWShFhC.js.br +0 -0
- package/dist/client/assets/DiffViewer-0nWShFhC.js.gz +0 -0
- package/dist/client/assets/ModelPreview-B2Hrizox.js.br +0 -0
- package/dist/client/assets/ModelPreview-B2Hrizox.js.gz +0 -0
- package/dist/client/assets/RightSidebar-CiYxOpjs.js.br +0 -0
- package/dist/client/assets/RightSidebar-CiYxOpjs.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BvhG-Int.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BvhG-Int.js.gz +0 -0
- package/dist/client/assets/app-CjvwGDVy.js +0 -35
- package/dist/client/assets/app-CjvwGDVy.js.br +0 -0
- package/dist/client/assets/app-CjvwGDVy.js.gz +0 -0
- package/dist/client/assets/arc-Cfd1r0w4.js.br +0 -0
- package/dist/client/assets/arc-Cfd1r0w4.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CYcaAY_y.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CYcaAY_y.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-uGZowYBC.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-uGZowYBC.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BuAjHXw2.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BuAjHXw2.js.gz +0 -0
- package/dist/client/assets/channel-klM1FsDR.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-C99DgtYa.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-C99DgtYa.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CJs2LWtE.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CJs2LWtE.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-Deb_Pzwv.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-Deb_Pzwv.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-C6wEoKIF.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-C6wEoKIF.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-Ccewxt_X.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-Ccewxt_X.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CAImJ8rh.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CAImJ8rh.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-D3Egll3y.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-MjvCZkx7.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-MjvCZkx7.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CrJn07Be.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CrJn07Be.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-x2YTsmxU.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-x2YTsmxU.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-D98MzrbS.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-D98MzrbS.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-DB_ACbg-.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-DB_ACbg-.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-Drt4iWsQ.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-Drt4iWsQ.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-D8mGxerZ.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-D8mGxerZ.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DTYnrl_Q.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DTYnrl_Q.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-ChsNovQf.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-ChsNovQf.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-DsFiio6_.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-DsFiio6_.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BbHyLMqr.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BbHyLMqr.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-3rZyzlwR.js.br +0 -0
- package/dist/client/assets/gestureArbiter-3rZyzlwR.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CTPZoYHy.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CTPZoYHy.js.gz +0 -0
- package/dist/client/assets/index-DxhkHH1u.css.br +0 -0
- package/dist/client/assets/index-DxhkHH1u.css.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-C7BUr6Q1.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-C7BUr6Q1.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DeKgSie7.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DeKgSie7.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BXLMRLCs.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BXLMRLCs.js.gz +0 -0
- package/dist/client/assets/layout-BIGVsIVB.js.br +0 -0
- package/dist/client/assets/layout-BIGVsIVB.js.gz +0 -0
- package/dist/client/assets/linear-BhqHS_Ls.js.br +0 -0
- package/dist/client/assets/linear-BhqHS_Ls.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DYTWj2Pu.js.br +0 -0
- package/dist/client/assets/mermaid.core-DYTWj2Pu.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BKVI5pEJ.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BKVI5pEJ.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-DyrBaUP8.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-DyrBaUP8.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DdRPwDgf.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DdRPwDgf.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-KzblsFOl.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-KzblsFOl.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Co2Mu1vo.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Co2Mu1vo.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjvJ0Ysn.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjvJ0Ysn.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-VL4F6lii.js.br +0 -0
- package/dist/client/assets/referenceLongPress-VL4F6lii.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-QJ6afxsR.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CYd9OO8p.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CYd9OO8p.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cau471RQ.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cau471RQ.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CWBvI9Ex.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CWBvI9Ex.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-ih47Vg8d.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-ih47Vg8d.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-D0ybQxyy.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-Cks23MF4.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-Cks23MF4.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CTe40kKh.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-C3Z6mGRy.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-C3Z6mGRy.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-9GLhPNes.js.gz +0 -0
- package/dist/client/assets/videoCompression-KoXLuxZT.js.br +0 -0
- package/dist/client/assets/videoCompression-KoXLuxZT.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BsZeAlBb.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BsZeAlBb.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BRT0eEuC.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BRT0eEuC.js.gz +0 -0
|
@@ -151,6 +151,10 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
|
|
|
151
151
|
};
|
|
152
152
|
router.get('/capabilities', run((_req, res) => {
|
|
153
153
|
res.json({ protocol_version: 2, limits: COLLAB_LIMITS,
|
|
154
|
+
task_workflow: { version: 2, command: 'td collab task', single_authority: true, explicit_reports: true,
|
|
155
|
+
managed_goals: true, automatic_review: true, dependency_dispatch: true, isolated_worktrees: true, encrypted_commit_transfer: true,
|
|
156
|
+
durable_questions: true, user_acceptance: true, versioned_artifacts: true, independent_reviews: true,
|
|
157
|
+
task_reply: 'Replies to task-linked user messages are stored in the task; status=stored is not a terminal delivery receipt' },
|
|
154
158
|
routing: { background_recovery: true, explicit_rebind: Boolean(rebind), fixed_tmux_pane: true },
|
|
155
159
|
statuses: ['pending', 'delivered', 'failed', 'expired'], queued_status: 'pending',
|
|
156
160
|
semantics: { delivered: 'written to terminal; no application acknowledgement implied',
|
|
@@ -201,8 +205,20 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
|
|
|
201
205
|
}));
|
|
202
206
|
router.post('/reply', run(async (req, res, sessionId) => {
|
|
203
207
|
const original = ownMessage(String(req.body.messageId ?? ''), sessionId, true);
|
|
204
|
-
if (!original.fromSessionId)
|
|
205
|
-
|
|
208
|
+
if (!original.fromSessionId) {
|
|
209
|
+
const link = original.metadata?.termdockTask;
|
|
210
|
+
if (link?.taskId && req.app.locals.collaborationTasks) {
|
|
211
|
+
const extras = extrasFromBody(req.body);
|
|
212
|
+
const status = extras.task?.status ?? (extras.responseKind === 'ack' ? 'ack' : extras.responseKind === 'result' ? 'complete' : extras.responseKind === 'progress' ? 'working' : null);
|
|
213
|
+
const task = await req.app.locals.collaborationTasks.apply(link.taskId, {
|
|
214
|
+
kind: status ? 'report' : 'comment', status: status ?? undefined, attemptId: link.attemptId,
|
|
215
|
+
content: req.body.content, evidence: extras.task?.evidence, idempotencyKey: extras.idempotencyKey,
|
|
216
|
+
}, req.app.locals.collaborationService.taskMember(sessionId));
|
|
217
|
+
res.json({ ok: true, status: 'stored', task_recorded: true, task_id: task.id, task_revision: task.revision });
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
throw new CollaborationError('NO_REPLY_TARGET', '该消息没有成员回复目标;任务请使用 td collab task report 或 task comment');
|
|
221
|
+
}
|
|
206
222
|
const messages = store.send({ ...extrasFromBody(req.body), groupId: original.groupId, fromSessionId: sessionId,
|
|
207
223
|
toSessionIds: [original.fromSessionId], kind: 'reply', content: typeof req.body.content === 'string' ? req.body.content : '',
|
|
208
224
|
replyTo: original.id, threadId: original.threadId });
|
|
@@ -89,6 +89,34 @@ export class CollaborationService {
|
|
|
89
89
|
this.persist();
|
|
90
90
|
}
|
|
91
91
|
descriptor() { return { ...this.options.node(), ...(this.document.origin ? { origin: this.document.origin } : {}) }; }
|
|
92
|
+
taskMember(sessionId) {
|
|
93
|
+
const parsed = address(sessionId);
|
|
94
|
+
if (!parsed)
|
|
95
|
+
return { serviceId: this.options.node().serviceId, sessionId };
|
|
96
|
+
const peer = this.document.peers.find(node => node.origin === parsed.origin);
|
|
97
|
+
if (!peer)
|
|
98
|
+
throw new CollaborationError('TASK_PEER_UNAVAILABLE', '成员所在服务尚未配对', 409);
|
|
99
|
+
return { serviceId: peer.serviceId, sessionId: parsed.id };
|
|
100
|
+
}
|
|
101
|
+
taskSession(member) {
|
|
102
|
+
if (member.serviceId === this.options.node().serviceId)
|
|
103
|
+
return member.sessionId;
|
|
104
|
+
const peer = this.document.peers.find(node => node.serviceId === member.serviceId);
|
|
105
|
+
if (!peer)
|
|
106
|
+
throw new CollaborationError('TASK_PEER_UNAVAILABLE', '任务所在服务尚未配对', 409);
|
|
107
|
+
return remoteSession(peer.origin, member.sessionId);
|
|
108
|
+
}
|
|
109
|
+
async requestTasks(serviceId, payload) {
|
|
110
|
+
const peer = this.document.peers.find(node => node.serviceId === serviceId);
|
|
111
|
+
if (!peer)
|
|
112
|
+
throw new CollaborationError('TASK_PEER_UNAVAILABLE', '任务来源服务未连接,记录已保留', 409);
|
|
113
|
+
const result = await (await this.client(peer)).request({ type: 'collaboration-service', action: 'tasks', ...payload });
|
|
114
|
+
if (result.taskError) {
|
|
115
|
+
const error = result.taskError;
|
|
116
|
+
throw new CollaborationError(error.code, error.message, error.status);
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
92
120
|
/** Called through the existing authenticated administrator connection. No
|
|
93
121
|
* client key is copied; only pinned public service descriptors are persisted. */
|
|
94
122
|
connectKnown(origin, nodes) {
|
|
@@ -260,6 +288,18 @@ export class CollaborationService {
|
|
|
260
288
|
return { ok: true };
|
|
261
289
|
if (packet.action === 'directory')
|
|
262
290
|
return this.snapshot(peer);
|
|
291
|
+
if (packet.action === 'tasks' && this.options.tasks) {
|
|
292
|
+
try {
|
|
293
|
+
return Promise.resolve(this.options.tasks.receive(peer, packet)).catch(error => ({ taskError: {
|
|
294
|
+
code: error instanceof CollaborationError ? error.code : 'TASK_ERROR', message: error instanceof Error ? error.message : String(error),
|
|
295
|
+
status: error instanceof CollaborationError ? error.httpStatus : 400
|
|
296
|
+
} }));
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
return { taskError: { code: error instanceof CollaborationError ? error.code : 'TASK_ERROR',
|
|
300
|
+
message: error instanceof Error ? error.message : String(error), status: error instanceof CollaborationError ? error.httpStatus : 400 } };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
263
303
|
if (packet.action === 'group') {
|
|
264
304
|
const canonical = packet.group;
|
|
265
305
|
if (!canonical?.sessionIds?.some(id => address(id)?.origin === peer.origin) && !this.document.replicas?.[canonical?.id]?.includes(peer.origin))
|
|
@@ -281,7 +321,7 @@ export class CollaborationService {
|
|
|
281
321
|
.filter(group => scope === undefined || group.sessionIds.every(id => address(id) ? true : scope.includes(id)))
|
|
282
322
|
.map(group => mapGroup(group, id => address(id) ? id : remoteSession(origin, id)));
|
|
283
323
|
return { sessions: scope === undefined ? sessions : sessions.filter(session => scope.includes(session.sessionId)),
|
|
284
|
-
groups, nodes: scope === undefined ? this.nodes() : [this.node(), peer] };
|
|
324
|
+
groups, taskHeads: this.options.tasks?.heads(groups.map(g => g.id)) ?? [], nodes: scope === undefined ? this.nodes() : [this.node(), peer] };
|
|
285
325
|
}
|
|
286
326
|
merge(canonical, nodes, source) {
|
|
287
327
|
if (!canonical || typeof canonical.id !== 'string' || !canonical.id.startsWith('cross-') || !Array.isArray(canonical.sessionIds)
|
|
@@ -377,6 +417,8 @@ export class CollaborationService {
|
|
|
377
417
|
this.observations.set(peer.serviceId, { sessions, checkedAt: Date.now() });
|
|
378
418
|
for (const group of data.groups)
|
|
379
419
|
this.merge(group, data.nodes, peer);
|
|
420
|
+
if (Array.isArray(data.taskHeads))
|
|
421
|
+
await this.options.tasks?.sync(peer, data.taskHeads);
|
|
380
422
|
for (const group of this.options.store.federationSnapshot().groups.filter(g => g.federated && (g.sessionIds.some(id => address(id)?.origin === peer.origin) || this.document.replicas?.[g.id]?.includes(peer.origin)))) {
|
|
381
423
|
const scope = this.effectiveScope(peer.serviceId);
|
|
382
424
|
// Never push a group to a scoped peer if it involves other local sessions.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { createReadStream } from 'node:fs';
|
|
5
|
+
import { mkdir, open, readFile, writeFile, rename, stat, unlink } from 'node:fs/promises';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
const exec = promisify(execFile), chunkSize = 256 * 1024, maxBytes = 128 * 1024 * 1024;
|
|
9
|
+
const directory = path.join(os.homedir(), '.termdock', 'task-bundles');
|
|
10
|
+
const preparing = new Map();
|
|
11
|
+
const git = async (cwd, args) => (await exec('git', ['-C', cwd, ...args], { timeout: 60_000, maxBuffer: 1024 * 1024,
|
|
12
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } })).stdout.trim();
|
|
13
|
+
async function digestFile(file) {
|
|
14
|
+
const digest = createHash('sha256');
|
|
15
|
+
for await (const chunk of createReadStream(file))
|
|
16
|
+
digest.update(chunk);
|
|
17
|
+
return digest.digest('hex');
|
|
18
|
+
}
|
|
19
|
+
function acceptedCommit(task) {
|
|
20
|
+
const artifact = task.artifacts.find(a => a.id === task.acceptedArtifactId && a.kind === 'result');
|
|
21
|
+
const commit = artifact?.evidence?.commit;
|
|
22
|
+
if (task.status !== 'accepted' || !artifact || !task.workspace || !commit || !/^[a-f0-9]{40,64}$/.test(commit)
|
|
23
|
+
|| !/^[a-f0-9]{40,64}$/.test(task.workspace.base) || !/^[a-f0-9]{32}$/.test(artifact.id))
|
|
24
|
+
throw new Error('依赖没有已评审的代码提交');
|
|
25
|
+
return { artifact, commit, base: task.workspace.base, workspace: task.workspace };
|
|
26
|
+
}
|
|
27
|
+
async function prepareBundle(task) {
|
|
28
|
+
const { artifact, commit, base, workspace } = acceptedCommit(task);
|
|
29
|
+
const existing = preparing.get(artifact.id);
|
|
30
|
+
if (existing)
|
|
31
|
+
return existing;
|
|
32
|
+
const operation = (async () => {
|
|
33
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
34
|
+
const file = path.join(directory, `${artifact.id}.bundle`), metadataFile = `${file}.json`;
|
|
35
|
+
try {
|
|
36
|
+
const metadata = JSON.parse(await readFile(metadataFile, 'utf8'));
|
|
37
|
+
if (metadata.commit === commit && metadata.base === base && metadata.bytes === (await stat(file)).size)
|
|
38
|
+
return metadata;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error.code !== 'ENOENT')
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
// Export the reviewed commit, even if the task branch has since moved.
|
|
45
|
+
const ref = `refs/termdock/exports/${artifact.id}`;
|
|
46
|
+
await git(workspace.cwd, ['update-ref', ref, commit]);
|
|
47
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
48
|
+
if (commit === base)
|
|
49
|
+
throw new Error('依赖未产生代码提交,无需传输;请检查项目基线是否一致');
|
|
50
|
+
try {
|
|
51
|
+
await git(workspace.cwd, ['bundle', 'create', temporary, ref, `^${base}`]);
|
|
52
|
+
const bytes = (await stat(temporary)).size;
|
|
53
|
+
if (bytes > maxBytes)
|
|
54
|
+
throw new Error('依赖提交包超过 128 MiB,请通过仓库远端同步后继续');
|
|
55
|
+
const metadata = { bytes, digest: await digestFile(temporary), commit, base, ref };
|
|
56
|
+
await rename(temporary, file);
|
|
57
|
+
await writeFile(`${metadataFile}.${process.pid}.tmp`, JSON.stringify(metadata), { mode: 0o600 });
|
|
58
|
+
await rename(`${metadataFile}.${process.pid}.tmp`, metadataFile);
|
|
59
|
+
return metadata;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await unlink(temporary).catch(() => { });
|
|
63
|
+
}
|
|
64
|
+
})().finally(() => preparing.delete(artifact.id));
|
|
65
|
+
preparing.set(artifact.id, operation);
|
|
66
|
+
return operation;
|
|
67
|
+
}
|
|
68
|
+
/** Chunks travel on the existing Noise RPC. No HTTP upload or repository credentials are introduced. */
|
|
69
|
+
export async function taskBundleChunk(task, offset) {
|
|
70
|
+
if (!Number.isSafeInteger(offset) || Number(offset) < 0 || Number(offset) % chunkSize !== 0)
|
|
71
|
+
throw new Error('提交包偏移无效');
|
|
72
|
+
const metadata = await prepareBundle(task);
|
|
73
|
+
if (Number(offset) >= metadata.bytes)
|
|
74
|
+
throw new Error('提交包偏移超出范围');
|
|
75
|
+
const artifact = acceptedCommit(task).artifact;
|
|
76
|
+
const file = await open(path.join(directory, `${artifact.id}.bundle`), 'r');
|
|
77
|
+
try {
|
|
78
|
+
const buffer = Buffer.alloc(Math.min(chunkSize, metadata.bytes - Number(offset)));
|
|
79
|
+
const { bytesRead } = await file.read(buffer, 0, buffer.length, Number(offset));
|
|
80
|
+
return { ...metadata, offset, data: buffer.subarray(0, bytesRead).toString('base64') };
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await file.close();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export async function importTaskDependency(current, dependency, repository, peers, localRead) {
|
|
87
|
+
const expected = acceptedCommit(dependency);
|
|
88
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
89
|
+
const temporary = path.join(directory, `${expected.artifact.id}.incoming.${current.id}.${process.pid}.tmp`);
|
|
90
|
+
const file = await open(temporary, 'w', 0o600);
|
|
91
|
+
let offset = 0, digest = '', total = Infinity, ref = '';
|
|
92
|
+
try {
|
|
93
|
+
do {
|
|
94
|
+
const response = current.ownerServiceId === peers.descriptor().serviceId ? await localRead(current.id, dependency.id, offset)
|
|
95
|
+
: await peers.requestTasks(current.ownerServiceId, { op: 'dependency-bundle', taskId: current.id, dependencyId: dependency.id, offset });
|
|
96
|
+
const chunk = response.chunk;
|
|
97
|
+
if (!chunk || chunk.offset !== offset || chunk.commit !== expected.commit || chunk.base !== expected.base
|
|
98
|
+
|| !Number.isSafeInteger(chunk.bytes) || chunk.bytes < 1 || chunk.bytes > maxBytes || typeof chunk.digest !== 'string' || !/^[a-f0-9]{64}$/.test(chunk.digest)
|
|
99
|
+
|| chunk.ref !== `refs/termdock/exports/${expected.artifact.id}` || typeof chunk.data !== 'string' || chunk.data.length > 350_000
|
|
100
|
+
|| digest && digest !== chunk.digest || offset && total !== chunk.bytes)
|
|
101
|
+
throw new Error('依赖提交包校验信息无效');
|
|
102
|
+
digest = chunk.digest;
|
|
103
|
+
total = chunk.bytes;
|
|
104
|
+
ref = chunk.ref;
|
|
105
|
+
const bytes = Buffer.from(chunk.data, 'base64');
|
|
106
|
+
if (!bytes.length || bytes.length > chunkSize || offset + bytes.length > total)
|
|
107
|
+
throw new Error('依赖提交包分片无效');
|
|
108
|
+
await file.write(bytes, 0, bytes.length, offset);
|
|
109
|
+
offset += bytes.length;
|
|
110
|
+
} while (offset < total);
|
|
111
|
+
await file.close();
|
|
112
|
+
if (await digestFile(temporary) !== digest)
|
|
113
|
+
throw new Error('依赖提交包摘要不匹配,保留任务等待重试');
|
|
114
|
+
await git(repository, ['bundle', 'verify', temporary]);
|
|
115
|
+
await git(repository, ['fetch', '--no-tags', temporary, ref]);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await file.close().catch(() => { });
|
|
119
|
+
await unlink(temporary).catch(() => { });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
export async function executeTaskCommand(command, request, io) {
|
|
4
|
+
const o = command.options, operation = command.operation;
|
|
5
|
+
const bodyOptions = ['content', 'file', 'stdin', 'idempotency-key'];
|
|
6
|
+
const allowed = {
|
|
7
|
+
list: ['group'], get: [], create: [...bodyOptions, 'group', 'title', 'constraints', 'acceptance', 'assignee', 'coordinator', 'parent', 'depends-on', 'managed', 'reviewers', 'shared-directory', 'integration'],
|
|
8
|
+
assign: [...bodyOptions, 'assignee', 'revision'], report: [...bodyOptions, 'attempt', 'status', 'evidence'], ask: [...bodyOptions, 'attempt', 'options'],
|
|
9
|
+
plan: [...bodyOptions, 'attempt', 'evidence'], review: [...bodyOptions, 'artifact', 'evidence', 'verdict'], comment: bodyOptions,
|
|
10
|
+
'request-review': [...bodyOptions, 'artifact', 'assignee', 'revision'],
|
|
11
|
+
revise: [...bodyOptions, 'revision'], close: [...bodyOptions, 'revision'], reopen: [...bodyOptions, 'revision'],
|
|
12
|
+
coordinate: [...bodyOptions, 'revision'], pause: [...bodyOptions, 'revision'], resume: [...bodyOptions, 'revision'], retry: [...bodyOptions, 'revision'],
|
|
13
|
+
};
|
|
14
|
+
for (const flag of Object.keys(o))
|
|
15
|
+
if (![...allowed[operation], 'session', 'json', 'jsonl', 'text', 'help'].includes(flag))
|
|
16
|
+
throw new Error(`--${flag} is not supported by task ${operation}`);
|
|
17
|
+
if (operation === 'list')
|
|
18
|
+
return request('GET', `/tasks${o.group ? `?group=${encodeURIComponent(String(o.group))}` : ''}`);
|
|
19
|
+
if (operation === 'get')
|
|
20
|
+
return request('GET', `/tasks/${encodeURIComponent(command.target)}`);
|
|
21
|
+
const contentSources = [o.content, o.file, o.stdin].filter(Boolean).length;
|
|
22
|
+
if (contentSources > 1)
|
|
23
|
+
throw new Error('Choose --content, --file or --stdin');
|
|
24
|
+
const content = o.file ? fs.readFileSync(String(o.file), 'utf8') : o.stdin ? await io.stdin?.() : o.content;
|
|
25
|
+
if (!['assign', 'close', 'reopen', 'request-review', 'pause', 'resume', 'retry'].includes(operation) && (typeof content !== 'string' || !content.trim()))
|
|
26
|
+
throw new Error('This task operation requires --content, --file or --stdin');
|
|
27
|
+
const idempotencyKey = String(o['idempotency-key'] ?? randomUUID());
|
|
28
|
+
const expectedRevision = o.revision === undefined ? undefined : Number(o.revision);
|
|
29
|
+
if (expectedRevision !== undefined && (!Number.isSafeInteger(expectedRevision) || expectedRevision < 1))
|
|
30
|
+
throw new Error('--revision must be a positive integer');
|
|
31
|
+
if (['assign', 'revise', 'close', 'reopen', 'request-review', 'coordinate', 'pause', 'resume', 'retry'].includes(operation) && expectedRevision === undefined)
|
|
32
|
+
throw new Error('Read task get first, then supply --revision to avoid overwriting another decision');
|
|
33
|
+
if (['assign', 'request-review'].includes(operation) && !o.assignee)
|
|
34
|
+
throw new Error('This task operation requires --assignee');
|
|
35
|
+
if (['report', 'ask', 'plan'].includes(operation) && !o.attempt)
|
|
36
|
+
throw new Error('Use --attempt from the dispatch message; never guess the current attempt');
|
|
37
|
+
if (operation === 'create') {
|
|
38
|
+
if (!o.title || !o.group)
|
|
39
|
+
throw new Error('task create requires --title and --group');
|
|
40
|
+
return request('POST', '/tasks', { input: { idempotencyKey, groupId: o.group, title: o.title, spec: content,
|
|
41
|
+
constraints: o.constraints, acceptance: o.acceptance, assigneeSessionId: o.assignee, coordinatorSessionId: o.coordinator,
|
|
42
|
+
parentTaskId: o.parent, dependsOn: o['depends-on'] ? String(o['depends-on']).split(',').filter(Boolean) : undefined,
|
|
43
|
+
integration: o.integration === true, managed: o.managed === true, isolated: o['shared-directory'] !== true,
|
|
44
|
+
reviewerSessionIds: o.reviewers ? String(o.reviewers).split(',').filter(Boolean) : undefined } });
|
|
45
|
+
}
|
|
46
|
+
const options = o.options ? JSON.parse(String(o.options)) : undefined;
|
|
47
|
+
if (options !== undefined && (!Array.isArray(options) || options.some(v => typeof v !== 'string')))
|
|
48
|
+
throw new Error('--options must be a JSON array of strings');
|
|
49
|
+
return request('POST', `/tasks/${encodeURIComponent(command.target)}`, { input: {
|
|
50
|
+
kind: operation === 'plan' ? 'submit-plan' : operation, idempotencyKey, expectedRevision, content,
|
|
51
|
+
assigneeSessionId: o.assignee, attemptId: o.attempt, status: o.status, artifactId: o.artifact, options, verdict: o.verdict,
|
|
52
|
+
evidence: o.evidence ? JSON.parse(String(o.evidence)) : undefined,
|
|
53
|
+
} });
|
|
54
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { CollaborationError } from './collaborationProtocol.js';
|
|
3
|
+
import { assertPeerRegistrationAuthority } from './collaborationPeerTransport.js';
|
|
4
|
+
export function collaborationTaskRoutes(options) {
|
|
5
|
+
const router = Router();
|
|
6
|
+
const groupId = (value) => {
|
|
7
|
+
const resolved = options.store.resolveGroupId(value);
|
|
8
|
+
if (resolved.status !== 'ok')
|
|
9
|
+
throw new CollaborationError(resolved.status === 'ambiguous' ? 'GROUP_ID_AMBIGUOUS' : 'TASK_GROUP_NOT_FOUND', '请使用存在且唯一的协作组 ID', resolved.status === 'ambiguous' ? 409 : 404);
|
|
10
|
+
return resolved.id;
|
|
11
|
+
};
|
|
12
|
+
const context = (req) => {
|
|
13
|
+
const tasks = req.app.locals.collaborationTasks;
|
|
14
|
+
const peers = req.app.locals.collaborationService;
|
|
15
|
+
if (!tasks || !peers)
|
|
16
|
+
throw new CollaborationError('TASK_SERVICE_STARTING', '任务服务正在启动,请稍后重试', 503);
|
|
17
|
+
if (!options.agent) {
|
|
18
|
+
try {
|
|
19
|
+
assertPeerRegistrationAuthority(req);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new CollaborationError('TASK_PERMISSION_DENIED', '当前连接无权处理协作任务', 403);
|
|
23
|
+
}
|
|
24
|
+
return { tasks, peers, actor: null };
|
|
25
|
+
}
|
|
26
|
+
const sessionId = options.resolveSession((req.method === 'GET' ? req.query : req.body) ?? {});
|
|
27
|
+
if (!sessionId || sessionId.startsWith('remote:'))
|
|
28
|
+
throw new CollaborationError('SESSION_NOT_FOUND', '请在 Termdock 管理的本机会话内使用任务命令', 404);
|
|
29
|
+
return { tasks, peers, actor: peers.taskMember(sessionId) };
|
|
30
|
+
};
|
|
31
|
+
const run = (handler) => async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
res.json(await handler(req, context(req)));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
res.status(error instanceof CollaborationError ? error.httpStatus : 400).json({ ok: false,
|
|
37
|
+
code: error instanceof CollaborationError ? error.code : 'TASK_ERROR', error: error instanceof Error ? error.message : String(error) });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
router.get('/', run((req, { tasks, actor }) => {
|
|
41
|
+
const requested = typeof req.query.group === 'string' ? groupId(req.query.group) : null;
|
|
42
|
+
const groups = requested ? [requested] : actor ? options.store.groupsForSession(actor.sessionId).map(g => g.id) : options.store.list().map(g => g.id);
|
|
43
|
+
return { tasks: groups.flatMap(id => tasks.list(id, actor)) };
|
|
44
|
+
}));
|
|
45
|
+
router.get('/:taskId', run(async (req, { tasks, actor }) => ({ task: await tasks.get(req.params.taskId, actor) })));
|
|
46
|
+
const input = (req, peers) => {
|
|
47
|
+
const body = req.body?.input;
|
|
48
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
49
|
+
throw new CollaborationError('INVALID_TASK', '需要任务内容');
|
|
50
|
+
if (body.reviewerSessionIds !== undefined && (!Array.isArray(body.reviewerSessionIds) || body.reviewerSessionIds.length > 32 || body.reviewerSessionIds.some((v) => typeof v !== 'string')))
|
|
51
|
+
throw new CollaborationError('INVALID_REVIEWERS', '执行成员列表无效');
|
|
52
|
+
return { ...body, ...(body.reviewerSessionIds ? { reviewers: body.reviewerSessionIds.map((id) => peers.taskMember(id)) } : {}), ...(typeof body.groupId === 'string' ? { groupId: groupId(body.groupId) } : {}), ...(body.assigneeSessionId ? { assignee: peers.taskMember(String(body.assigneeSessionId)) } : {}),
|
|
53
|
+
...(body.coordinatorSessionId !== undefined ? { coordinator: body.coordinatorSessionId ? peers.taskMember(String(body.coordinatorSessionId)) : null } : {}) };
|
|
54
|
+
};
|
|
55
|
+
router.post('/', run(async (req, { tasks, peers, actor }) => ({ task: await tasks.create(input(req, peers), actor) })));
|
|
56
|
+
router.post('/:taskId', run(async (req, { tasks, peers, actor }) => ({ task: await tasks.apply(req.params.taskId, input(req, peers), actor) })));
|
|
57
|
+
return router;
|
|
58
|
+
}
|