termdock 1.4.313 → 1.4.315
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-ChS2-lkz.js → App-B2SFV3qg.js} +53 -53
- package/dist/client/assets/App-B2SFV3qg.js.br +0 -0
- package/dist/client/assets/App-B2SFV3qg.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-JtjyyJoW.js → ArchitecturePanel-Cj7za6DZ.js} +6 -6
- package/dist/client/assets/ArchitecturePanel-Cj7za6DZ.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-Cj7za6DZ.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-BlQ5-VPp.js → ChangeWalkthroughPanel-BB52iLLC.js} +2 -2
- package/dist/client/assets/ChangeWalkthroughPanel-BB52iLLC.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BB52iLLC.js.gz +0 -0
- package/dist/client/assets/{CollaborationMainWorkspace-aFLAMqDr.js → CollaborationMainWorkspace-D5WKV3rA.js} +1 -1
- package/dist/client/assets/CollaborationMainWorkspace-D5WKV3rA.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-D5WKV3rA.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-MwUgcmG_.js +2 -0
- package/dist/client/assets/ComputerControlView-Dkc4R1IU.js +5 -0
- package/dist/client/assets/ComputerControlView-Dkc4R1IU.js.br +0 -0
- package/dist/client/assets/ComputerControlView-Dkc4R1IU.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-CR4uDFOx.js → DagPlayground-BHY3l8UG.js} +1 -1
- package/dist/client/assets/DagPlayground-BHY3l8UG.js.br +0 -0
- package/dist/client/assets/DagPlayground-BHY3l8UG.js.gz +0 -0
- package/dist/client/assets/{DiffLab-BqeHMDOy.js → DiffLab-BSQiKfBJ.js} +1 -1
- package/dist/client/assets/DiffLab-BSQiKfBJ.js.br +0 -0
- package/dist/client/assets/DiffLab-BSQiKfBJ.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DqrOcRfP.js → DiffReview-CYrBBq0V.js} +1 -1
- package/dist/client/assets/DiffReview-CYrBBq0V.js.br +0 -0
- package/dist/client/assets/DiffReview-CYrBBq0V.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CEYpbrL6.js → DiffReviewLab-VSIbEnxm.js} +1 -1
- package/dist/client/assets/DiffReviewLab-VSIbEnxm.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-VSIbEnxm.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-F-uQSmhG.js → DiffViewer-Cx5fyiMB.js} +8 -8
- package/dist/client/assets/DiffViewer-Cx5fyiMB.js.br +0 -0
- package/dist/client/assets/DiffViewer-Cx5fyiMB.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-KmXFkgij.js → ModelPreview-B22odexG.js} +1 -1
- package/dist/client/assets/ModelPreview-B22odexG.js.br +0 -0
- package/dist/client/assets/ModelPreview-B22odexG.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-VMdXpo4h.js → RightSidebar-DKA0jXPW.js} +3 -3
- package/dist/client/assets/RightSidebar-DKA0jXPW.js.br +0 -0
- package/dist/client/assets/RightSidebar-DKA0jXPW.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-CAMk1C0N.js → abnfDiagram-VCTEODGH-sbUSsiPn.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-sbUSsiPn.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-sbUSsiPn.js.gz +0 -0
- package/dist/client/assets/app-CYOLJycb.js +35 -0
- package/dist/client/assets/app-CYOLJycb.js.br +0 -0
- package/dist/client/assets/app-CYOLJycb.js.gz +0 -0
- package/dist/client/assets/{arc-CYG_-1vC.js → arc-GhJ9aeQ3.js} +1 -1
- package/dist/client/assets/arc-GhJ9aeQ3.js.br +0 -0
- package/dist/client/assets/arc-GhJ9aeQ3.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-BqHzezLR.js → architectureDiagram-5GKGNRK7-BYmAIJBx.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BYmAIJBx.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BYmAIJBx.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-D6GWRO_Z.js → blockDiagram-I7D4REHJ-CZNZT_ez.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-CZNZT_ez.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CZNZT_ez.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-CutmGIGb.js → c4Diagram-7LVT6UL2-6xcSowLn.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-6xcSowLn.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-6xcSowLn.js.gz +0 -0
- package/dist/client/assets/channel-C1FwyjiU.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-DwiUpGFu.js → chunk-2Q5K7J3B-C06nkhUQ.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-C35gLPSH.js → chunk-5VM5RSS4-BHY43hJO.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-CNptP19P.js → chunk-F27PBJKO-Dl8JYcZO.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-Dl8JYcZO.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-Dl8JYcZO.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-DHdpB9A0.js → chunk-IMKFNOWR-BALi4Q3g.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-BALi4Q3g.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BALi4Q3g.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-CrKSOzdE.js → chunk-JWPE2WC7-BBD2d7j7.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-CiZGLRSk.js → chunk-POPQ4Y6H-CZN0_ndj.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-B70pX8OB.js → chunk-SVP7TREG-CD-Zf9rn.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-CD-Zf9rn.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CD-Zf9rn.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-Ba1mI99F.js → chunk-TICWLB2K-Clpg1zwp.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-Clpg1zwp.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Clpg1zwp.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DmKIl18h.js → chunk-XXDRQBXY-BanPVnIr.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-FyKDan8T.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-FyKDan8T.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-C-NMDUHW.js → cose-bilkent-JH36ORCC-431u7cfU.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-431u7cfU.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-431u7cfU.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-CZgEc1ab.js → cynefin-OW5HDTMX-BuLFGx14.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-BuLFGx14.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-BuLFGx14.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CHQeSNm2.js → cynefinDiagram-5FMLGOSQ-qLzjwMMG.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-qLzjwMMG.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-qLzjwMMG.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-B_jkMdPS.js → dagre-GXQ25YYZ-CUdd5M5g.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-CUdd5M5g.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CUdd5M5g.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-nv6Lnsrp.js → diagram-S7CK7UJ4-DLQClBzm.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-DLQClBzm.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DLQClBzm.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-BZf2fzaA.js → diagram-UQ7AKVKN-1RGASXU_.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-1RGASXU_.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-1RGASXU_.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-CxL0_BH8.js → diagram-VSXAHHWV-DqnCzn2R.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-DqnCzn2R.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-DqnCzn2R.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-Dm9MqpIE.js → diagram-VX7I27RA-CMXsPqTS.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-CMXsPqTS.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CMXsPqTS.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-BIfTa7P5.js → diagram-Z3DM3KII-BM0N1kCR.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-BM0N1kCR.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-BM0N1kCR.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-D4XhCDFS.js → ebnfDiagram-PWID7BFC-CvaVo-wh.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-CvaVo-wh.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-CvaVo-wh.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-Dxd48dXC.js → erDiagram-RLTQ6QDP-okw-AY7i.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-okw-AY7i.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-okw-AY7i.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-BXBMsEmE.js → flowDiagram-HODETNUW-B_DWtzOe.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-B_DWtzOe.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-B_DWtzOe.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CBfDd-KZ.js → ganttDiagram-EL5Y4UJY-Bm4nYUVg.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bm4nYUVg.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bm4nYUVg.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-DXLmNGli.js → gestureArbiter-XalN4TaN.js} +1 -1
- package/dist/client/assets/gestureArbiter-XalN4TaN.js.br +0 -0
- package/dist/client/assets/gestureArbiter-XalN4TaN.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-DtLM68fN.js → gitGraphDiagram-WWUBYQGX-B7LAo8S2.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-B7LAo8S2.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-B7LAo8S2.js.gz +0 -0
- package/dist/client/assets/{index-KuPaZyuZ.css → index-BObjbh2R.css} +1 -1
- package/dist/client/assets/index-BObjbh2R.css.br +0 -0
- package/dist/client/assets/{index-KuPaZyuZ.css.gz → index-BObjbh2R.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-FRhqdJvW.js → infoDiagram-27XIBGKW-DXncUrwz.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DAHBvAZ-.js → ishikawaDiagram-5VMMS53U-Ds28H7pI.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DAHBvAZ-.js.br → ishikawaDiagram-5VMMS53U-Ds28H7pI.js.br} +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Ds28H7pI.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-CVuWuL3Z.js → journeyDiagram-3NMN7TZE-WeF_efZ2.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-WeF_efZ2.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-WeF_efZ2.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-ByQSUVJV.js → kanban-definition-UXKFOSKX-CMbZcy6U.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-CMbZcy6U.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CMbZcy6U.js.gz +0 -0
- package/dist/client/assets/{layout-Bb3Nb1c4.js → layout-DNapC8T-.js} +1 -1
- package/dist/client/assets/layout-DNapC8T-.js.br +0 -0
- package/dist/client/assets/layout-DNapC8T-.js.gz +0 -0
- package/dist/client/assets/{linear-DHMMQlOo.js → linear-B9AFx-TF.js} +1 -1
- package/dist/client/assets/linear-B9AFx-TF.js.br +0 -0
- package/dist/client/assets/linear-B9AFx-TF.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-BYfniK0H.js → mermaid.core-Ddh1Z0hf.js} +5 -5
- package/dist/client/assets/mermaid.core-Ddh1Z0hf.js.br +0 -0
- package/dist/client/assets/mermaid.core-Ddh1Z0hf.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-EDLD5AyH.js → mindmap-definition-YA3MSWOX-B0xMGUol.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-B0xMGUol.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-B0xMGUol.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-DCrtirwT.js → passwordBootstrap-DQRd5vCF.js} +1 -1
- package/dist/client/assets/passwordBootstrap-DQRd5vCF.js.br +0 -0
- package/dist/client/assets/{passwordBootstrap-DCrtirwT.js.gz → passwordBootstrap-DQRd5vCF.js.gz} +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-BHYhkqJN.js → pegDiagram-XKGWAZYB-BVZ-3kEF.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-BVZ-3kEF.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BVZ-3kEF.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-BUIJlswC.js → pieDiagram-E7YTZNPT-Cim4Hk3I.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-Cim4Hk3I.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-Cim4Hk3I.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-D8Im-7yC.js → quadrantDiagram-AXDQQJYC-CYiEj5sp.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CYiEj5sp.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CYiEj5sp.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-D7n6z2G1.js → railroadDiagram-O6MQD6OU-DjNNfYra.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjNNfYra.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjNNfYra.js.gz +0 -0
- package/dist/client/assets/{rdpSession-DJlNIbVk.js → rdpSession-DEzSQAuN.js} +1 -1
- package/dist/client/assets/rdpSession-DEzSQAuN.js.br +0 -0
- package/dist/client/assets/rdpSession-DEzSQAuN.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-DFSrssSr.js → referenceLongPress-BjyTtoDY.js} +1 -1
- package/dist/client/assets/referenceLongPress-BjyTtoDY.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BjyTtoDY.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-Ki0rR-F7.js → requirementDiagram-BXWQKSXE-ZwiKdiI3.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-ZwiKdiI3.js.br +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-Ki0rR-F7.js.gz → requirementDiagram-BXWQKSXE-ZwiKdiI3.js.gz} +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-36NmMqsW.js → sankeyDiagram-P5KCCOFB-BYR7ctps.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BYR7ctps.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BYR7ctps.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-5vsPuFyO.js → sequenceDiagram-WJ2MYXX4-DxYCvK80.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DxYCvK80.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DxYCvK80.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-DbAulwBg.js → sizeCapture-INFHLROL-CXruk8Ko.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-CXruk8Ko.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CXruk8Ko.js.gz +0 -0
- package/dist/client/assets/{sparkles-CapLTKAs.js → sparkles-DRH97PDH.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-Bgwe0g5S.js → stateDiagram-D77RDMKH-CENDGrxr.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-CENDGrxr.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CENDGrxr.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-De-tGy_n.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-COGAWe-g.js → swimlanes-42K2YHIH-BZQeVFeA.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-BZQeVFeA.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-BZQeVFeA.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-D1YMLrIO.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-C4gt5z68.js → timeline-definition-24CTP7MA-DiJ9i33g.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-DiJ9i33g.js.br +0 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-C4gt5z68.js.gz → timeline-definition-24CTP7MA-DiJ9i33g.js.gz} +0 -0
- package/dist/client/assets/{triangle-alert-xPHw25jD.js → triangle-alert-DECoBoOV.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CIEXh9oD.js → vennDiagram-4TSXK5OY-DBiEJQ9Y.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-DBiEJQ9Y.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DBiEJQ9Y.js.gz +0 -0
- package/dist/client/assets/{videoCompression-CUkCS2-q.js → videoCompression-8r1jOza9.js} +1 -1
- package/dist/client/assets/videoCompression-8r1jOza9.js.br +0 -0
- package/dist/client/assets/videoCompression-8r1jOza9.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-gQhcW1vd.js → wardleyDiagram-VM6X3IG4-B6wCSfya.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B6wCSfya.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B6wCSfya.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-BmIcdejz.js → xychartDiagram-S5SC5T6Z-DlNQayU5.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DlNQayU5.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DlNQayU5.js.gz +0 -0
- package/dist/client/index.html +3 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/ipad-status-bar.js +12 -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 +30 -8
- package/dist/server/agent/collaborationStore.js +25 -2
- package/dist/server/agent/collaborationTmuxDelivery.js +11 -3
- package/dist/server/agent/integrationCli.js +15 -3
- package/dist/server/agent/integrationServer.js +16 -1
- package/dist/server/agent/integrationSessions.js +342 -14
- package/dist/server/agent/integrationStore.js +1 -1
- package/dist/server/agent/promptDelivery.js +7 -1
- package/dist/server/agent/sessionLaunchDiagnostics.js +26 -0
- package/dist/server/agent/sessionLifecycle.js +4 -0
- package/dist/server/agent/sessionManagement.js +87 -0
- package/dist/server/agent/terminalInput.js +9 -1
- package/dist/server/routes/terminal.js +172 -21
- package/docs/integrations.md +208 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-ChS2-lkz.js.br +0 -0
- package/dist/client/assets/App-ChS2-lkz.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-JtjyyJoW.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-JtjyyJoW.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BlQ5-VPp.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BlQ5-VPp.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-aFLAMqDr.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-aFLAMqDr.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-BDQMRhU9.js +0 -2
- package/dist/client/assets/ComputerControlView-TAKDbBUl.js +0 -5
- package/dist/client/assets/ComputerControlView-TAKDbBUl.js.br +0 -0
- package/dist/client/assets/ComputerControlView-TAKDbBUl.js.gz +0 -0
- package/dist/client/assets/DagPlayground-CR4uDFOx.js.br +0 -0
- package/dist/client/assets/DagPlayground-CR4uDFOx.js.gz +0 -0
- package/dist/client/assets/DiffLab-BqeHMDOy.js.br +0 -0
- package/dist/client/assets/DiffLab-BqeHMDOy.js.gz +0 -0
- package/dist/client/assets/DiffReview-DqrOcRfP.js.br +0 -0
- package/dist/client/assets/DiffReview-DqrOcRfP.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CEYpbrL6.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CEYpbrL6.js.gz +0 -0
- package/dist/client/assets/DiffViewer-F-uQSmhG.js.br +0 -0
- package/dist/client/assets/DiffViewer-F-uQSmhG.js.gz +0 -0
- package/dist/client/assets/ModelPreview-KmXFkgij.js.br +0 -0
- package/dist/client/assets/ModelPreview-KmXFkgij.js.gz +0 -0
- package/dist/client/assets/RightSidebar-VMdXpo4h.js.br +0 -0
- package/dist/client/assets/RightSidebar-VMdXpo4h.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CAMk1C0N.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CAMk1C0N.js.gz +0 -0
- package/dist/client/assets/app-CHxLSuGQ.js +0 -35
- package/dist/client/assets/app-CHxLSuGQ.js.br +0 -0
- package/dist/client/assets/app-CHxLSuGQ.js.gz +0 -0
- package/dist/client/assets/arc-CYG_-1vC.js.br +0 -0
- package/dist/client/assets/arc-CYG_-1vC.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BqHzezLR.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-BqHzezLR.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-D6GWRO_Z.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-D6GWRO_Z.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CutmGIGb.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CutmGIGb.js.gz +0 -0
- package/dist/client/assets/channel-B3BKM2gg.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-CNptP19P.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CNptP19P.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-DHdpB9A0.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-DHdpB9A0.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-B70pX8OB.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-B70pX8OB.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Ba1mI99F.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Ba1mI99F.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-CS4V_MQS.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CS4V_MQS.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-C-NMDUHW.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-C-NMDUHW.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CZgEc1ab.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CZgEc1ab.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CHQeSNm2.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CHQeSNm2.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-B_jkMdPS.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-B_jkMdPS.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-nv6Lnsrp.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-nv6Lnsrp.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BZf2fzaA.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BZf2fzaA.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CxL0_BH8.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CxL0_BH8.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-Dm9MqpIE.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-Dm9MqpIE.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-BIfTa7P5.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-BIfTa7P5.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-D4XhCDFS.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-D4XhCDFS.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dxd48dXC.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dxd48dXC.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BXBMsEmE.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BXBMsEmE.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CBfDd-KZ.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CBfDd-KZ.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-DXLmNGli.js.br +0 -0
- package/dist/client/assets/gestureArbiter-DXLmNGli.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DtLM68fN.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DtLM68fN.js.gz +0 -0
- package/dist/client/assets/index-KuPaZyuZ.css.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DAHBvAZ-.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CVuWuL3Z.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CVuWuL3Z.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-ByQSUVJV.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-ByQSUVJV.js.gz +0 -0
- package/dist/client/assets/layout-Bb3Nb1c4.js.br +0 -0
- package/dist/client/assets/layout-Bb3Nb1c4.js.gz +0 -0
- package/dist/client/assets/linear-DHMMQlOo.js.br +0 -0
- package/dist/client/assets/linear-DHMMQlOo.js.gz +0 -0
- package/dist/client/assets/mermaid.core-BYfniK0H.js.br +0 -0
- package/dist/client/assets/mermaid.core-BYfniK0H.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-EDLD5AyH.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-EDLD5AyH.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-DCrtirwT.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BHYhkqJN.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BHYhkqJN.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-BUIJlswC.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-BUIJlswC.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-D8Im-7yC.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-D8Im-7yC.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-D7n6z2G1.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-D7n6z2G1.js.gz +0 -0
- package/dist/client/assets/rdpSession-DJlNIbVk.js.br +0 -0
- package/dist/client/assets/rdpSession-DJlNIbVk.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-DFSrssSr.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DFSrssSr.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Ki0rR-F7.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-36NmMqsW.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-36NmMqsW.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-5vsPuFyO.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-5vsPuFyO.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-DbAulwBg.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-DbAulwBg.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-Bgwe0g5S.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-Bgwe0g5S.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-Bg6S3Zm0.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-COGAWe-g.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-COGAWe-g.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DwBBOocG.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-C4gt5z68.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CIEXh9oD.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CIEXh9oD.js.gz +0 -0
- package/dist/client/assets/videoCompression-CUkCS2-q.js.br +0 -0
- package/dist/client/assets/videoCompression-CUkCS2-q.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-gQhcW1vd.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-gQhcW1vd.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmIcdejz.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmIcdejz.js.gz +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import { cleanMemberName } from './collaborationRoutes.js';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
4
5
|
import { atomicJson, integrationError } from './integrationStore.js';
|
|
5
6
|
import { SessionLifecycleCoordinator, assertMessageRuntime, assertReleaseFacts, assertReleaseGeneration } from './sessionLifecycle.js';
|
|
6
7
|
import { resumeConfigurationFingerprint } from './sessionResumeConfiguration.js';
|
|
7
8
|
import { NativeResumeOwnerError } from './nativeResumeOwner.js';
|
|
9
|
+
import { CollaborationError } from './collaborationProtocol.js';
|
|
10
|
+
import { beginLaunchDiagnostics, launchFailure, launchProgress } from './sessionLaunchDiagnostics.js';
|
|
8
11
|
/** Quote each configured argument as literal shell data, including paths. */
|
|
9
12
|
export function integrationLaunchCommand(record, restore) {
|
|
10
13
|
const launchArgs = record.profile.argv.map(arg => arg === '{cwd}' ? record.cwd : arg);
|
|
@@ -20,8 +23,9 @@ function startupInput(record, now) {
|
|
|
20
23
|
return condition ? { state: 'pending', deadline: now + (condition.timeoutMs ?? 120000), matched_since: null, observed_at: null } : undefined;
|
|
21
24
|
}
|
|
22
25
|
export function publicIntegrationSession(record) {
|
|
23
|
-
const { profile: _, deadline: _deadline, launch_submitted: _submitted, startup_condition: _condition, restore_diagnostics: diagnostics, ...publicRecord } = record;
|
|
24
|
-
return { ...publicRecord, ...(diagnostics ? { restore_diagnostics_available: true } : {})
|
|
26
|
+
const { profile: _, deadline: _deadline, launch_submitted: _submitted, startup_condition: _condition, restore_diagnostics: diagnostics, launch_diagnostics: launchDiagnostics, launch_diagnostics_history: _history, message_history_seen: _messages, close_intent: _closeIntent, ...publicRecord } = record;
|
|
27
|
+
return { ...publicRecord, close_pending: !!_closeIntent, ...(diagnostics ? { restore_diagnostics_available: true } : {}),
|
|
28
|
+
...(launchDiagnostics ? { launch_diagnostics_available: true } : {}) };
|
|
25
29
|
}
|
|
26
30
|
export function permittedCwd(profile, cwd) {
|
|
27
31
|
if (typeof cwd !== 'string' || !path.isAbsolute(cwd) || /[\x00-\x1f\x7f]/.test(cwd))
|
|
@@ -56,6 +60,8 @@ export class IntegrationSessions {
|
|
|
56
60
|
listeners = new Set();
|
|
57
61
|
lifecycle = new SessionLifecycleCoordinator();
|
|
58
62
|
mutations = new Map();
|
|
63
|
+
coldRetries = new Set();
|
|
64
|
+
closingOperations = new Set();
|
|
59
65
|
timers = new Set();
|
|
60
66
|
stopObservation;
|
|
61
67
|
stopDeliveryGuard;
|
|
@@ -80,7 +86,7 @@ export class IntegrationSessions {
|
|
|
80
86
|
record.runtime_present ??= null;
|
|
81
87
|
}
|
|
82
88
|
for (const record of this.doc.sessions)
|
|
83
|
-
if (['starting', 'restoring', 'binding_pending'].includes(record.state) || record.state
|
|
89
|
+
if (['starting', 'restoring', 'binding_pending'].includes(record.state) || ['releasing', 'closing'].includes(record.state) || record.startup_input?.state === 'pending')
|
|
84
90
|
this.scheduleRefresh(record);
|
|
85
91
|
// A pre-restart partial match cannot prove continuity of the live screen.
|
|
86
92
|
for (const record of this.doc.sessions)
|
|
@@ -111,7 +117,9 @@ export class IntegrationSessions {
|
|
|
111
117
|
}
|
|
112
118
|
saveRecord(record) {
|
|
113
119
|
const before = this.doc.sessions;
|
|
114
|
-
|
|
120
|
+
const seen = before.find(s => s.session_id === record.session_id)?.message_history_seen;
|
|
121
|
+
this.doc.sessions = [...before.filter(s => s.session_id !== record.session_id), structuredClone({ ...record,
|
|
122
|
+
...(seen ? { message_history_seen: true } : {}) })];
|
|
115
123
|
try {
|
|
116
124
|
this.save();
|
|
117
125
|
}
|
|
@@ -154,7 +162,8 @@ export class IntegrationSessions {
|
|
|
154
162
|
const now = Date.now(), record = { operation_id: randomUUID(), session_id: randomBytes(6).toString('hex'),
|
|
155
163
|
group_id: principal.groupId, principal_id: principal.id, agent_slug: profile.agentSlug, agent_native_session_id: null,
|
|
156
164
|
state: 'starting', generation: 1, runtime_present: null, error_code: null, cwd, launch_profile: profile.id, profile: structuredClone(profile),
|
|
157
|
-
created_at: now, updated_at: now, deadline: now + this.bindingTimeout, launch_submitted: false };
|
|
165
|
+
created_at: now, updated_at: now, deadline: now + this.bindingTimeout, launch_submitted: false, message_history_seen: false };
|
|
166
|
+
record.launch_diagnostics = beginLaunchDiagnostics(record.operation_id, 1, 'cold_start');
|
|
158
167
|
record.startup_input = startupInput(record, now);
|
|
159
168
|
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: record.session_id };
|
|
160
169
|
try {
|
|
@@ -166,7 +175,7 @@ export class IntegrationSessions {
|
|
|
166
175
|
}
|
|
167
176
|
return this.launch(record, false);
|
|
168
177
|
}
|
|
169
|
-
launch(record, restoring) {
|
|
178
|
+
launch(record, restoring, retryCold = false) {
|
|
170
179
|
const promise = (async () => {
|
|
171
180
|
try {
|
|
172
181
|
// Store intent before launching. A failed persistence cannot execute.
|
|
@@ -181,17 +190,29 @@ export class IntegrationSessions {
|
|
|
181
190
|
catch (error) {
|
|
182
191
|
// Existing creation supports plugins without an exact resume path.
|
|
183
192
|
// They remain launchable, but cannot gain a releasable descriptor.
|
|
184
|
-
if (restoring || error.code !== 'EXACT_RESUME_UNSUPPORTED')
|
|
193
|
+
if (restoring || retryCold || error.code !== 'EXACT_RESUME_UNSUPPORTED')
|
|
185
194
|
throw error;
|
|
186
195
|
}
|
|
187
196
|
}
|
|
188
197
|
record.launch_submitted = true;
|
|
189
198
|
this.saveRecord(record);
|
|
199
|
+
const progress = (phase) => {
|
|
200
|
+
const latest = this.doc.sessions.find(s => s.session_id === record.session_id);
|
|
201
|
+
if (latest.operation_id !== record.operation_id || latest.generation !== record.generation)
|
|
202
|
+
integrationError('SESSION_GENERATION_MISMATCH', 'Launch operation changed during progress recording', 409);
|
|
203
|
+
if (latest.launch_diagnostics) {
|
|
204
|
+
record.launch_diagnostics = launchProgress(latest.launch_diagnostics, phase);
|
|
205
|
+
this.saveRecord({ ...latest, launch_diagnostics: record.launch_diagnostics });
|
|
206
|
+
}
|
|
207
|
+
};
|
|
190
208
|
const prepared = (binding) => { record.terminal_binding = binding; this.saveRecord(record); };
|
|
191
|
-
if (
|
|
192
|
-
await this.adapter.
|
|
209
|
+
if (retryCold)
|
|
210
|
+
await this.adapter.retryCold(record, prepared, progress);
|
|
211
|
+
else if (restoring)
|
|
212
|
+
await this.adapter.restore(record, prepared, progress);
|
|
193
213
|
else
|
|
194
|
-
await this.adapter.create(record, prepared);
|
|
214
|
+
await this.adapter.create(record, prepared, progress);
|
|
215
|
+
progress('binding_observe');
|
|
195
216
|
await this.refresh(record.session_id);
|
|
196
217
|
this.scheduleRefresh(record);
|
|
197
218
|
}
|
|
@@ -199,6 +220,7 @@ export class IntegrationSessions {
|
|
|
199
220
|
const current = this.doc.sessions.find(s => s.session_id === record.session_id);
|
|
200
221
|
const code = error.code;
|
|
201
222
|
this.saveRecord({ ...current, state: 'failed', error_code: typeof code === 'string' ? code : 'SESSION_LAUNCH_FAILED',
|
|
223
|
+
launch_diagnostics: current.launch_diagnostics ? launchFailure(current.launch_diagnostics, error, typeof code === 'string' ? code : 'SESSION_LAUNCH_FAILED') : undefined,
|
|
202
224
|
restore_diagnostics: error instanceof NativeResumeOwnerError ? { ...structuredClone(error.diagnostics), operation_id: current.operation_id } : undefined,
|
|
203
225
|
updated_at: Date.now() });
|
|
204
226
|
}
|
|
@@ -216,10 +238,33 @@ export class IntegrationSessions {
|
|
|
216
238
|
return structuredClone({ session_id: record.session_id, operation_id: record.operation_id,
|
|
217
239
|
state: record.state, error_code: record.error_code, diagnostics: record.restore_diagnostics ?? null });
|
|
218
240
|
}
|
|
219
|
-
|
|
241
|
+
launchDiagnostics(id) {
|
|
242
|
+
const record = this.doc.sessions.find(s => s.session_id === id);
|
|
243
|
+
if (!record)
|
|
244
|
+
return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Integration session does not exist', 404);
|
|
245
|
+
return structuredClone({ launch_diagnostics: record.launch_diagnostics ?? null,
|
|
246
|
+
launch_diagnostics_history: record.launch_diagnostics_history ?? [] });
|
|
247
|
+
}
|
|
248
|
+
assertRuntimeMessage(id) {
|
|
249
|
+
const record = this.doc.sessions.find(s => s.session_id === id);
|
|
250
|
+
if (this.closingOperations.has(id))
|
|
251
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close preflight is in progress', 409);
|
|
252
|
+
if (this.coldRetries.has(id) || record?.cold_retry_pending)
|
|
253
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Cold retry must finish or be reconciled before sending', 409);
|
|
254
|
+
if (record?.state === 'closing' && !record.operation_uncertain)
|
|
255
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress', 409);
|
|
256
|
+
if (record?.close_intent)
|
|
257
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Close outcome requires reconciliation', 409);
|
|
258
|
+
assertMessageRuntime(record);
|
|
259
|
+
// Durable, conservative latch before admission; even a later enqueue
|
|
260
|
+
// failure cannot make a previously attempted business request disappear.
|
|
261
|
+
if (record && !record.message_history_seen)
|
|
262
|
+
this.saveRecord({ ...record, message_history_seen: true });
|
|
263
|
+
}
|
|
220
264
|
assertMessageTarget(principal, id) {
|
|
221
265
|
const record = this.doc.sessions.find(s => s.session_id === id && s.group_id === principal.groupId);
|
|
222
|
-
|
|
266
|
+
if (record)
|
|
267
|
+
this.assertRuntimeMessage(id);
|
|
223
268
|
}
|
|
224
269
|
async mutate(principal, key, input, action) {
|
|
225
270
|
const request = this.request(principal, key, input);
|
|
@@ -259,6 +304,76 @@ export class IntegrationSessions {
|
|
|
259
304
|
async restore(principal, id, key) {
|
|
260
305
|
return this.mutate(principal, key, ['restore', id], () => this.lifecycle.run(id, () => this.restoreOnce(principal, id, key)));
|
|
261
306
|
}
|
|
307
|
+
async retryCold(principal, id, generation, key) {
|
|
308
|
+
return this.mutate(principal, key, ['retry-cold', id, generation], () => this.lifecycle.run(id, async () => {
|
|
309
|
+
const request = this.request(principal, key, ['retry-cold', id, generation]);
|
|
310
|
+
if (request.previous)
|
|
311
|
+
return this.replayRequest(principal, id, request.previous);
|
|
312
|
+
this.assertManagementSettled(this.lookup(principal, id));
|
|
313
|
+
if (!this.adapter.retryCold || !this.adapter.messageHistory)
|
|
314
|
+
integrationError('SESSION_COLD_RETRY_UNSUPPORTED', 'Runtime adapter does not support verified cold retry', 409);
|
|
315
|
+
if (this.pending.has(id))
|
|
316
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Launch is in progress', 409);
|
|
317
|
+
this.coldRetries.add(id);
|
|
318
|
+
try {
|
|
319
|
+
const record = await this.get(principal, id);
|
|
320
|
+
this.assertManagementSettled(record);
|
|
321
|
+
assertReleaseGeneration(record, generation);
|
|
322
|
+
if (record.cold_retry_pending || record.operation_uncertain)
|
|
323
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile prior lifecycle outcome before cold retry', 409);
|
|
324
|
+
if (record.agent_native_session_id)
|
|
325
|
+
integrationError('SESSION_COLD_RETRY_NATIVE_BOUND', 'Use exact native restore for a bound session', 409);
|
|
326
|
+
if (record.state !== 'failed')
|
|
327
|
+
integrationError('SESSION_COLD_RETRY_NOT_FAILED', 'Only failed unbound cold starts can be retried', 409);
|
|
328
|
+
const history = this.adapter.messageHistory(id);
|
|
329
|
+
if (history === null)
|
|
330
|
+
integrationError('SESSION_MESSAGE_HISTORY_UNCONFIRMED', 'Message history cannot be verified', 409);
|
|
331
|
+
if (record.message_history_seen || history || this.adapter.pendingMessages?.(id))
|
|
332
|
+
integrationError('SESSION_MESSAGE_HISTORY_PRESENT', 'Cold retry refuses any TD business message history or attempted admission', 409);
|
|
333
|
+
const authorized = principal.launchProfiles.find(p => p.id === record.launch_profile);
|
|
334
|
+
if (!authorized)
|
|
335
|
+
integrationError('LAUNCH_PROFILE_DENIED', 'Original launch profile is no longer authorized', 403);
|
|
336
|
+
permittedCwd(authorized, record.cwd);
|
|
337
|
+
permittedCwd(record.profile, record.cwd);
|
|
338
|
+
if (!record.resume_configuration_fingerprint)
|
|
339
|
+
integrationError('RESUME_CONFIGURATION_UNCONFIRMED', 'Administrator must confirm the launcher/plugin fingerprint', 409);
|
|
340
|
+
if (record.resume_configuration_fingerprint !== await resumeConfigurationFingerprint(record, this.adapter))
|
|
341
|
+
integrationError('RESUME_CONFIGURATION_CHANGED', 'Launcher/plugin configuration changed', 409);
|
|
342
|
+
const observed = await this.adapter.inspect(record);
|
|
343
|
+
if (!record.terminal_binding || !observed.exists || observed.running || !observed.shell || observed.nativeId)
|
|
344
|
+
integrationError('SESSION_COLD_RETRY_RUNTIME_UNCONFIRMED', 'Retry requires the exact original, exited foreground shell', 409);
|
|
345
|
+
record.launch_diagnostics_history = [...(record.launch_diagnostics_history ?? []), ...(record.launch_diagnostics ? [record.launch_diagnostics] : [])].slice(-16);
|
|
346
|
+
record.generation = generation + 1;
|
|
347
|
+
record.operation_id = randomUUID();
|
|
348
|
+
record.state = 'starting';
|
|
349
|
+
record.error_code = null;
|
|
350
|
+
record.cold_retry_pending = true;
|
|
351
|
+
record.cold_retry_count = (record.cold_retry_count ?? 0) + 1;
|
|
352
|
+
record.runtime_present = true;
|
|
353
|
+
record.launch_submitted = false;
|
|
354
|
+
record.updated_at = Date.now();
|
|
355
|
+
record.deadline = Date.now() + this.bindingTimeout;
|
|
356
|
+
record.restore_diagnostics = undefined;
|
|
357
|
+
record.startup_input = startupInput(record, Date.now());
|
|
358
|
+
record.launch_diagnostics = beginLaunchDiagnostics(record.operation_id, record.generation, 'cold_retry');
|
|
359
|
+
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
|
|
360
|
+
try {
|
|
361
|
+
this.saveRecord(record);
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
delete this.doc.requests[request.scoped];
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
const result = await this.launch(record, false, true);
|
|
368
|
+
result.cold_retry_pending = false;
|
|
369
|
+
this.saveRecord(result);
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
this.coldRetries.delete(id);
|
|
374
|
+
}
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
262
377
|
async restoreOnce(principal, id, idempotencyKey) {
|
|
263
378
|
const request = this.request(principal, idempotencyKey, ['restore', id]);
|
|
264
379
|
if (request.previous)
|
|
@@ -268,6 +383,9 @@ export class IntegrationSessions {
|
|
|
268
383
|
let releaseNative;
|
|
269
384
|
try {
|
|
270
385
|
const record = await this.get(principal, id);
|
|
386
|
+
this.assertManagementSettled(record);
|
|
387
|
+
if (record.cold_retry_pending)
|
|
388
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile the cold retry before native restore', 409);
|
|
271
389
|
if (!record.agent_native_session_id)
|
|
272
390
|
integrationError('NATIVE_SESSION_ID_MISSING', 'An exact native session binding is required', 409);
|
|
273
391
|
// Recheck the current grant and actual directories; restore uses the
|
|
@@ -310,6 +428,8 @@ export class IntegrationSessions {
|
|
|
310
428
|
record.deadline = Date.now() + this.bindingTimeout;
|
|
311
429
|
record.updated_at = Date.now();
|
|
312
430
|
record.restore_diagnostics = undefined;
|
|
431
|
+
record.launch_diagnostics_history = [...(record.launch_diagnostics_history ?? []), ...(record.launch_diagnostics ? [record.launch_diagnostics] : [])].slice(-16);
|
|
432
|
+
record.launch_diagnostics = beginLaunchDiagnostics(record.operation_id, record.generation, 'native_restore');
|
|
313
433
|
if (!record.startup_input_disabled && !record.profile.startupInput && !record.startup_condition)
|
|
314
434
|
record.startup_condition = structuredClone(principal.launchProfiles.find(profile => profile.id === record.launch_profile)?.startupInput);
|
|
315
435
|
record.startup_input = startupInput(record, Date.now());
|
|
@@ -339,6 +459,7 @@ export class IntegrationSessions {
|
|
|
339
459
|
const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
|
|
340
460
|
if (!record)
|
|
341
461
|
return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Recovery record does not exist', 404);
|
|
462
|
+
this.assertManagementSettled(record);
|
|
342
463
|
assertReleaseGeneration(record, generation);
|
|
343
464
|
if (this.pending.has(id) || record.operation_uncertain || ['starting', 'restoring', 'binding_pending', 'releasing'].includes(record.state)) {
|
|
344
465
|
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current lifecycle operation before clearing startup input conditions', 409);
|
|
@@ -360,6 +481,7 @@ export class IntegrationSessions {
|
|
|
360
481
|
const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
|
|
361
482
|
if (!record)
|
|
362
483
|
return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Recovery record does not exist', 404);
|
|
484
|
+
this.assertManagementSettled(record);
|
|
363
485
|
assertReleaseGeneration(record, generation);
|
|
364
486
|
if (this.pending.has(id) || ['starting', 'restoring', 'binding_pending', 'releasing'].includes(record.state))
|
|
365
487
|
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current operation before confirming compatibility', 409);
|
|
@@ -372,16 +494,145 @@ export class IntegrationSessions {
|
|
|
372
494
|
return record;
|
|
373
495
|
});
|
|
374
496
|
}
|
|
497
|
+
assertManagementSettled(record) {
|
|
498
|
+
if (record.state === 'closed')
|
|
499
|
+
integrationError('SESSION_CLOSED', 'Explicitly closed sessions cannot be restored or restarted', 409);
|
|
500
|
+
if (record.state === 'closing' && !record.operation_uncertain)
|
|
501
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress', 409);
|
|
502
|
+
if (record.close_intent || record.state === 'closing')
|
|
503
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile the pending close before any lifecycle operation', 409);
|
|
504
|
+
if (record.rename_pending)
|
|
505
|
+
integrationError('SESSION_RENAME_SYNC_PENDING', 'Read session get to reconcile the pending name update', 409);
|
|
506
|
+
}
|
|
507
|
+
assertManagementIdle(record) {
|
|
508
|
+
if (this.pending.has(record.session_id) || record.cold_retry_pending || record.operation_uncertain || ['starting', 'restoring', 'binding_pending', 'releasing', 'closing'].includes(record.state)) {
|
|
509
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current lifecycle operation first', 409);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
async rename(principal, id, generation, value, key) {
|
|
513
|
+
if (typeof value !== 'string')
|
|
514
|
+
integrationError('INVALID_NAME', 'name must be non-empty text up to 80 characters');
|
|
515
|
+
const name = cleanMemberName(value);
|
|
516
|
+
if (!name)
|
|
517
|
+
integrationError('INVALID_NAME', 'name must be non-empty text up to 80 characters');
|
|
518
|
+
return this.mutate(principal, key, ['rename', id, generation, name], () => this.lifecycle.run(id, async () => {
|
|
519
|
+
const request = this.request(principal, key, ['rename', id, generation, name]);
|
|
520
|
+
if (request.previous)
|
|
521
|
+
return this.replayRequest(principal, id, request.previous);
|
|
522
|
+
if (!this.adapter.rename)
|
|
523
|
+
integrationError('SESSION_RENAME_UNSUPPORTED', 'Runtime adapter does not support renaming', 409);
|
|
524
|
+
const record = await this.get(principal, id);
|
|
525
|
+
assertReleaseGeneration(record, generation);
|
|
526
|
+
if (record.close_intent || record.rename_pending)
|
|
527
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the pending management operation first', 409);
|
|
528
|
+
this.assertManagementIdle(record);
|
|
529
|
+
await this.adapter.prepareRename?.(record);
|
|
530
|
+
record.name = name;
|
|
531
|
+
record.name_updated_at = Date.now();
|
|
532
|
+
record.updated_at = record.name_updated_at;
|
|
533
|
+
record.generation = generation + 1;
|
|
534
|
+
record.name_generation = record.generation;
|
|
535
|
+
record.name_operation_id = record.operation_id;
|
|
536
|
+
record.rename_pending = true;
|
|
537
|
+
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
|
|
538
|
+
try {
|
|
539
|
+
this.saveRecord(record);
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
delete this.doc.requests[request.scoped];
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
await this.adapter.rename(record);
|
|
547
|
+
record.rename_pending = false;
|
|
548
|
+
this.saveRecord(record);
|
|
549
|
+
}
|
|
550
|
+
catch { /* Durable intent is retried by get/restart; no runtime is created. */ }
|
|
551
|
+
return this.lookup(principal, id);
|
|
552
|
+
}));
|
|
553
|
+
}
|
|
554
|
+
async closeSession(principal, id, generation, key) {
|
|
555
|
+
return this.mutate(principal, key, ['close', id, generation], () => this.lifecycle.run(id, async () => {
|
|
556
|
+
const request = this.request(principal, key, ['close', id, generation]);
|
|
557
|
+
if (request.previous)
|
|
558
|
+
return this.replayRequest(principal, id, request.previous);
|
|
559
|
+
this.closingOperations.add(id);
|
|
560
|
+
try {
|
|
561
|
+
if (!this.adapter.prepareClose || !this.adapter.closeRuntime || !this.adapter.runtimePresent)
|
|
562
|
+
integrationError('SESSION_CLOSE_UNSUPPORTED', 'Runtime adapter does not support closing', 409);
|
|
563
|
+
const record = await this.get(principal, id);
|
|
564
|
+
assertReleaseGeneration(record, generation);
|
|
565
|
+
if (record.close_intent || record.rename_pending)
|
|
566
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Read session get to reconcile prior management intent', 409);
|
|
567
|
+
this.assertManagementIdle(record);
|
|
568
|
+
if (record.state === 'closed') {
|
|
569
|
+
if (await this.adapter.runtimePresent(record))
|
|
570
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Unexpected runtime exists for a closed record', 409);
|
|
571
|
+
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
|
|
572
|
+
try {
|
|
573
|
+
this.save();
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
delete this.doc.requests[request.scoped];
|
|
577
|
+
throw error;
|
|
578
|
+
}
|
|
579
|
+
return record;
|
|
580
|
+
}
|
|
581
|
+
if (this.adapter.pendingMessages?.(id))
|
|
582
|
+
integrationError('SESSION_PENDING_MESSAGES', 'Pending messages must be resolved before closing', 409);
|
|
583
|
+
const target = await this.adapter.prepareClose(record);
|
|
584
|
+
record.operation_id = randomUUID();
|
|
585
|
+
record.generation = generation + 1;
|
|
586
|
+
record.state = 'closing';
|
|
587
|
+
record.close_intent = { operation_id: record.operation_id, target };
|
|
588
|
+
record.error_code = null;
|
|
589
|
+
record.operation_uncertain = false;
|
|
590
|
+
record.updated_at = Date.now();
|
|
591
|
+
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
|
|
592
|
+
try {
|
|
593
|
+
this.saveRecord(record);
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
delete this.doc.requests[request.scoped];
|
|
597
|
+
throw error;
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
await this.adapter.closeRuntime(record, false);
|
|
601
|
+
if (await this.adapter.runtimePresent(record))
|
|
602
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime removal cannot be confirmed', 409);
|
|
603
|
+
record.state = 'closed';
|
|
604
|
+
record.runtime_present = false;
|
|
605
|
+
record.terminal_binding = null;
|
|
606
|
+
record.startup_input = undefined;
|
|
607
|
+
record.close_intent = undefined;
|
|
608
|
+
}
|
|
609
|
+
catch (error) {
|
|
610
|
+
record.state = 'failed';
|
|
611
|
+
record.operation_uncertain = true;
|
|
612
|
+
record.runtime_present = null;
|
|
613
|
+
record.error_code = typeof error.code === 'string' ? error.code : 'SESSION_CLOSE_FAILED';
|
|
614
|
+
}
|
|
615
|
+
record.updated_at = Date.now();
|
|
616
|
+
this.saveRecord(record);
|
|
617
|
+
return record;
|
|
618
|
+
}
|
|
619
|
+
finally {
|
|
620
|
+
this.closingOperations.delete(id);
|
|
621
|
+
}
|
|
622
|
+
}));
|
|
623
|
+
}
|
|
375
624
|
async release(principal, id, generation, key) {
|
|
376
625
|
return this.mutate(principal, key, ['release', id, generation], () => this.lifecycle.run(id, async () => {
|
|
377
626
|
const request = this.request(principal, key, ['release', id, generation]);
|
|
378
627
|
if (request.previous)
|
|
379
628
|
return this.replayRequest(principal, id, request.previous);
|
|
629
|
+
this.assertManagementSettled(this.lookup(principal, id));
|
|
380
630
|
if (!this.adapter.release || !this.adapter.runtimePresent)
|
|
381
631
|
integrationError('SESSION_RELEASE_UNSUPPORTED', 'Runtime adapter does not support release', 409);
|
|
382
632
|
if (this.pending.has(id))
|
|
383
633
|
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Launch is in progress', 409);
|
|
384
634
|
const record = await this.get(principal, id);
|
|
635
|
+
this.assertManagementSettled(record);
|
|
385
636
|
assertReleaseGeneration(record, generation);
|
|
386
637
|
if (record.state !== 'released') {
|
|
387
638
|
assertReleaseFacts(record, await this.adapter.inspect(record));
|
|
@@ -443,6 +694,54 @@ export class IntegrationSessions {
|
|
|
443
694
|
const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
|
|
444
695
|
if (!record)
|
|
445
696
|
return;
|
|
697
|
+
if (record.rename_pending) {
|
|
698
|
+
if (this.lifecycle.active(id))
|
|
699
|
+
return;
|
|
700
|
+
try {
|
|
701
|
+
await this.lifecycle.run(id, async () => {
|
|
702
|
+
if (!this.adapter.rename)
|
|
703
|
+
return;
|
|
704
|
+
await this.adapter.rename(record);
|
|
705
|
+
if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
|
|
706
|
+
return;
|
|
707
|
+
record.rename_pending = false;
|
|
708
|
+
this.saveRecord(record);
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
catch { /* Keep the persisted intent for a later get/restart. */ }
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (record.state === 'closed' || record.state === 'closing' || record.close_intent) {
|
|
715
|
+
if (this.lifecycle.active(id))
|
|
716
|
+
return;
|
|
717
|
+
try {
|
|
718
|
+
if (record.state !== 'closed') {
|
|
719
|
+
if (!this.adapter.closeRuntime)
|
|
720
|
+
integrationError('SESSION_CLOSE_UNSUPPORTED', 'Close reconciliation is unavailable', 409);
|
|
721
|
+
await this.adapter.closeRuntime(record, true);
|
|
722
|
+
}
|
|
723
|
+
if (!this.adapter.runtimePresent || await this.adapter.runtimePresent(record))
|
|
724
|
+
integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime exists for a closed or closing session', 409);
|
|
725
|
+
const next = { ...record, state: 'closed', runtime_present: false, terminal_binding: null, close_intent: undefined,
|
|
726
|
+
operation_uncertain: false, error_code: null, startup_input: undefined };
|
|
727
|
+
if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
|
|
728
|
+
return;
|
|
729
|
+
if (JSON.stringify(next) !== JSON.stringify(record))
|
|
730
|
+
this.saveRecord({ ...next, updated_at: Date.now() });
|
|
731
|
+
}
|
|
732
|
+
catch (error) {
|
|
733
|
+
if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
|
|
734
|
+
return;
|
|
735
|
+
// Keep closed terminal, and keep unresolved intent fenced. Never kill on refresh.
|
|
736
|
+
const next = { ...record, runtime_present: null, operation_uncertain: true,
|
|
737
|
+
error_code: typeof error.code === 'string' ? error.code : 'OPERATION_OUTCOME_UNCONFIRMED' };
|
|
738
|
+
if (JSON.stringify(next) !== JSON.stringify(record))
|
|
739
|
+
this.saveRecord({ ...next, updated_at: Date.now() });
|
|
740
|
+
}
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (record.cold_retry_pending && (this.lifecycle.active(id) || this.pending.has(id)))
|
|
744
|
+
return;
|
|
446
745
|
if (record.state === 'released' || record.state === 'releasing' || record.operation_uncertain) {
|
|
447
746
|
if (this.lifecycle.active(id))
|
|
448
747
|
return;
|
|
@@ -483,8 +782,10 @@ export class IntegrationSessions {
|
|
|
483
782
|
if (JSON.stringify(current) !== JSON.stringify(record))
|
|
484
783
|
return;
|
|
485
784
|
const code = error.code;
|
|
486
|
-
|
|
487
|
-
|
|
785
|
+
const errorCode = typeof code === 'string' ? code : 'SESSION_OBSERVATION_FAILED';
|
|
786
|
+
if (record.state !== 'failed' || record.error_code !== errorCode)
|
|
787
|
+
this.saveRecord({ ...record, state: 'failed', error_code: errorCode,
|
|
788
|
+
launch_diagnostics: record.launch_diagnostics ? launchFailure(record.launch_diagnostics, error, errorCode) : undefined, updated_at: Date.now() });
|
|
488
789
|
return;
|
|
489
790
|
}
|
|
490
791
|
const next = { ...record, runtime_present: this.adapter.runtimePresent ? await this.adapter.runtimePresent(record) : observed.exists };
|
|
@@ -521,6 +822,27 @@ export class IntegrationSessions {
|
|
|
521
822
|
next.state = 'failed';
|
|
522
823
|
next.error_code = 'SESSION_BINDING_TIMEOUT';
|
|
523
824
|
}
|
|
825
|
+
if (record.cold_retry_pending) {
|
|
826
|
+
if (next.state === 'ready')
|
|
827
|
+
next.cold_retry_pending = false;
|
|
828
|
+
else if (record.terminal_binding && observed.exists && !observed.running && observed.shell && !observed.nativeId) {
|
|
829
|
+
next.state = 'failed';
|
|
830
|
+
next.error_code = 'SESSION_COLD_RETRY_INTERRUPTED';
|
|
831
|
+
next.cold_retry_pending = false;
|
|
832
|
+
if (next.launch_diagnostics)
|
|
833
|
+
next.launch_diagnostics = launchProgress(next.launch_diagnostics, 'reconciled_shell');
|
|
834
|
+
}
|
|
835
|
+
else if (!observed.exists) {
|
|
836
|
+
next.state = 'failed';
|
|
837
|
+
next.error_code = 'SESSION_COLD_RETRY_RUNTIME_UNCONFIRMED';
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (next.launch_diagnostics) {
|
|
841
|
+
next.launch_diagnostics = { ...next.launch_diagnostics, runtime_exists: observed.exists };
|
|
842
|
+
if (next.state === 'failed' && next.error_code && (record.state !== 'failed' || record.error_code !== next.error_code)) {
|
|
843
|
+
next.launch_diagnostics = launchFailure(next.launch_diagnostics, new CollaborationError(next.error_code, '', 409), next.error_code);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
524
846
|
if (next.startup_input && next.startup_input.state !== 'observed') {
|
|
525
847
|
const condition = next.startup_condition ?? next.profile.startupInput;
|
|
526
848
|
let matched = false;
|
|
@@ -554,6 +876,12 @@ export class IntegrationSessions {
|
|
|
554
876
|
const existing = this.doc.sessions.find(record => record.session_id === id);
|
|
555
877
|
if (!existing)
|
|
556
878
|
return null;
|
|
879
|
+
if (this.closingOperations.has(id))
|
|
880
|
+
return { allowed: false, reason: 'SESSION_OPERATION_IN_PROGRESS' };
|
|
881
|
+
if (existing.state === 'closed')
|
|
882
|
+
return { allowed: false, reason: 'SESSION_CLOSED' };
|
|
883
|
+
if (existing.close_intent || existing.state === 'closing')
|
|
884
|
+
return { allowed: false, reason: 'SESSION_OPERATION_IN_PROGRESS' };
|
|
557
885
|
if (existing.state === 'released' || existing.state === 'releasing' || existing.operation_uncertain)
|
|
558
886
|
return { allowed: false, reason: existing.state === 'released' ? 'SESSION_RELEASED' : 'SESSION_OPERATION_IN_PROGRESS' };
|
|
559
887
|
if (!existing.startup_input)
|
|
@@ -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 = ['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', 'session.release'];
|
|
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', 'session.release', 'session.rename', 'session.close'];
|
|
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 });
|
|
@@ -18,13 +18,19 @@ export function buildBracketedPasteBytes(prompt) {
|
|
|
18
18
|
return `\x1b[200~${normalizePromptForPaste(prompt)}\x1b[201~`;
|
|
19
19
|
}
|
|
20
20
|
/** Serialize TD prompt pairs per PTY. Success only records terminal writes. */
|
|
21
|
-
export function writeBracketedPrompt(target, prompt, assertCurrent) {
|
|
21
|
+
export function writeBracketedPrompt(target, prompt, assertCurrent, progress) {
|
|
22
|
+
progress?.('queue_wait');
|
|
22
23
|
return serializeTerminalInput(target, async () => {
|
|
24
|
+
progress?.('queue_acquired');
|
|
23
25
|
assertCurrent?.();
|
|
26
|
+
progress?.('paste_attempted');
|
|
24
27
|
target.write(buildBracketedPasteBytes(prompt));
|
|
28
|
+
progress?.('paste_written');
|
|
25
29
|
await waitForPromptSubmit();
|
|
26
30
|
assertCurrent?.();
|
|
31
|
+
progress?.('submit_attempted');
|
|
27
32
|
target.write('\r');
|
|
33
|
+
progress?.('submit_written');
|
|
28
34
|
});
|
|
29
35
|
}
|
|
30
36
|
/**
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CollaborationError } from './collaborationProtocol.js';
|
|
2
|
+
import { TerminalInputTargetChangedError } from './terminalInput.js';
|
|
3
|
+
export function beginLaunchDiagnostics(operation_id, generation, kind) {
|
|
4
|
+
const now = Date.now();
|
|
5
|
+
return { operation_id, generation, kind, phase: 'configuration', updated_at: now,
|
|
6
|
+
error_code: null, reason_code: null, paste: 'not_attempted', submit: 'not_attempted',
|
|
7
|
+
runtime_exists: null, steps: [{ phase: 'configuration', at: now }] };
|
|
8
|
+
}
|
|
9
|
+
export function launchProgress(current, phase) {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
return { ...current, phase, updated_at: now, steps: [...current.steps, { phase, at: now }].slice(-24),
|
|
12
|
+
paste: phase === 'paste_attempted' ? 'attempted' : phase === 'paste_written' ? 'write_returned' : current.paste,
|
|
13
|
+
submit: phase === 'submit_attempted' ? 'attempted' : phase === 'submit_written' ? 'write_returned' : current.submit };
|
|
14
|
+
}
|
|
15
|
+
/** Error text/stdout/argv are never copied into durable diagnostics. */
|
|
16
|
+
export function launchFailure(current, error, error_code) {
|
|
17
|
+
const value = error;
|
|
18
|
+
const standard = new Set(['ENOENT', 'EACCES', 'EPERM', 'EIO', 'ETIMEDOUT', 'EPIPE', 'ECONNRESET',
|
|
19
|
+
'TMUX_PANE_CHANGED', 'TMUX_PANE_IN_MODE', 'SESSION_REMOVED', 'SHELL_BACKEND_CHANGED']);
|
|
20
|
+
const reason_code = error instanceof TerminalInputTargetChangedError ? error.code
|
|
21
|
+
: error instanceof CollaborationError && /^[A-Z][A-Z0-9_]{0,79}$/.test(error.code) ? error.code
|
|
22
|
+
: typeof value?.code === 'string' && standard.has(value.code) ? value.code
|
|
23
|
+
: typeof value?.message === 'string' && standard.has(value.message) ? value.message : 'UNCLASSIFIED_LAUNCH_ERROR';
|
|
24
|
+
return { ...current, updated_at: Date.now(), error_code, reason_code,
|
|
25
|
+
...(error instanceof TerminalInputTargetChangedError ? { target_change: error.evidence } : {}) };
|
|
26
|
+
}
|
|
@@ -50,6 +50,10 @@ export function assertReleaseFacts(record, facts) {
|
|
|
50
50
|
export function assertMessageRuntime(record) {
|
|
51
51
|
if (!record)
|
|
52
52
|
return;
|
|
53
|
+
if (record.state === 'closed')
|
|
54
|
+
fail('SESSION_CLOSED', 'Session was explicitly closed; it cannot be sent to or restored');
|
|
55
|
+
if (record.state === 'closing')
|
|
56
|
+
fail('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress');
|
|
53
57
|
if (record.state === 'released')
|
|
54
58
|
fail('SESSION_RELEASED', 'Runtime was released; explicitly restore this session before sending');
|
|
55
59
|
if (record.state === 'releasing')
|