termdock 1.4.306 → 1.4.308
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-BziVLy1b.js → App-ggIA_xqR.js} +7 -7
- package/dist/client/assets/App-ggIA_xqR.js.br +0 -0
- package/dist/client/assets/App-ggIA_xqR.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-CARNBEqQ.js → ArchitecturePanel-CoBspW_C.js} +1 -1
- package/dist/client/assets/ArchitecturePanel-CoBspW_C.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-CoBspW_C.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-00oa0z6w.js → ChangeWalkthroughPanel-D1Puc7B3.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-D1Puc7B3.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-D1Puc7B3.js.gz +0 -0
- package/dist/client/assets/{CollaborationMainWorkspace-DuEeKQKZ.js → CollaborationMainWorkspace-BPyK5Xs8.js} +1 -1
- package/dist/client/assets/CollaborationMainWorkspace-BPyK5Xs8.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-BPyK5Xs8.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-CTSJJqze.js +2 -0
- package/dist/client/assets/{ComputerControlView-C9v1Ooc9.js → ComputerControlView-D5Lw9sNA.js} +2 -2
- package/dist/client/assets/ComputerControlView-D5Lw9sNA.js.br +0 -0
- package/dist/client/assets/ComputerControlView-D5Lw9sNA.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-DfUpMALj.js → DagPlayground-DYJrGfiG.js} +1 -1
- package/dist/client/assets/DagPlayground-DYJrGfiG.js.br +0 -0
- package/dist/client/assets/DagPlayground-DYJrGfiG.js.gz +0 -0
- package/dist/client/assets/{DiffLab-Cf_URhQt.js → DiffLab-5zdcFW3z.js} +1 -1
- package/dist/client/assets/DiffLab-5zdcFW3z.js.br +0 -0
- package/dist/client/assets/DiffLab-5zdcFW3z.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DjG9vCpH.js → DiffReview-BBBC_NjV.js} +1 -1
- package/dist/client/assets/DiffReview-BBBC_NjV.js.br +0 -0
- package/dist/client/assets/DiffReview-BBBC_NjV.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-BKOvHdJY.js → DiffReviewLab-CbhosFSB.js} +1 -1
- package/dist/client/assets/DiffReviewLab-CbhosFSB.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CbhosFSB.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-6n3tgsdc.js → DiffViewer-BuQwFQ4V.js} +1 -1
- package/dist/client/assets/DiffViewer-BuQwFQ4V.js.br +0 -0
- package/dist/client/assets/DiffViewer-BuQwFQ4V.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-BNs2sRct.js → ModelPreview-nO2VmqdP.js} +1 -1
- package/dist/client/assets/ModelPreview-nO2VmqdP.js.br +0 -0
- package/dist/client/assets/ModelPreview-nO2VmqdP.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-CcMSU1v8.js → RightSidebar-BoNzpS2K.js} +3 -3
- package/dist/client/assets/RightSidebar-BoNzpS2K.js.br +0 -0
- package/dist/client/assets/RightSidebar-BoNzpS2K.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-DogjvRKp.js → abnfDiagram-VCTEODGH-yi0K8GDG.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-yi0K8GDG.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-yi0K8GDG.js.gz +0 -0
- package/dist/client/assets/{app-D6vN8PW-.js → app-B6FdOF6K.js} +3 -3
- package/dist/client/assets/app-B6FdOF6K.js.br +0 -0
- package/dist/client/assets/app-B6FdOF6K.js.gz +0 -0
- package/dist/client/assets/{arc-Cqel4Ted.js → arc-_nLI_-XZ.js} +1 -1
- package/dist/client/assets/arc-_nLI_-XZ.js.br +0 -0
- package/dist/client/assets/arc-_nLI_-XZ.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-DgvPtgNb.js → architectureDiagram-5GKGNRK7-CikrA78O.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CikrA78O.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CikrA78O.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-BxbWO4x4.js → blockDiagram-I7D4REHJ-CWJq6qJ7.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-CWJq6qJ7.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CWJq6qJ7.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-gsA37gjL.js → c4Diagram-7LVT6UL2-gzPzLGvs.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-gzPzLGvs.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-gzPzLGvs.js.gz +0 -0
- package/dist/client/assets/channel-BYsFmOmF.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-ChC9yYOd.js → chunk-2Q5K7J3B-CfX9l18E.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-Bi4Hc8yL.js → chunk-5VM5RSS4-JSV1yrXM.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-DvVWvQEk.js → chunk-F27PBJKO-CQ0LXeap.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-CQ0LXeap.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CQ0LXeap.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-BnwQLR5S.js → chunk-IMKFNOWR-CJOEPkK9.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-CJOEPkK9.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CJOEPkK9.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-BkNnaDiR.js → chunk-JWPE2WC7-Dpp7Xu_E.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-BRzm6Uzi.js → chunk-POPQ4Y6H-9hDa1b8z.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-CDYm-dzk.js → chunk-SVP7TREG-BskkG9gg.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-CDYm-dzk.js.br → chunk-SVP7TREG-BskkG9gg.js.br} +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BskkG9gg.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-BKaW9Z9i.js → chunk-TICWLB2K-DyzuP-9I.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-DyzuP-9I.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-DyzuP-9I.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DcHZ_FHb.js → chunk-XXDRQBXY-C31_1i6z.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-BnmZv6Ns.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BnmZv6Ns.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-DCbbTNc6.js → cose-bilkent-JH36ORCC-Bm-ESDOc.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-Bm-ESDOc.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-Bm-ESDOc.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-i23hD0Z2.js → cynefin-OW5HDTMX-DbFWAPvX.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-DbFWAPvX.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DbFWAPvX.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CbyLYcqc.js → cynefinDiagram-5FMLGOSQ-Ca0IKRdH.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Ca0IKRdH.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Ca0IKRdH.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-iJ4VKzZm.js → dagre-GXQ25YYZ-D_5uEMjJ.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-D_5uEMjJ.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-D_5uEMjJ.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-BNVZcdsO.js → diagram-S7CK7UJ4-DWVpndRP.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-DWVpndRP.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DWVpndRP.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-1ghTvPiu.js → diagram-UQ7AKVKN-DmYTya3w.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-DmYTya3w.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DmYTya3w.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-Ce_0nMd3.js → diagram-VSXAHHWV-BEA6kqNj.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-BEA6kqNj.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-BEA6kqNj.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-CLHEkhUt.js → diagram-VX7I27RA-CU9vP0P0.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-CU9vP0P0.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CU9vP0P0.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-iyb5DkP6.js → diagram-Z3DM3KII-B_GvE2g-.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-B_GvE2g-.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B_GvE2g-.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Dxh2TzXm.js → ebnfDiagram-PWID7BFC-BLrPQuLE.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-BLrPQuLE.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-BLrPQuLE.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-Cr8IkdCC.js → erDiagram-RLTQ6QDP-DlXgoyZ-.js} +1 -1
- package/dist/client/assets/{erDiagram-RLTQ6QDP-Cr8IkdCC.js.br → erDiagram-RLTQ6QDP-DlXgoyZ-.js.br} +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DlXgoyZ-.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-B8ZF1bwr.js → flowDiagram-HODETNUW-fPHWxEDZ.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-fPHWxEDZ.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-fPHWxEDZ.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-zhdL10eM.js → ganttDiagram-EL5Y4UJY-B8MOv6ug.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-B8MOv6ug.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-B8MOv6ug.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-CXYHfU__.js → gestureArbiter-JW8vcVRm.js} +1 -1
- package/dist/client/assets/gestureArbiter-JW8vcVRm.js.br +0 -0
- package/dist/client/assets/gestureArbiter-JW8vcVRm.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BQf2fHBo.js → gitGraphDiagram-WWUBYQGX-lH9gSoFx.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-lH9gSoFx.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-lH9gSoFx.js.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-BT8xey7S.js → infoDiagram-27XIBGKW-CSG29Ty_.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DunPdwW9.js → ishikawaDiagram-5VMMS53U-CcwSE5qV.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CcwSE5qV.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CcwSE5qV.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-B0y75iIg.js → journeyDiagram-3NMN7TZE-CXFUeP2c.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CXFUeP2c.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CXFUeP2c.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-BfgA5WLo.js → kanban-definition-UXKFOSKX-KEHwljd2.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-KEHwljd2.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-KEHwljd2.js.gz +0 -0
- package/dist/client/assets/{layout-BvjABLff.js → layout-DqYx0MnO.js} +1 -1
- package/dist/client/assets/layout-DqYx0MnO.js.br +0 -0
- package/dist/client/assets/layout-DqYx0MnO.js.gz +0 -0
- package/dist/client/assets/{linear-DgeFRliF.js → linear-BnG3XaJW.js} +1 -1
- package/dist/client/assets/linear-BnG3XaJW.js.br +0 -0
- package/dist/client/assets/linear-BnG3XaJW.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DM6Rlal9.js → mermaid.core-Ce00rdM6.js} +5 -5
- package/dist/client/assets/mermaid.core-Ce00rdM6.js.br +0 -0
- package/dist/client/assets/mermaid.core-Ce00rdM6.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-DhEiABv6.js → mindmap-definition-YA3MSWOX-D0hOW4SY.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-D0hOW4SY.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-D0hOW4SY.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-Dxv0I4wM.js → passwordBootstrap-Bncb8qF_.js} +1 -1
- package/dist/client/assets/passwordBootstrap-Bncb8qF_.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Bncb8qF_.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-LTlVaJfm.js → pegDiagram-XKGWAZYB-UKp9t91x.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-UKp9t91x.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-UKp9t91x.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-9bnryna3.js → pieDiagram-E7YTZNPT-Dif97wbH.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-Dif97wbH.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-Dif97wbH.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js → quadrantDiagram-AXDQQJYC-BPyHtH91.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.br → quadrantDiagram-AXDQQJYC-BPyHtH91.js.br} +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPyHtH91.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-DTtXvKOu.js → railroadDiagram-O6MQD6OU-Wleq9LmS.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Wleq9LmS.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Wleq9LmS.js.gz +0 -0
- package/dist/client/assets/{rdpSession-Ggo3N5s5.js → rdpSession-CobFMSUs.js} +1 -1
- package/dist/client/assets/rdpSession-CobFMSUs.js.br +0 -0
- package/dist/client/assets/rdpSession-CobFMSUs.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-Df8W2cyP.js → referenceLongPress-bZ0xp-v2.js} +1 -1
- package/dist/client/assets/referenceLongPress-bZ0xp-v2.js.br +0 -0
- package/dist/client/assets/referenceLongPress-bZ0xp-v2.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-BNia9zI0.js → requirementDiagram-BXWQKSXE-BL4pp0Ta.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BL4pp0Ta.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BL4pp0Ta.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-uvg5npfK.js → sankeyDiagram-P5KCCOFB-CV1cKx37.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CV1cKx37.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CV1cKx37.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-DpJNf2MD.js → sequenceDiagram-WJ2MYXX4-BF2InLwV.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BF2InLwV.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BF2InLwV.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CkWB2AnF.js → sizeCapture-INFHLROL-CldUyStR.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-CldUyStR.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CldUyStR.js.gz +0 -0
- package/dist/client/assets/{sparkles-DOuEtn62.js → sparkles-Cg-yPdE2.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-CeMzMQq-.js → stateDiagram-D77RDMKH-CByehbEd.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-CByehbEd.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CByehbEd.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CTcrJ-w0.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-Bo9GejWo.js → swimlanes-42K2YHIH--1_7YTL4.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH--1_7YTL4.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH--1_7YTL4.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-RSMV9AhO.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-cvWXYEZ4.js → timeline-definition-24CTP7MA-CXfXJFK6.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-CXfXJFK6.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-CXfXJFK6.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-DzV0gQXz.js → triangle-alert-CbMRJ6sx.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CzleWcmk.js → vennDiagram-4TSXK5OY-byr6UQpL.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-byr6UQpL.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-byr6UQpL.js.gz +0 -0
- package/dist/client/assets/{videoCompression-DCnzjEfU.js → videoCompression-ivJAy00d.js} +1 -1
- package/dist/client/assets/videoCompression-ivJAy00d.js.br +0 -0
- package/dist/client/assets/videoCompression-ivJAy00d.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-Cir1iutR.js → wardleyDiagram-VM6X3IG4-FJduk-7s.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-FJduk-7s.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-FJduk-7s.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-pNPcVJ1C.js → xychartDiagram-S5SC5T6Z-Ct1fBPFS.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Ct1fBPFS.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Ct1fBPFS.js.gz +0 -0
- package/dist/client/index.html +1 -1
- 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 +62 -16
- package/dist/server/agent/collaborationPrompt.js +3 -1
- package/dist/server/agent/collaborationProtocol.js +1 -1
- package/dist/server/agent/collaborationRoutes.js +8 -1
- package/dist/server/agent/collaborationStore.js +81 -11
- package/dist/server/agent/collaborationTaskCli.js +25 -7
- package/dist/server/agent/collaborationTaskPurpose.js +20 -0
- package/dist/server/agent/collaborationTaskRoutes.js +1 -1
- package/dist/server/agent/collaborationTaskService.js +15 -6
- package/dist/server/agent/collaborationTaskStore.js +35 -6
- package/dist/server/agent/integrationCli.js +15 -4
- package/dist/server/agent/integrationServer.js +92 -14
- package/dist/server/agent/integrationStore.js +1 -1
- package/dist/server/cli.js +1 -1
- package/docs/integrations.md +177 -5
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- 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.br +0 -0
- package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js.gz +0 -0
- 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.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-B_mzpNuw.js +0 -2
- 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-DfUpMALj.js.br +0 -0
- package/dist/client/assets/DagPlayground-DfUpMALj.js.gz +0 -0
- 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-DjG9vCpH.js.br +0 -0
- package/dist/client/assets/DiffReview-DjG9vCpH.js.gz +0 -0
- 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-6n3tgsdc.js.br +0 -0
- package/dist/client/assets/DiffViewer-6n3tgsdc.js.gz +0 -0
- 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.br +0 -0
- package/dist/client/assets/RightSidebar-CcMSU1v8.js.gz +0 -0
- 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.br +0 -0
- package/dist/client/assets/app-D6vN8PW-.js.gz +0 -0
- 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-DgvPtgNb.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DgvPtgNb.js.gz +0 -0
- 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-gsA37gjL.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-gsA37gjL.js.gz +0 -0
- package/dist/client/assets/channel-CBc8-n7y.js +0 -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-BnwQLR5S.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BnwQLR5S.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CDYm-dzk.js.gz +0 -0
- 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/classDiagram-ZZMXUADV-CNFc2dOc.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CNFc2dOc.js +0 -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-i23hD0Z2.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-i23hD0Z2.js.gz +0 -0
- 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-iJ4VKzZm.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-iJ4VKzZm.js.gz +0 -0
- 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-1ghTvPiu.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-1ghTvPiu.js.gz +0 -0
- 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-CLHEkhUt.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CLHEkhUt.js.gz +0 -0
- 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-Dxh2TzXm.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Dxh2TzXm.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Cr8IkdCC.js.gz +0 -0
- 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-zhdL10eM.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-zhdL10eM.js.gz +0 -0
- 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-BQf2fHBo.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BQf2fHBo.js.gz +0 -0
- 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-B0y75iIg.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B0y75iIg.js.gz +0 -0
- 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-BvjABLff.js.br +0 -0
- package/dist/client/assets/layout-BvjABLff.js.gz +0 -0
- 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-DM6Rlal9.js.br +0 -0
- package/dist/client/assets/mermaid.core-DM6Rlal9.js.gz +0 -0
- 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-Dxv0I4wM.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Dxv0I4wM.js.gz +0 -0
- 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-9bnryna3.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-9bnryna3.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.gz +0 -0
- 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.br +0 -0
- package/dist/client/assets/rdpSession-Ggo3N5s5.js.gz +0 -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-BNia9zI0.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BNia9zI0.js.gz +0 -0
- 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-DpJNf2MD.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DpJNf2MD.js.gz +0 -0
- 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/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 +0 -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 +0 -8
- 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/vennDiagram-4TSXK5OY-CzleWcmk.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CzleWcmk.js.gz +0 -0
- 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-Cir1iutR.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cir1iutR.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.js.gz +0 -0
|
@@ -2,6 +2,7 @@ import { randomBytes, createHash } from 'node:crypto';
|
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
4
|
import { collaborationResultPresentation } from './collaborationResultPresentation.js';
|
|
5
|
+
import { taskExecution, taskPurpose } from './collaborationTaskPurpose.js';
|
|
5
6
|
import { CollaborationError } from './collaborationProtocol.js';
|
|
6
7
|
import { taskMemberKey } from './collaborationTaskTypes.js';
|
|
7
8
|
const id = () => randomBytes(16).toString('hex');
|
|
@@ -50,6 +51,9 @@ function validateSnapshot(task) {
|
|
|
50
51
|
text(task.spec, '任务内容', 32_000, true);
|
|
51
52
|
text(task.constraints, '约束');
|
|
52
53
|
text(task.acceptance, '完成标准');
|
|
54
|
+
taskPurpose(task.purpose);
|
|
55
|
+
if (task.purpose === 'automation' && (task.workflow || task.parentTaskId || task.dependsOn.length || task.coordinator))
|
|
56
|
+
invalid();
|
|
53
57
|
member({ serviceId: task.ownerServiceId, sessionId: 'validation' });
|
|
54
58
|
if (task.coordinator !== null)
|
|
55
59
|
member(task.coordinator);
|
|
@@ -83,6 +87,8 @@ function validateSnapshot(task) {
|
|
|
83
87
|
invalid();
|
|
84
88
|
if (event.deliveryId !== undefined && !validId(event.deliveryId))
|
|
85
89
|
invalid();
|
|
90
|
+
if (event.purpose !== undefined)
|
|
91
|
+
taskPurpose(event.purpose);
|
|
86
92
|
if (event.source !== undefined && !['system', 'user', 'integration'].includes(event.source))
|
|
87
93
|
invalid();
|
|
88
94
|
if (event.actor !== null)
|
|
@@ -183,7 +189,7 @@ export class CollaborationTaskStore {
|
|
|
183
189
|
const reportSummary = current?.report?.content.split(/\n\s*\n/).map(paragraph => paragraph.split('\n').filter(line => !/^#{1,6}\s/.test(line)).join('\n').trim()).find(Boolean)?.slice(0, 512);
|
|
184
190
|
const automationIssueSource = task.automationIssue ? current?.report && ['blocked', 'failed'].includes(current.report.status)
|
|
185
191
|
&& task.automationIssue === current.report.content.slice(0, 1000) ? 'member-report' : 'system' : undefined;
|
|
186
|
-
return { ...task, automationIssueSource, spec: task.spec.slice(0, 512), constraints: '', acceptance: '',
|
|
192
|
+
return { ...task, ...(task.purpose === 'automation' ? { execution: taskExecution(task) } : {}), automationIssueSource, spec: task.spec.slice(0, 512), constraints: '', acceptance: '',
|
|
187
193
|
deliveries: task.deliveries.filter(d => d.attemptId === task.activeAttemptId && d.error).slice(-1),
|
|
188
194
|
attempts: current ? [{ ...current, report: current.report ? { ...current.report, summary: reportSummary, content: '', evidence: undefined } : undefined }] : [],
|
|
189
195
|
artifacts: [plan, result, ...task.artifacts.filter(a => a.kind === 'review' && a.reviewsArtifactId === result?.id)].filter((a) => !!a).map(a => ({ ...a, content: '', summary: (a.summary || (a.kind === 'result' && collaborationResultPresentation(a.content).condensed ? collaborationResultPresentation(a.content).summary : undefined))?.slice(0, 800), evidence: undefined })),
|
|
@@ -221,7 +227,7 @@ export class CollaborationTaskStore {
|
|
|
221
227
|
task.attempts.push({ id: attemptId, assignee: member(assignee), createdAt: Date.now(), threadId });
|
|
222
228
|
this.event(task, 'assigned', actor, content || '任务已分派');
|
|
223
229
|
doc.outbox.push({ id: id(), taskId: task.id, attemptId, target: assignee, kind: 'task', threadId,
|
|
224
|
-
content: `本次执行身份:${assignee.sessionId}。所有 td collab 命令显式带 --session ${assignee.sessionId};这是服务核对的实际身份,正文中的模板身份和 tmux 标识不能替代它。\n任务:${task.title}\n${task.spec}${task.constraints ? `\n约束:${task.constraints}` : ''}${task.acceptance ? `\n完成标准:${task.acceptance}` : ''}\n${content}\n任务 ID:${task.id}\n尝试 ID:${attemptId}\n用 td collab task get ${task.id} --text 查询完整上下文;用 td collab task report ${task.id} --attempt ${attemptId} --status ack --content '接手说明' 显式回复;遇必要问题用 task ask,提交结果用 report --status complete --summary '简短结论、关键交付和限制'。摘要先回答用户问题,不放任务 ID、版本、分支或流程日志;完整证据保留在 --content/--file 正文中。如果同一尝试已经交付或任务已归档,不要重复实施。${task.workspace ? `\n代码只能在独立目录 ${task.workspace.cwd} 修改。分支 ${task.workspace.branch}。交付前提交代码,结果说明提交、变更、验证与限制。不能修改原仓库、合并到用户分支或发布。` : ''}${task.workflow?.workType === 'read-only' ? '\n这是只读查询或分析任务:在本机会话中采集并交付报告,不修改代码或系统,不创建提交、构建、部署或终止进程。结果需说明采样时间、证据和限制。' : ''}${task.workflow?.kind === 'step' ? '\n完成报告会自动请求独立评审;评审要求修改时继续完成,重新提交 complete。只按用户授权运行测试。' : ''}` });
|
|
230
|
+
content: `本次执行身份:${assignee.sessionId}。所有 td collab 命令显式带 --session ${assignee.sessionId};这是服务核对的实际身份,正文中的模板身份和 tmux 标识不能替代它。\n任务:${task.title}\n${task.spec}${task.constraints ? `\n约束:${task.constraints}` : ''}${task.acceptance ? `\n完成标准:${task.acceptance}` : ''}\n${content}\n任务 ID:${task.id}\n尝试 ID:${attemptId}\n用 td collab task get ${task.id} --text 查询完整上下文;用 td collab task report ${task.id} --attempt ${attemptId} --status ack --content '接手说明' 显式回复;遇必要问题用 task ask,提交结果用 report --status complete --summary '简短结论、关键交付和限制'。摘要先回答用户问题,不放任务 ID、版本、分支或流程日志;完整证据保留在 --content/--file 正文中。如果同一尝试已经交付或任务已归档,不要重复实施。${task.purpose === 'automation' ? '\n这是独立后台自动化执行记录:complete 是你明确提交的执行结果,无需等待用户 accepted。机械校验和外部发布由接入系统处理;纯咨询用 respond 关联原 comment,不重复提交 complete。必要问题用 ask 保留原文,由接入系统联系用户并回答。' : ''}${task.workspace ? `\n代码只能在独立目录 ${task.workspace.cwd} 修改。分支 ${task.workspace.branch}。交付前提交代码,结果说明提交、变更、验证与限制。不能修改原仓库、合并到用户分支或发布。` : ''}${task.workflow?.workType === 'read-only' ? '\n这是只读查询或分析任务:在本机会话中采集并交付报告,不修改代码或系统,不创建提交、构建、部署或终止进程。结果需说明采样时间、证据和限制。' : ''}${task.workflow?.kind === 'step' ? '\n完成报告会自动请求独立评审;评审要求修改时继续完成,重新提交 complete。只按用户授权运行测试。' : ''}` });
|
|
225
231
|
}
|
|
226
232
|
goalInstructions(task) {
|
|
227
233
|
return `${this.baseGoalInstructions(task)}\n启动 Agent 前,读取 task get 返回的 launchProfiles、defaultLaunchProfileId 和 roster.launchProfile。根据用户填写的 notes 判断适用任务;这些是选用建议,不是能力或性能保证。需要另一种模型或参数时,用 td collab spawn ${task.groupId} <agentSlug> --launch-profile <方案id> --cwd <项目目录> --session ${task.coordinator?.sessionId} 创建对应执行成员,再把子任务分派给它。已有成员及其代码执行会话保留创建时的启动方案,不因默认方案变更而更换模型。`;
|
|
@@ -248,6 +254,9 @@ export class CollaborationTaskStore {
|
|
|
248
254
|
content: `你被指定为任务「${task.title}」的协调者。\n目标:${task.spec}\n约束:${task.constraints || '未补充'}\n验收标准:${task.acceptance || '由用户决定'}\n任务 ID:${task.id}\n用 td collab task get ${task.id} --text 查看原始记录;用 task list --group ${task.groupId} 查看工作组。需要拆分时用 task create --group ${task.groupId} --parent ${task.id} --title '子任务标题' --content '任务内容'。分派前查询 revision,再用 task assign --revision;把必要的人类决策交给 task ask,不推断成员忙闲,不停止其他成员终端。` });
|
|
249
255
|
}
|
|
250
256
|
create(owner, input, actor, origin) {
|
|
257
|
+
const purpose = taskPurpose(input.purpose);
|
|
258
|
+
if (purpose === 'automation' && (input.managed || input.parentTaskId || input.dependsOn?.length || input.coordinator || input.reviewers?.length || input.integration))
|
|
259
|
+
throw new CollaborationError('AUTOMATION_STANDALONE_REQUIRED', '后台自动化记录不加入人工目标、依赖或评审流程');
|
|
251
260
|
const title = text(input.title, '标题', 640, true), spec = text(input.spec, '任务内容', 32_000, true);
|
|
252
261
|
const constraints = text(input.constraints, '约束'), acceptance = text(input.acceptance, '完成标准');
|
|
253
262
|
if (input.dependsOn !== undefined && (!Array.isArray(input.dependsOn) || input.dependsOn.length > 32 || input.dependsOn.some(v => typeof v !== 'string')))
|
|
@@ -276,6 +285,8 @@ export class CollaborationTaskStore {
|
|
|
276
285
|
for (const dependency of [...dependsOn, ...(input.parentTaskId ? [input.parentTaskId] : [])]) {
|
|
277
286
|
if (!doc.tasks.some(t => t.id === dependency && t.groupId === input.groupId))
|
|
278
287
|
throw new CollaborationError('TASK_DEPENDENCY_NOT_FOUND', '父任务或依赖任务不在当前协作组', 404);
|
|
288
|
+
if (doc.tasks.find(t => t.id === dependency)?.purpose === 'automation')
|
|
289
|
+
throw new CollaborationError('AUTOMATION_STANDALONE_REQUIRED', '后台自动化记录不能作为人工任务父级或验收依赖');
|
|
279
290
|
}
|
|
280
291
|
const now = Date.now();
|
|
281
292
|
const parent = doc.tasks.find(t => t.id === input.parentTaskId);
|
|
@@ -307,11 +318,11 @@ export class CollaborationTaskStore {
|
|
|
307
318
|
if (!required.length || required.some(t => !dependsOn.includes(t.id)))
|
|
308
319
|
throw new CollaborationError('INTEGRATION_DEPENDENCIES_REQUIRED', '集成任务必须依赖目标下全部实施子任务');
|
|
309
320
|
}
|
|
310
|
-
const task = { id: id(), ownerServiceId: owner, groupId: input.groupId, title, spec, constraints, acceptance,
|
|
321
|
+
const task = { id: id(), ownerServiceId: owner, groupId: input.groupId, title, spec, constraints, acceptance, purpose,
|
|
311
322
|
coordinator: parent?.workflow ? parent.coordinator : input.coordinator !== undefined ? input.coordinator : input.parentTaskId ? doc.tasks.find(t => t.id === input.parentTaskId)?.coordinator ?? actor : null,
|
|
312
323
|
parentTaskId: input.parentTaskId ?? null, dependsOn, createdAt: now, updatedAt: now, revision: 1,
|
|
313
324
|
...(origin ? { origin: structuredClone(origin) } : {}), status: 'open', activeAttemptId: null, attempts: [], decisions: [], artifacts: [], events: [], deliveries: [], ...(workflow ? { workflow } : {}) };
|
|
314
|
-
this.event(task, 'created', actor, spec);
|
|
325
|
+
this.event(task, 'created', actor, spec).purpose = purpose;
|
|
315
326
|
if (parent?.constraints)
|
|
316
327
|
task.constraints = text([parent.constraints, constraints].filter(Boolean).join('\n'), '继承约束');
|
|
317
328
|
if (workflow?.kind === 'goal') {
|
|
@@ -335,6 +346,12 @@ export class CollaborationTaskStore {
|
|
|
335
346
|
}, origin);
|
|
336
347
|
}
|
|
337
348
|
apply(taskId, input, actor, origin) {
|
|
349
|
+
if (input.purpose !== undefined && input.kind !== 'configure')
|
|
350
|
+
throw new CollaborationError('INVALID_TASK_PURPOSE', 'purpose can only be changed through configure');
|
|
351
|
+
if (input.kind === 'configure' && input.purpose === undefined)
|
|
352
|
+
throw new CollaborationError('INVALID_TASK_PURPOSE', 'configure requires purpose');
|
|
353
|
+
if (input.kind === 'configure')
|
|
354
|
+
taskPurpose(input.purpose);
|
|
338
355
|
const content = text(input.content, '内容');
|
|
339
356
|
const summary = text(input.summary, '结果摘要', 2400);
|
|
340
357
|
if (summary && (input.kind !== 'report' || input.status !== 'complete'))
|
|
@@ -353,6 +370,8 @@ export class CollaborationTaskStore {
|
|
|
353
370
|
if (origin && ['accept', 'approve-plan', 'report', 'ask', 'submit-plan', 'review', 'respond'].includes(input.kind))
|
|
354
371
|
throw new CollaborationError('INTEGRATION_OPERATION_DENIED', '此操作需要用户或原执行成员身份', 403);
|
|
355
372
|
const coordination = actor === null || sameMember(actor, task.coordinator);
|
|
373
|
+
if (input.kind === 'configure' && actor !== null)
|
|
374
|
+
throw new CollaborationError('USER_DECISION_REQUIRED', '用途配置需要用户管理身份或授权的集成身份', 403);
|
|
356
375
|
if (['assign', 'coordinator', 'close', 'reopen', 'revise', 'request-review', 'coordinate', 'pause', 'resume', 'retry'].includes(input.kind) && !coordination)
|
|
357
376
|
throw new CollaborationError('TASK_PERMISSION_DENIED', '此操作需要用户或当前协调者', 403);
|
|
358
377
|
if (['answer', 'accept', 'approve-plan'].includes(input.kind) && actor !== null)
|
|
@@ -360,7 +379,7 @@ export class CollaborationTaskStore {
|
|
|
360
379
|
if (!['report', 'ask', 'submit-plan', 'review', 'comment', 'respond', 'answer'].includes(input.kind) && input.expectedRevision !== task.revision)
|
|
361
380
|
throw new CollaborationError('TASK_CHANGED', '任务已更新,请查看最新记录后重试', 409);
|
|
362
381
|
const userFollowup = actor === null && input.kind === 'revise' && !!content;
|
|
363
|
-
if (task.status !== 'open' && !['reopen', 'report'].includes(input.kind) && !(task.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
|
|
382
|
+
if (task.status !== 'open' && !['configure', 'reopen', 'report'].includes(input.kind) && !(task.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
|
|
364
383
|
throw new CollaborationError('TASK_ARCHIVED', '任务已归档;需要继续时请重新打开', 409);
|
|
365
384
|
if (task.workflow && task.status !== 'open' && input.kind !== 'reopen' && !(task.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
|
|
366
385
|
throw new CollaborationError('TASK_ARCHIVED', '自动协作的已完成版本不能追加执行报告,请先重新打开', 409);
|
|
@@ -390,7 +409,15 @@ export class CollaborationTaskStore {
|
|
|
390
409
|
throw new CollaborationError('ATTEMPT_SUPERSEDED', '这轮分派已被替换,不能再请求用户决定', 409);
|
|
391
410
|
if (task.workflow && ['report', 'ask', 'submit-plan'].includes(input.kind) && attempt?.id !== task.activeAttemptId)
|
|
392
411
|
throw new CollaborationError('ATTEMPT_SUPERSEDED', '自动协作只能推进当前分派', 409);
|
|
393
|
-
if (input.kind === '
|
|
412
|
+
if (input.kind === 'configure') {
|
|
413
|
+
const purpose = taskPurpose(input.purpose);
|
|
414
|
+
if (purpose === 'automation' && (task.workflow || task.parentTaskId || task.dependsOn.length || task.coordinator
|
|
415
|
+
|| doc.tasks.some(t => t.parentTaskId === task.id || t.workflow?.rootTaskId === task.id || t.dependsOn.includes(task.id))))
|
|
416
|
+
throw new CollaborationError('AUTOMATION_STANDALONE_REQUIRED', '只能把独立记录改为后台自动化用途');
|
|
417
|
+
task.purpose = purpose;
|
|
418
|
+
this.event(task, 'configured', actor, content || `任务用途已配置为 ${purpose}`).purpose = purpose;
|
|
419
|
+
}
|
|
420
|
+
else if (input.kind === 'assign') {
|
|
394
421
|
if (task.workflow?.kind === 'goal' && !sameMember(input.assignee ?? null, task.coordinator))
|
|
395
422
|
throw new CollaborationError('GOAL_COORDINATOR_REQUIRED', '目标由协调者负责,请在子任务中分派实施');
|
|
396
423
|
if (task.dependsOn.some(dep => doc.tasks.find(t => t.id === dep)?.status !== 'accepted'))
|
|
@@ -407,6 +434,8 @@ export class CollaborationTaskStore {
|
|
|
407
434
|
this.notifyCoordinator(doc, task);
|
|
408
435
|
}
|
|
409
436
|
else if (input.kind === 'coordinator') {
|
|
437
|
+
if (task.purpose === 'automation' && input.coordinator)
|
|
438
|
+
throw new CollaborationError('AUTOMATION_STANDALONE_REQUIRED', '后台自动化记录不加入人工协调流程');
|
|
410
439
|
if (task.workflow && !input.coordinator)
|
|
411
440
|
throw new CollaborationError('GOAL_COORDINATOR_REQUIRED', '自动协作需要协调者');
|
|
412
441
|
const previousCoordinator = task.coordinator;
|
|
@@ -4,7 +4,7 @@ import http from 'node:http';
|
|
|
4
4
|
import { INTEGRATION_PROTOCOL } from './integrationStore.js';
|
|
5
5
|
import { integrationSocketPath } from './integrationServer.js';
|
|
6
6
|
import { CollaborationError } from './collaborationProtocol.js';
|
|
7
|
-
import { executeCollaborationCommand, duration } from './collaborationCli.js';
|
|
7
|
+
import { COLLAB_HELP, executeCollaborationCommand, duration } from './collaborationCli.js';
|
|
8
8
|
import { getTermdockVersion } from '../utils/version.js';
|
|
9
9
|
export const INTEGRATION_HELP = `td integration — local scoped integration administration
|
|
10
10
|
groups | list
|
|
@@ -14,6 +14,9 @@ export const INTEGRATION_HELP = `td integration — local scoped integration adm
|
|
|
14
14
|
revoke <principal-id>
|
|
15
15
|
Credentials are saved as a private file and never printed. Workers set
|
|
16
16
|
TERMDOCK_INTEGRATION_CREDENTIAL_FILE, then use td collab --principal <id> …
|
|
17
|
+
Ordinary messages: permissions message.send, message.read, events.read;
|
|
18
|
+
td collab --principal <id> --help lists send/reply/history and event examples.
|
|
19
|
+
No task or user acceptance is required for a message-driven integration.
|
|
17
20
|
Only the local administrator can provision/revoke grants. See docs/integrations.md.`;
|
|
18
21
|
export function readIntegrationCredential(file, principalId) {
|
|
19
22
|
const info = fs.lstatSync(file);
|
|
@@ -55,7 +58,7 @@ export async function runIntegrationAdmin(argv, port, adminToken, write) {
|
|
|
55
58
|
let reserved;
|
|
56
59
|
try {
|
|
57
60
|
const action = argv[0] ?? 'help', options = {};
|
|
58
|
-
if (action === 'help' ||
|
|
61
|
+
if (action === 'help' || argv.includes('--help')) {
|
|
59
62
|
write(INTEGRATION_HELP);
|
|
60
63
|
return 0;
|
|
61
64
|
}
|
|
@@ -131,6 +134,10 @@ export async function revokeIntegration(id, port, adminToken, write) {
|
|
|
131
134
|
}
|
|
132
135
|
export async function runIntegrationCollab(command, port, io) {
|
|
133
136
|
try {
|
|
137
|
+
if (command.action === 'help') {
|
|
138
|
+
io.write(COLLAB_HELP);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
134
141
|
const principalId = String(command.options.principal), file = process.env.TERMDOCK_INTEGRATION_CREDENTIAL_FILE;
|
|
135
142
|
if (!file)
|
|
136
143
|
throw new CollaborationError('INTEGRATION_CREDENTIAL_REQUIRED', 'Set TERMDOCK_INTEGRATION_CREDENTIAL_FILE to a private credential file', 401);
|
|
@@ -160,8 +167,12 @@ export async function runIntegrationCollab(command, port, io) {
|
|
|
160
167
|
io.write(JSON.stringify(parsed(await request(socketPath, command.operation === 'get' ? 'GET' : 'POST', route, body, headers(credential)))));
|
|
161
168
|
return 0;
|
|
162
169
|
}
|
|
163
|
-
|
|
164
|
-
|
|
170
|
+
const messageCapability = command.action === 'send' ? 'integration_message_send' : command.action === 'reply' ? 'integration_message_reply'
|
|
171
|
+
: command.action === 'message' && command.operation === 'list' ? 'integration_message_history' : null;
|
|
172
|
+
if (messageCapability && capability[messageCapability] !== true)
|
|
173
|
+
throw new CollaborationError('INTEGRATION_MESSAGING_UNSUPPORTED', 'CLI and running service must support integration messaging (minimum 1.4.308); upgrade both and read capabilities', 409);
|
|
174
|
+
if (!['task', 'message', 'send', 'reply'].includes(command.action) || command.action === 'message' && !['get', 'list'].includes(command.operation))
|
|
175
|
+
throw new CollaborationError('INTEGRATION_OPERATION_DENIED', 'Command is not exposed to integration identities; see td collab --principal <id> --help', 403);
|
|
165
176
|
return executeCollaborationCommand(command, {}, { ...io, request: async (method, endpoint, body, timeout) => {
|
|
166
177
|
const origin = { source: command.options.source, externalActor: command.options['external-actor'] ? JSON.parse(String(command.options['external-actor'])) : undefined,
|
|
167
178
|
externalMessageId: command.options['external-message-id'], metadata: command.options.metadata ? JSON.parse(String(command.options.metadata)) : undefined };
|
|
@@ -4,12 +4,20 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import { timingSafeEqual } from 'node:crypto';
|
|
7
|
-
import { CollaborationError } from './collaborationProtocol.js';
|
|
7
|
+
import { CollaborationError, resolveIdPrefix } from './collaborationProtocol.js';
|
|
8
8
|
import { terminalMessage } from './collaborationStore.js';
|
|
9
|
-
import { IntegrationStore, INTEGRATION_PROTOCOL, integrationError } from './integrationStore.js';
|
|
9
|
+
import { IntegrationStore, INTEGRATION_PROTOCOL, INTEGRATION_OPERATIONS, integrationError } from './integrationStore.js';
|
|
10
10
|
import { IntegrationSessions, publicIntegrationSession } from './integrationSessions.js';
|
|
11
11
|
import { getTermdockVersion } from '../utils/version.js';
|
|
12
12
|
export function integrationSocketPath(port) { return path.join(homedir(), '.termdock', `integration-${port}.sock`); }
|
|
13
|
+
function scopedId(input, ids, type) {
|
|
14
|
+
if (typeof input !== 'string')
|
|
15
|
+
integrationError(`INVALID_${type}_ID`, 'A message or member id is required');
|
|
16
|
+
const result = resolveIdPrefix([...new Set(ids)], input);
|
|
17
|
+
if (result.status !== 'ok')
|
|
18
|
+
integrationError(`${type}_${result.status === 'ambiguous' ? 'ID_AMBIGUOUS' : 'NOT_FOUND'}`, `No unique ${type.toLowerCase()} in this integration group`, result.status === 'ambiguous' ? 409 : 404);
|
|
19
|
+
return result.id;
|
|
20
|
+
}
|
|
13
21
|
/** A local authenticated API and push stream. It is never mounted on the
|
|
14
22
|
* public HTTP application and does not reuse an integration's admin token. */
|
|
15
23
|
export class IntegrationRuntime {
|
|
@@ -35,7 +43,7 @@ export class IntegrationRuntime {
|
|
|
35
43
|
} };
|
|
36
44
|
this.stops.push(options.messages.subscribe(changed), options.taskStore.subscribe(changed), this.sessions.subscribe(changed));
|
|
37
45
|
const app = express();
|
|
38
|
-
app.use(express.json({ limit: '
|
|
46
|
+
app.use(express.json({ limit: '2mb' }));
|
|
39
47
|
app.use((req, res, next) => {
|
|
40
48
|
if (req.headers['x-termdock-integration-protocol'] !== String(INTEGRATION_PROTOCOL)) {
|
|
41
49
|
res.status(409).json({ ...this.error(new CollaborationError('INCOMPATIBLE_INTEGRATION_PROTOCOL', 'Unsupported integration protocol', 409)), protocol: INTEGRATION_PROTOCOL });
|
|
@@ -73,7 +81,7 @@ export class IntegrationRuntime {
|
|
|
73
81
|
integrationError('INVALID_INTEGRATION_POLICY', 'Policy identity must match the requested identity'); this.group(req.body?.groupId); this.store.update(req.body); return { ok: true, id: req.params.id }; }));
|
|
74
82
|
app.post('/admin/principals/:id/revoke', run(req => { admin(req); this.store.revoke(req.params.id); return { ok: true }; }));
|
|
75
83
|
app.get('/capabilities', run(req => { const p = principal(req); return { ...this.capabilities(), principal: { id: p.id, group_id: p.groupId, permissions: p.permissions, launch_profiles: p.launchProfiles.map(profile => ({ id: profile.id, agent_slug: profile.agentSlug, cwd_roots: profile.cwdRoots, startup_input_condition: !!profile.startupInput })) } }; }));
|
|
76
|
-
app.get('/tasks', run(req => { const p = principal(req); this.authorize(p, 'task.read', req.query.group); return { tasks: options.tasks.list(p.groupId, null) }; }));
|
|
84
|
+
app.get('/tasks', run(req => { const p = principal(req); this.authorize(p, 'task.read', req.query.group); return { tasks: options.tasks.list(p.groupId, null, req.query.purpose) }; }));
|
|
77
85
|
app.get('/tasks/:id', run(async (req) => { const p = principal(req); this.taskPermission(p, req.params.id, 'task.read'); return { task: await options.tasks.get(req.params.id, null) }; }));
|
|
78
86
|
app.post('/tasks', run(async (req) => {
|
|
79
87
|
const p = principal(req), raw = req.body?.input ?? {};
|
|
@@ -81,7 +89,7 @@ export class IntegrationRuntime {
|
|
|
81
89
|
if (raw.managed || raw.parentTaskId || raw.dependsOn?.length || raw.coordinatorSessionId || raw.reviewerSessionIds?.length || raw.integration)
|
|
82
90
|
integrationError('INTEGRATION_OPERATION_DENIED', 'Integration creates ordinary standalone tasks only', 403);
|
|
83
91
|
const input = { idempotencyKey: raw.idempotencyKey, groupId: p.groupId, title: raw.title, spec: raw.spec,
|
|
84
|
-
constraints: raw.constraints, acceptance: raw.acceptance, assignee: raw.assigneeSessionId ? options.peers.taskMember(String(raw.assigneeSessionId)) : undefined };
|
|
92
|
+
purpose: raw.purpose, constraints: raw.constraints, acceptance: raw.acceptance, assignee: raw.assigneeSessionId ? options.peers.taskMember(String(raw.assigneeSessionId)) : undefined };
|
|
85
93
|
if (input.assignee)
|
|
86
94
|
this.authorize(p, 'task.assign');
|
|
87
95
|
const task = await options.tasks.create(input, null, this.origin(p, req.body?.origin));
|
|
@@ -90,24 +98,75 @@ export class IntegrationRuntime {
|
|
|
90
98
|
}));
|
|
91
99
|
app.post('/tasks/:id', run(async (req) => {
|
|
92
100
|
const p = principal(req), raw = req.body?.input ?? {};
|
|
93
|
-
const permissions = { assign: 'task.assign', comment: 'task.comment', revise: 'task.revise', answer: 'task.answer' };
|
|
101
|
+
const permissions = { configure: 'task.configure', assign: 'task.assign', comment: 'task.comment', revise: 'task.revise', answer: 'task.answer' };
|
|
94
102
|
const permission = permissions[raw.kind];
|
|
95
103
|
if (!permission)
|
|
96
104
|
integrationError('INTEGRATION_OPERATION_DENIED', 'Operation requires a user or terminal member', 403);
|
|
97
105
|
this.taskPermission(p, req.params.id, permission);
|
|
98
106
|
const input = { kind: raw.kind, idempotencyKey: raw.idempotencyKey, content: raw.content,
|
|
99
|
-
expectedRevision: raw.expectedRevision, decisionId: raw.decisionId,
|
|
107
|
+
purpose: raw.purpose, expectedRevision: raw.expectedRevision, decisionId: raw.decisionId,
|
|
100
108
|
assignee: raw.assigneeSessionId ? options.peers.taskMember(String(raw.assigneeSessionId)) : undefined };
|
|
101
109
|
const task = await options.tasks.apply(req.params.id, input, null, this.origin(p, req.body?.origin));
|
|
102
110
|
this.sync();
|
|
103
111
|
const event = options.taskStore.integrationRequestEvent(p.id, input.idempotencyKey, task.id);
|
|
104
112
|
return { task, event_id: event?.id ?? null, attempt_id: event?.attemptId ?? null, delivery_id: event?.deliveryId ?? null };
|
|
105
113
|
}));
|
|
114
|
+
app.post('/send', run(req => {
|
|
115
|
+
const p = principal(req);
|
|
116
|
+
this.authorize(p, 'message.send', req.body?.group_id);
|
|
117
|
+
const group = this.group(p.groupId), raw = req.body ?? {};
|
|
118
|
+
if (raw.kind && raw.kind !== 'message')
|
|
119
|
+
integrationError('INTEGRATION_OPERATION_DENIED', 'Integration send uses ordinary messages only', 403);
|
|
120
|
+
const targets = Array.isArray(raw.toSessionIds) ? raw.toSessionIds : [raw.targetSessionId];
|
|
121
|
+
if (!targets.length || targets.some((id) => typeof id !== 'string'))
|
|
122
|
+
integrationError('INVALID_MESSAGE_TARGET', 'Specify a local group member');
|
|
123
|
+
const recipients = targets.map((id) => scopedId(id, group.sessionIds, 'SESSION'));
|
|
124
|
+
let thread;
|
|
125
|
+
if (raw.thread_id)
|
|
126
|
+
thread = scopedId(raw.thread_id, options.messages.snapshotMessages().filter(m => m.groupId === p.groupId).map(m => m.threadId), 'THREAD');
|
|
127
|
+
const messages = options.messages.send({ ...this.messageExtras(raw), groupId: p.groupId, fromSessionId: null,
|
|
128
|
+
integrationOrigin: this.origin(p, raw.origin), toSessionIds: recipients, kind: 'message', content: raw.message, threadId: thread });
|
|
129
|
+
this.sync();
|
|
130
|
+
return { ok: true, message_ids: messages.map(m => m.id), receipts: messages.map(m => options.messages.receipt(m.id)), ...options.messages.receipt(messages[0].id) };
|
|
131
|
+
}));
|
|
132
|
+
app.post('/reply', run(req => {
|
|
133
|
+
const p = principal(req);
|
|
134
|
+
this.authorize(p, 'message.send', req.body?.group_id);
|
|
135
|
+
const raw = req.body ?? {}, original = this.message(p, raw.messageId);
|
|
136
|
+
const target = original.toPrincipalId === p.id ? original.fromSessionId
|
|
137
|
+
: original.integrationOrigin?.integrationId === p.id ? original.toSessionId : null;
|
|
138
|
+
if (!target || !this.group(p.groupId).sessionIds.includes(target))
|
|
139
|
+
integrationError('NO_REPLY_TARGET', 'Reply requires your own message and its original live group member', 409);
|
|
140
|
+
const messages = options.messages.send({ ...this.messageExtras(raw), groupId: p.groupId, fromSessionId: null,
|
|
141
|
+
integrationOrigin: this.origin(p, raw.origin), toSessionIds: [target], kind: 'reply', content: raw.content, threadId: original.threadId, replyTo: original.id });
|
|
142
|
+
this.sync();
|
|
143
|
+
return { ok: true, ...options.messages.receipt(messages[0].id) };
|
|
144
|
+
}));
|
|
145
|
+
app.get('/message', run(req => {
|
|
146
|
+
const p = principal(req);
|
|
147
|
+
this.authorize(p, 'message.read', req.query.group);
|
|
148
|
+
const messages = options.messages.snapshotMessages().filter(m => m.groupId === p.groupId).sort((a, b) => a.sequence - b.sequence);
|
|
149
|
+
const after = req.query['after-id'] ? this.message(p, String(req.query['after-id'])) : null;
|
|
150
|
+
const limit = req.query.limit === undefined ? 50 : Number(req.query.limit);
|
|
151
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 200)
|
|
152
|
+
integrationError('INVALID_MESSAGE_LIMIT', 'limit must be 1..200');
|
|
153
|
+
const thread = req.query.thread ? scopedId(String(req.query.thread), messages.map(m => m.threadId), 'THREAD') : null;
|
|
154
|
+
const filtered = messages.filter(m => (!after || m.sequence > after.sequence) && (!thread || m.threadId === thread));
|
|
155
|
+
const page = [];
|
|
156
|
+
let bytes = 0;
|
|
157
|
+
for (const message of filtered.slice(0, limit)) {
|
|
158
|
+
const size = Buffer.byteLength(JSON.stringify(message));
|
|
159
|
+
if (page.length && bytes + size > 2 * 1024 * 1024)
|
|
160
|
+
break;
|
|
161
|
+
page.push(message);
|
|
162
|
+
bytes += size;
|
|
163
|
+
}
|
|
164
|
+
return { messages: page.map(m => terminalMessage(m)), next_after_id: page.at(-1)?.id ?? after?.id ?? null, has_more: filtered.length > page.length, retention: 'retained_messages_only' };
|
|
165
|
+
}));
|
|
106
166
|
app.get('/message/:id', run(req => {
|
|
107
|
-
const p = principal(req)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.authorize(p, 'task.read', message.groupId);
|
|
167
|
+
const p = principal(req);
|
|
168
|
+
this.authorize(p, p.permissions.includes('message.read') ? 'message.read' : 'task.read');
|
|
169
|
+
const message = this.message(p, req.params.id);
|
|
111
170
|
const receipt = options.messages.receipt(message.id);
|
|
112
171
|
const { snapshot: _, ...diagnostic } = receipt;
|
|
113
172
|
return { ok: true, ...diagnostic, ...(req.query.receipt_only === 'true' ? {} : { message: terminalMessage(message) }) };
|
|
@@ -148,7 +207,9 @@ export class IntegrationRuntime {
|
|
|
148
207
|
integration_policy_update: true,
|
|
149
208
|
session_restore_diagnostics: true,
|
|
150
209
|
native_identity_linux_flock_owner: process.platform === 'linux',
|
|
151
|
-
|
|
210
|
+
background_task_records: true, task_purpose_configuration: true, explicit_execution_state: true,
|
|
211
|
+
integration_message_send: true, integration_message_reply: true, integration_message_history: true,
|
|
212
|
+
permissions: INTEGRATION_OPERATIONS };
|
|
152
213
|
}
|
|
153
214
|
error(error) {
|
|
154
215
|
return { type: 'error', ok: false, code: error instanceof CollaborationError ? error.code : 'INTEGRATION_INTERNAL_ERROR',
|
|
@@ -169,6 +230,18 @@ export class IntegrationRuntime {
|
|
|
169
230
|
integrationError('TASK_NOT_FOUND', 'Task does not exist within this integration grant', 404);
|
|
170
231
|
this.authorize(p, operation, task.groupId);
|
|
171
232
|
}
|
|
233
|
+
message(p, id) {
|
|
234
|
+
const scoped = this.options.messages.snapshotMessages().filter(m => m.groupId === p.groupId);
|
|
235
|
+
const resolved = scopedId(id, scoped.map(m => m.id), 'MESSAGE');
|
|
236
|
+
return this.options.messages.getMessage(resolved);
|
|
237
|
+
}
|
|
238
|
+
messageExtras(raw) {
|
|
239
|
+
if (typeof raw.idempotency_key !== 'string' || !raw.idempotency_key.trim())
|
|
240
|
+
integrationError('IDEMPOTENCY_KEY_REQUIRED', 'Integration message mutations require an explicit idempotency key');
|
|
241
|
+
if (raw.task || raw.task_envelope || raw.metadata?.termdockTask)
|
|
242
|
+
integrationError('INTEGRATION_OPERATION_DENIED', 'Ordinary messages cannot forge task envelopes', 403);
|
|
243
|
+
return { idempotencyKey: raw.idempotency_key, responseKind: raw.response_kind, metadata: raw.metadata, expiresAt: raw.expires_at };
|
|
244
|
+
}
|
|
172
245
|
origin(p, input) {
|
|
173
246
|
const value = input && typeof input === 'object' ? input : {};
|
|
174
247
|
if (Buffer.byteLength(JSON.stringify(value)) > 16384)
|
|
@@ -214,11 +287,16 @@ export class IntegrationRuntime {
|
|
|
214
287
|
if (groups.has(message.groupId)) {
|
|
215
288
|
const link = message.metadata?.termdockTask;
|
|
216
289
|
const context = { group_id: message.groupId, task_id: link?.taskId ?? null, attempt_id: link?.attemptId ?? null,
|
|
217
|
-
reply_to_event_id: link?.replyToEventId ?? null, message_id: message.id, source: message.fromSessionId ? 'member' : 'system'
|
|
290
|
+
reply_to_event_id: link?.replyToEventId ?? null, message_id: message.id, source: message.integrationOrigin ? 'integration' : message.fromSessionId ? 'member' : 'system',
|
|
291
|
+
actor: message.integrationOrigin ? { integration_id: message.integrationOrigin.integrationId } : message.fromSessionId ? { session_id: message.fromSessionId } : null,
|
|
292
|
+
external_actor: message.integrationOrigin?.externalActor ?? null };
|
|
218
293
|
updates.push({ sourceKey: `message:${message.id}`, sourceVersion: '1', event: { ...context,
|
|
219
294
|
kind: message.kind === 'reply' ? 'message.reply' : 'message.queued', created_at: message.createdAt,
|
|
220
295
|
payload: { message_id: message.id, thread_id: message.threadId, reply_to: message.replyTo ?? null,
|
|
221
|
-
from_session_id: message.fromSessionId, to_session_id: message.
|
|
296
|
+
from_session_id: message.fromSessionId, to_session_id: message.toPrincipalId ? null : message.toSessionId,
|
|
297
|
+
to_principal_id: message.toPrincipalId ?? null, integration_origin: message.integrationOrigin ?? null,
|
|
298
|
+
response_kind: message.responseKind ?? null, stored_at: message.storedAt ?? null,
|
|
299
|
+
content: message.content, metadata: message.metadata ?? null } } });
|
|
222
300
|
const { snapshot: _, ...receipt } = this.options.messages.receipt(message.id);
|
|
223
301
|
updates.push({ sourceKey: `message-status:${message.id}`, sourceVersion: JSON.stringify(receipt), event: {
|
|
224
302
|
...context, kind: 'message.delivery', created_at: message.deliveredAt ?? message.createdAt, payload: { receipt }
|
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
4
4
|
import { CollaborationError } from './collaborationProtocol.js';
|
|
5
5
|
export const INTEGRATION_PROTOCOL = 1;
|
|
6
|
-
export const INTEGRATION_OPERATIONS = ['task.read', 'task.create', 'task.assign', 'task.comment', 'task.revise', 'task.answer', 'events.read', 'session.create', 'session.read', 'session.restore'];
|
|
6
|
+
export const INTEGRATION_OPERATIONS = ['message.send', 'message.read', 'task.read', 'task.create', 'task.configure', 'task.assign', 'task.comment', 'task.revise', 'task.answer', 'events.read', 'session.create', 'session.read', 'session.restore'];
|
|
7
7
|
export function integrationError(code, message, status = 400) { throw new CollaborationError(code, message, status); }
|
|
8
8
|
export function atomicJson(file, value) {
|
|
9
9
|
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
package/dist/server/cli.js
CHANGED
|
@@ -3489,7 +3489,7 @@ async function main() {
|
|
|
3489
3489
|
}
|
|
3490
3490
|
if (options.integration) {
|
|
3491
3491
|
const argv = options.integration;
|
|
3492
|
-
if (!argv.length ||
|
|
3492
|
+
if (!argv.length || argv.includes('--help') || argv[0] === 'help') {
|
|
3493
3493
|
console.log(INTEGRATION_HELP);
|
|
3494
3494
|
return;
|
|
3495
3495
|
}
|