termdock 1.4.309 → 1.4.311
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +3 -1
- package/README.md +3 -1
- package/THIRD_PARTY_NOTICES.md +30 -0
- package/dist/client/assets/{App-ggIA_xqR.js → App-ChS2-lkz.js} +62 -55
- 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-Cmpmp6FS.css → ArchitecturePanel-B_BDrrfR.css} +1 -1
- package/dist/client/assets/ArchitecturePanel-B_BDrrfR.css.br +0 -0
- package/dist/client/assets/ArchitecturePanel-B_BDrrfR.css.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-JtjyyJoW.js +9 -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-D1Puc7B3.js → ChangeWalkthroughPanel-BlQ5-VPp.js} +2 -2
- 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 +1 -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 +2 -0
- package/dist/client/assets/{ComputerControlView-D5Lw9sNA.js → ComputerControlView-TAKDbBUl.js} +2 -2
- 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-DYJrGfiG.js → DagPlayground-CR4uDFOx.js} +1 -1
- 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-5zdcFW3z.js → DiffLab-BqeHMDOy.js} +1 -1
- 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-BBBC_NjV.js → DiffReview-DqrOcRfP.js} +1 -1
- 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-CbhosFSB.js → DiffReviewLab-CEYpbrL6.js} +2 -2
- 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-BuQwFQ4V.js → DiffViewer-F-uQSmhG.js} +8 -8
- 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-nO2VmqdP.js → ModelPreview-KmXFkgij.js} +1 -1
- 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 +1677 -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-yi0K8GDG.js → abnfDiagram-VCTEODGH-CAMk1C0N.js} +1 -1
- 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-B6FdOF6K.js → app-CHxLSuGQ.js} +4 -4
- 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-_nLI_-XZ.js → arc-CYG_-1vC.js} +1 -1
- 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-CikrA78O.js → architectureDiagram-5GKGNRK7-BqHzezLR.js} +1 -1
- 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-CWJq6qJ7.js → blockDiagram-I7D4REHJ-D6GWRO_Z.js} +1 -1
- 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-gzPzLGvs.js → c4Diagram-7LVT6UL2-CutmGIGb.js} +1 -1
- 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 +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CfX9l18E.js → chunk-2Q5K7J3B-DwiUpGFu.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-JSV1yrXM.js → chunk-5VM5RSS4-C35gLPSH.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-CQ0LXeap.js → chunk-F27PBJKO-CNptP19P.js} +1 -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-CJOEPkK9.js → chunk-IMKFNOWR-DHdpB9A0.js} +1 -1
- 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-JWPE2WC7-Dpp7Xu_E.js → chunk-JWPE2WC7-CrKSOzdE.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-9hDa1b8z.js → chunk-POPQ4Y6H-CiZGLRSk.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-BskkG9gg.js → chunk-SVP7TREG-B70pX8OB.js} +1 -1
- 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-DyzuP-9I.js → chunk-TICWLB2K-Ba1mI99F.js} +1 -1
- 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/{chunk-XXDRQBXY-C31_1i6z.js → chunk-XXDRQBXY-DmKIl18h.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-CS4V_MQS.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CS4V_MQS.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-Bm-ESDOc.js → cose-bilkent-JH36ORCC-C-NMDUHW.js} +1 -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-DbFWAPvX.js → cynefin-OW5HDTMX-CZgEc1ab.js} +1 -1
- 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-Ca0IKRdH.js → cynefinDiagram-5FMLGOSQ-CHQeSNm2.js} +1 -1
- 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-D_5uEMjJ.js → dagre-GXQ25YYZ-B_jkMdPS.js} +1 -1
- 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-DWVpndRP.js → diagram-S7CK7UJ4-nv6Lnsrp.js} +1 -1
- 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-DmYTya3w.js → diagram-UQ7AKVKN-BZf2fzaA.js} +1 -1
- 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-BEA6kqNj.js → diagram-VSXAHHWV-CxL0_BH8.js} +1 -1
- 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-CU9vP0P0.js → diagram-VX7I27RA-Dm9MqpIE.js} +1 -1
- 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-B_GvE2g-.js → diagram-Z3DM3KII-BIfTa7P5.js} +1 -1
- 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-BLrPQuLE.js → ebnfDiagram-PWID7BFC-D4XhCDFS.js} +1 -1
- 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-DlXgoyZ-.js → erDiagram-RLTQ6QDP-Dxd48dXC.js} +1 -1
- 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-fPHWxEDZ.js → flowDiagram-HODETNUW-BXBMsEmE.js} +1 -1
- 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-B8MOv6ug.js → ganttDiagram-EL5Y4UJY-CBfDd-KZ.js} +1 -1
- 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-JW8vcVRm.js → gestureArbiter-DXLmNGli.js} +1 -1
- 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-lH9gSoFx.js → gitGraphDiagram-WWUBYQGX-DtLM68fN.js} +1 -1
- 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 +1 -0
- package/dist/client/assets/index-KuPaZyuZ.css.br +0 -0
- package/dist/client/assets/{index-CNY7CTVa.css.gz → index-KuPaZyuZ.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-CSG29Ty_.js → infoDiagram-27XIBGKW-FRhqdJvW.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-CcwSE5qV.js → ishikawaDiagram-5VMMS53U-DAHBvAZ-.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DAHBvAZ-.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DAHBvAZ-.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-CXFUeP2c.js → journeyDiagram-3NMN7TZE-CVuWuL3Z.js} +1 -1
- 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-KEHwljd2.js → kanban-definition-UXKFOSKX-ByQSUVJV.js} +1 -1
- 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-DqYx0MnO.js → layout-Bb3Nb1c4.js} +1 -1
- 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-BnG3XaJW.js → linear-DHMMQlOo.js} +1 -1
- 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-Ce00rdM6.js → mermaid.core-BYfniK0H.js} +5 -5
- 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-D0hOW4SY.js → mindmap-definition-YA3MSWOX-EDLD5AyH.js} +1 -1
- 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 +2 -0
- package/dist/client/assets/passwordBootstrap-DCrtirwT.js.br +0 -0
- package/dist/client/assets/{passwordBootstrap-Bncb8qF_.js.gz → passwordBootstrap-DCrtirwT.js.gz} +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-UKp9t91x.js → pegDiagram-XKGWAZYB-BHYhkqJN.js} +1 -1
- 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-Dif97wbH.js → pieDiagram-E7YTZNPT-BUIJlswC.js} +1 -1
- 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-BPyHtH91.js → quadrantDiagram-AXDQQJYC-D8Im-7yC.js} +1 -1
- 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-Wleq9LmS.js → railroadDiagram-O6MQD6OU-D7n6z2G1.js} +1 -1
- 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-CobFMSUs.js → rdpSession-DJlNIbVk.js} +1 -1
- 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-bZ0xp-v2.js → referenceLongPress-DFSrssSr.js} +1 -1
- 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-BL4pp0Ta.js → requirementDiagram-BXWQKSXE-Ki0rR-F7.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Ki0rR-F7.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Ki0rR-F7.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CV1cKx37.js → sankeyDiagram-P5KCCOFB-36NmMqsW.js} +1 -1
- 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-BF2InLwV.js → sequenceDiagram-WJ2MYXX4-5vsPuFyO.js} +1 -1
- 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-CldUyStR.js → sizeCapture-INFHLROL-DbAulwBg.js} +1 -1
- 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/{sparkles-Cg-yPdE2.js → sparkles-CapLTKAs.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-CByehbEd.js → stateDiagram-D77RDMKH-Bgwe0g5S.js} +1 -1
- 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 +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH--1_7YTL4.js → swimlanes-42K2YHIH-COGAWe-g.js} +1 -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 +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-CXfXJFK6.js → timeline-definition-24CTP7MA-C4gt5z68.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-C4gt5z68.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-C4gt5z68.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-CbMRJ6sx.js → triangle-alert-xPHw25jD.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-byr6UQpL.js → vennDiagram-4TSXK5OY-CIEXh9oD.js} +1 -1
- 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-ivJAy00d.js → videoCompression-CUkCS2-q.js} +1 -1
- 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-FJduk-7s.js → wardleyDiagram-VM6X3IG4-gQhcW1vd.js} +1 -1
- 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-Ct1fBPFS.js → xychartDiagram-S5SC5T6Z-BmIcdejz.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmIcdejz.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BmIcdejz.js.gz +0 -0
- package/dist/client/index.html +2 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/agent/collaborationCli.js +6 -4
- package/dist/server/agent/collaborationDeliveryWorker.js +3 -97
- package/dist/server/agent/collaborationTmuxDelivery.js +23 -51
- package/dist/server/agent/integrationCli.js +23 -0
- package/dist/server/agent/integrationServer.js +7 -0
- package/dist/server/agent/integrationSessions.js +24 -1
- package/dist/server/agent/promptDelivery.js +20 -7
- package/dist/server/agent/sessionLifecycle.js +2 -2
- package/dist/server/architecture/cli.js +320 -0
- package/dist/server/architecture/document.js +328 -0
- package/dist/server/architecture/documentDiff.js +39 -0
- package/dist/server/architecture/fieldMutation.js +52 -0
- package/dist/server/architecture/flowchart.js +62 -0
- package/dist/server/architecture/mermaidDiff.js +85 -0
- package/dist/server/architecture/routes.js +117 -0
- package/dist/server/architecture/store.js +502 -0
- package/dist/server/cli.js +7 -1
- package/dist/server/entry.js +2 -0
- package/dist/server/federation/accessPolicy.js +9 -1
- package/dist/server/routes/terminal.js +8 -12
- package/docs/integrations.md +45 -1
- package/package.json +3 -1
- package/runtime-manifest.json +4 -4
- 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-Cmpmp6FS.css.br +0 -0
- package/dist/client/assets/ArchitecturePanel-Cmpmp6FS.css.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-CoBspW_C.js +0 -12
- 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-D1Puc7B3.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-D1Puc7B3.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-BPyK5Xs8.js +0 -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 +0 -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-DYJrGfiG.js.br +0 -0
- package/dist/client/assets/DagPlayground-DYJrGfiG.js.gz +0 -0
- 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-BBBC_NjV.js.br +0 -0
- package/dist/client/assets/DiffReview-BBBC_NjV.js.gz +0 -0
- 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-BuQwFQ4V.js.br +0 -0
- package/dist/client/assets/DiffViewer-BuQwFQ4V.js.gz +0 -0
- 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-BoNzpS2K.js +0 -1677
- 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-yi0K8GDG.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-yi0K8GDG.js.gz +0 -0
- 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-_nLI_-XZ.js.br +0 -0
- package/dist/client/assets/arc-_nLI_-XZ.js.gz +0 -0
- 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-CWJq6qJ7.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CWJq6qJ7.js.gz +0 -0
- 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 +0 -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-CJOEPkK9.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CJOEPkK9.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BskkG9gg.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BskkG9gg.js.gz +0 -0
- 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/classDiagram-ZZMXUADV-BnmZv6Ns.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BnmZv6Ns.js +0 -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-DbFWAPvX.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DbFWAPvX.js.gz +0 -0
- 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-D_5uEMjJ.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-D_5uEMjJ.js.gz +0 -0
- 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-DmYTya3w.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DmYTya3w.js.gz +0 -0
- 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-CU9vP0P0.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CU9vP0P0.js.gz +0 -0
- 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-BLrPQuLE.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-BLrPQuLE.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DlXgoyZ-.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DlXgoyZ-.js.gz +0 -0
- 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-B8MOv6ug.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-B8MOv6ug.js.gz +0 -0
- 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-lH9gSoFx.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-lH9gSoFx.js.gz +0 -0
- package/dist/client/assets/index-CNY7CTVa.css +0 -1
- package/dist/client/assets/index-CNY7CTVa.css.br +0 -0
- 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-CXFUeP2c.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CXFUeP2c.js.gz +0 -0
- 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-DqYx0MnO.js.br +0 -0
- package/dist/client/assets/layout-DqYx0MnO.js.gz +0 -0
- 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-Ce00rdM6.js.br +0 -0
- package/dist/client/assets/mermaid.core-Ce00rdM6.js.gz +0 -0
- 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-Bncb8qF_.js +0 -2
- package/dist/client/assets/passwordBootstrap-Bncb8qF_.js.br +0 -0
- 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-Dif97wbH.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-Dif97wbH.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPyHtH91.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPyHtH91.js.gz +0 -0
- 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-CobFMSUs.js.br +0 -0
- package/dist/client/assets/rdpSession-CobFMSUs.js.gz +0 -0
- 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-BL4pp0Ta.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BL4pp0Ta.js.gz +0 -0
- 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-BF2InLwV.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BF2InLwV.js.gz +0 -0
- 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/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 +0 -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 +0 -8
- 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/vennDiagram-4TSXK5OY-byr6UQpL.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-byr6UQpL.js.gz +0 -0
- 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-FJduk-7s.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-FJduk-7s.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Ct1fBPFS.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Ct1fBPFS.js.gz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { plainCollaborationSnapshot } from './collaborationText.js';
|
|
2
|
-
import { normalizePromptForPaste } from './promptDelivery.js';
|
|
2
|
+
import { normalizePromptForPaste, waitForPromptSubmit } from './promptDelivery.js';
|
|
3
3
|
const TMUX_KEY_NAMES = {
|
|
4
4
|
enter: 'Enter', escape: 'Escape', space: 'Space', left: 'Left', right: 'Right', up: 'Up', down: 'Down',
|
|
5
5
|
};
|
|
@@ -19,26 +19,9 @@ const APPROVAL_DIALOG_PATTERNS = [
|
|
|
19
19
|
/\b1\.\s*是\b/,
|
|
20
20
|
/允许.*执行|确认.*执行/i,
|
|
21
21
|
];
|
|
22
|
-
/** Agent TUIs collapse pasted input in the input box to a marker line like
|
|
23
|
-
* "[Pasted text #3 +42 lines]". While the paste sits unsubmitted the marker
|
|
24
|
-
* stays on screen; a submitted paste clears the box and only the transcript
|
|
25
|
-
* holds the content. Session-unique #N lets us diff screen captures. */
|
|
26
|
-
const PASTE_MARKER_PATTERN = /\[Pasted text #(\d+)/g;
|
|
27
22
|
export function detectApprovalDialog(content) {
|
|
28
23
|
return APPROVAL_DIALOG_PATTERNS.some((pattern) => pattern.test(content));
|
|
29
24
|
}
|
|
30
|
-
/** Paste marker sequence numbers visible in a screen capture. */
|
|
31
|
-
export function extractPasteMarkerNumbers(content) {
|
|
32
|
-
return new Set([...content.matchAll(PASTE_MARKER_PATTERN)].map((match) => Number(match[1])));
|
|
33
|
-
}
|
|
34
|
-
/** True when `after` shows a paste marker that was not in `before`. Diffing
|
|
35
|
-
* prevents a recovery Enter from submitting a stale paste that predates this
|
|
36
|
-
* delivery (or someone else's draft): we only ever submit what we just put
|
|
37
|
-
* there, at most once per delivery. */
|
|
38
|
-
export function hasNewPasteMarker(after, before) {
|
|
39
|
-
const beforeNumbers = extractPasteMarkerNumbers(before);
|
|
40
|
-
return [...extractPasteMarkerNumbers(after)].some((number) => !beforeNumbers.has(number));
|
|
41
|
-
}
|
|
42
25
|
async function assertSamePane(run, pane) {
|
|
43
26
|
const identity = (await run(['display-message', '-p', '-t', pane.paneId,
|
|
44
27
|
'#{pid}:#{session_id}:#{pane_id}:#{pane_pid}'])).trim();
|
|
@@ -48,15 +31,19 @@ async function assertSamePane(run, pane) {
|
|
|
48
31
|
/** Unique-per-process buffer name so concurrent deliveries to different panes
|
|
49
32
|
* never share (or clobber) a buffer. */
|
|
50
33
|
let bufferSequence = 0;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
const paneWrites = new Map();
|
|
35
|
+
/** Serialize TD paste/submit pairs for this exact runtime pane. */
|
|
36
|
+
export function writeCollaborationTmuxPane(run, pane, prompt, stdin) {
|
|
37
|
+
const key = `${pane.serverPid}:${pane.sessionId}:${pane.paneId}:${pane.panePid}`;
|
|
38
|
+
const previous = paneWrites.get(key) ?? Promise.resolve();
|
|
39
|
+
const operation = previous.catch(() => undefined).then(() => writeTmuxPrompt(run, pane, prompt, stdin))
|
|
40
|
+
.finally(() => { if (paneWrites.get(key) === operation)
|
|
41
|
+
paneWrites.delete(key); });
|
|
42
|
+
paneWrites.set(key, operation);
|
|
43
|
+
return operation;
|
|
44
|
+
}
|
|
45
|
+
async function writeTmuxPrompt(run, pane, prompt,
|
|
46
|
+
/** Body travels on stdin so tmux cannot parse its semicolons/backslashes. */
|
|
60
47
|
stdin) {
|
|
61
48
|
await assertSamePane(run, pane);
|
|
62
49
|
// A fixed pane target is independent of the current window, keyboard focus
|
|
@@ -77,13 +64,8 @@ stdin) {
|
|
|
77
64
|
// every tmux version.
|
|
78
65
|
const buffer = `termdock-collab-${process.pid}-${bufferSequence++}`;
|
|
79
66
|
try {
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
// client's paste can interleave between our text and our submit CR
|
|
83
|
-
// (measured: one contiguous block, 0ms apart, versus two invocations
|
|
84
|
-
// ~14ms apart). A failing step stops the rest — verified on 3.4 and 3.7 —
|
|
85
|
-
// which is the safe direction: a failed text paste is never followed by a
|
|
86
|
-
// bare CR into whatever the input box already held.
|
|
67
|
+
// Paste once, then send one unbracketed CR after 50ms. No screen parsing,
|
|
68
|
+
// Agent-specific recovery, consumption confirmation or additional Enter.
|
|
87
69
|
await stdin([
|
|
88
70
|
// The body arrives on stdin, not argv: it is user content, and in a
|
|
89
71
|
// `\;` chain argv is a language where `;` and `\` mean something.
|
|
@@ -91,13 +73,17 @@ stdin) {
|
|
|
91
73
|
// -r keeps LF as LF rather than the separator default of CR. The
|
|
92
74
|
// normalizer already folded every line break to CR, so no LF is left
|
|
93
75
|
// for it to rewrite — the flag is insurance, not the mechanism.
|
|
94
|
-
'paste-buffer', '-p', '-r', '-d', '-b', buffer, '-t', pane.paneId,
|
|
76
|
+
'paste-buffer', '-p', '-r', '-d', '-b', buffer, '-t', pane.paneId,
|
|
77
|
+
], normalizePromptForPaste(prompt));
|
|
78
|
+
await waitForPromptSubmit();
|
|
79
|
+
await assertSamePane(run, pane);
|
|
80
|
+
await run([
|
|
95
81
|
// The submit key rides outside the paste block: inside it, an editor
|
|
96
82
|
// inserts a pasted CR as text instead of acting on it. Pasting the bare
|
|
97
83
|
// CR (no -p) keeps the key in the same mode-proof channel as the text.
|
|
98
84
|
'set-buffer', '-b', buffer, '--', '\r', ';',
|
|
99
85
|
'paste-buffer', '-d', '-b', buffer, '-t', pane.paneId,
|
|
100
|
-
]
|
|
86
|
+
]);
|
|
101
87
|
}
|
|
102
88
|
finally {
|
|
103
89
|
// -d consumed the buffer on the happy path; this sweeps up after a failed
|
|
@@ -139,21 +125,7 @@ export async function approveCollaborationDialog(run, pane) {
|
|
|
139
125
|
await sendTmuxPaneKey(run, pane, 'enter');
|
|
140
126
|
return true;
|
|
141
127
|
}
|
|
142
|
-
/**
|
|
143
|
-
* turn and is still sitting unsubmitted in the input box. Only acts on
|
|
144
|
-
* differential evidence — a paste marker that appeared after the write —
|
|
145
|
-
* never on pre-existing stale markers, and returns whether Enter was sent.
|
|
146
|
-
* Committing the whole input buffer is safe: each delivery is written once,
|
|
147
|
-
* so each marker's content enters the transcript exactly once. */
|
|
148
|
-
export async function recoverStuckPaste(run, pane, baseline) {
|
|
149
|
-
const viewport = await captureTmuxPaneText(run, pane);
|
|
150
|
-
if (!hasNewPasteMarker(viewport, baseline))
|
|
151
|
-
return false;
|
|
152
|
-
await sendTmuxPaneKey(run, pane, 'enter');
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
/** History-inclusive pane text (scrollback + viewport) used to confirm a
|
|
156
|
-
* delivery was actually rendered by the agent, not wiped by a boot clear. */
|
|
128
|
+
/** History-inclusive terminal observation, without inferring consumption. */
|
|
157
129
|
export async function captureTmuxPaneHistory(run, pane, lines = 800, rawOutput = false) {
|
|
158
130
|
await assertSamePane(run, pane);
|
|
159
131
|
if (!Number.isInteger(lines) || lines < 1 || lines > 10000)
|
|
@@ -8,6 +8,17 @@ import { COLLAB_HELP, executeCollaborationCommand, duration } from './collaborat
|
|
|
8
8
|
import { getTermdockVersion } from '../utils/version.js';
|
|
9
9
|
export const INTEGRATION_HELP = `td integration — local scoped integration administration
|
|
10
10
|
groups | list
|
|
11
|
+
clear-startup-input <TD-session-id> --generation <N>
|
|
12
|
+
Administrator removes this session's saved screen conditions and disables
|
|
13
|
+
inheritance on later restores; original identity/launch/history are preserved.
|
|
14
|
+
Pending messages may then use the ordinary delivery worker; delivered bodies
|
|
15
|
+
are never replayed. No Agent restart, resize, RPC or readiness claim.
|
|
16
|
+
The generation increments once; read session get for the new generation and
|
|
17
|
+
startup_input_disabled=true. Repeating with the old generation is rejected.
|
|
18
|
+
Minimum CLI/running service 1.4.310; session_startup_input_clear=true.
|
|
19
|
+
Errors: SESSION_STARTUP_INPUT_CLEAR_UNSUPPORTED, INVALID_SESSION_GENERATION,
|
|
20
|
+
SESSION_GENERATION_MISMATCH, SESSION_OPERATION_IN_PROGRESS,
|
|
21
|
+
INTEGRATION_SESSION_NOT_FOUND. Profile policy update alone keeps old snapshots.
|
|
11
22
|
resume-configuration <TD-session-id> (read current/recorded fingerprints; no mutation)
|
|
12
23
|
confirm-resume <TD-session-id> --generation <N> --fingerprint <sha256>
|
|
13
24
|
Administrator explicitly authorizes the current launcher/plugin recovery semantics.
|
|
@@ -72,6 +83,18 @@ export async function runIntegrationAdmin(argv, port, adminToken, write) {
|
|
|
72
83
|
return 0;
|
|
73
84
|
}
|
|
74
85
|
const socketPath = integrationSocketPath(port);
|
|
86
|
+
if (action === 'clear-startup-input') {
|
|
87
|
+
const id = argv[1];
|
|
88
|
+
if (argv.length !== 4 || !id || !/^[a-zA-Z0-9._-]{1,80}$/.test(id) || argv[2] !== '--generation'
|
|
89
|
+
|| !/^[1-9][0-9]*$/.test(argv[3]) || !Number.isSafeInteger(Number(argv[3]))) {
|
|
90
|
+
throw new Error('Usage: td integration clear-startup-input <TD-session-id> --generation <positive integer>');
|
|
91
|
+
}
|
|
92
|
+
const capabilities = parsed(await request(socketPath, 'GET', '/admin/capabilities', undefined, headers(undefined, adminToken)));
|
|
93
|
+
if (capabilities.session_startup_input_clear !== true)
|
|
94
|
+
throw new CollaborationError('SESSION_STARTUP_INPUT_CLEAR_UNSUPPORTED', 'CLI and running service must be at least 1.4.310', 409);
|
|
95
|
+
write(JSON.stringify(parsed(await request(socketPath, 'POST', `/admin/sessions/${encodeURIComponent(id)}/startup-input/clear`, { generation: Number(argv[3]) }, headers(undefined, adminToken)))));
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
75
98
|
if (action === 'resume-configuration' || action === 'confirm-resume') {
|
|
76
99
|
const id = argv[1];
|
|
77
100
|
if (!id || !/^[a-zA-Z0-9._-]{1,80}$/.test(id))
|
|
@@ -73,6 +73,12 @@ export class IntegrationRuntime {
|
|
|
73
73
|
app.get('/admin/sessions/:id/restore-diagnostics', run(req => { admin(req); return this.sessions.restoreDiagnostics(req.params.id); }));
|
|
74
74
|
app.get('/admin/sessions/:id/resume-configuration', run(async (req) => { admin(req); return this.sessions.resumeConfiguration(req.params.id); }));
|
|
75
75
|
app.post('/admin/sessions/:id/resume-configuration', run(async (req) => { admin(req); return { session: publicIntegrationSession(await this.sessions.confirmResumeConfiguration(req.params.id, req.body?.generation, req.body?.fingerprint)) }; }));
|
|
76
|
+
app.post('/admin/sessions/:id/startup-input/clear', run(async (req) => {
|
|
77
|
+
admin(req);
|
|
78
|
+
const session = await this.sessions.clearStartupInput(req.params.id, req.body?.generation);
|
|
79
|
+
this.sync();
|
|
80
|
+
return { session: publicIntegrationSession(session) };
|
|
81
|
+
}));
|
|
76
82
|
app.get('/admin/principals', run(req => { admin(req); return { integrations: this.store.policies() }; }));
|
|
77
83
|
app.post('/admin/principals', run(req => { admin(req); this.group(req.body?.groupId); const provisioned = this.store.provision(req.body); try {
|
|
78
84
|
this.sync();
|
|
@@ -217,6 +223,7 @@ export class IntegrationRuntime {
|
|
|
217
223
|
idempotent_session_create: true, exact_session_restore: true, external_validation: false,
|
|
218
224
|
startup_input_conditions: true, session_runtime_release: true, stable_session_identity: true, session_lifecycle_generation: true,
|
|
219
225
|
session_resume_configuration: true, session_lifecycle_min_version: '1.4.309',
|
|
226
|
+
session_startup_input_clear: true, session_startup_input_clear_min_version: '1.4.310',
|
|
220
227
|
integration_policy_update: true,
|
|
221
228
|
session_restore_diagnostics: true,
|
|
222
229
|
native_identity_linux_flock_owner: process.platform === 'linux',
|
|
@@ -14,6 +14,8 @@ export function integrationLaunchCommand(record, restore) {
|
|
|
14
14
|
return `cd -- ${quote(record.cwd)} && ${[record.profile.executable, ...args].map(quote).join(' ')}`;
|
|
15
15
|
}
|
|
16
16
|
function startupInput(record, now) {
|
|
17
|
+
if (record.startup_input_disabled)
|
|
18
|
+
return undefined;
|
|
17
19
|
const condition = record.startup_condition ?? record.profile.startupInput;
|
|
18
20
|
return condition ? { state: 'pending', deadline: now + (condition.timeoutMs ?? 120000), matched_since: null, observed_at: null } : undefined;
|
|
19
21
|
}
|
|
@@ -308,7 +310,7 @@ export class IntegrationSessions {
|
|
|
308
310
|
record.deadline = Date.now() + this.bindingTimeout;
|
|
309
311
|
record.updated_at = Date.now();
|
|
310
312
|
record.restore_diagnostics = undefined;
|
|
311
|
-
if (!record.profile.startupInput && !record.startup_condition)
|
|
313
|
+
if (!record.startup_input_disabled && !record.profile.startupInput && !record.startup_condition)
|
|
312
314
|
record.startup_condition = structuredClone(principal.launchProfiles.find(profile => profile.id === record.launch_profile)?.startupInput);
|
|
313
315
|
record.startup_input = startupInput(record, Date.now());
|
|
314
316
|
this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
|
|
@@ -332,6 +334,27 @@ export class IntegrationSessions {
|
|
|
332
334
|
return { session_id: id, generation: record.generation ?? 1, recorded_fingerprint: record.resume_configuration_fingerprint ?? null,
|
|
333
335
|
current_fingerprint: await resumeConfigurationFingerprint(record, this.adapter), confirmation_required: !record.resume_configuration_fingerprint };
|
|
334
336
|
}
|
|
337
|
+
async clearStartupInput(id, generation) {
|
|
338
|
+
return this.lifecycle.run(id, async () => {
|
|
339
|
+
const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
|
|
340
|
+
if (!record)
|
|
341
|
+
return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Recovery record does not exist', 404);
|
|
342
|
+
assertReleaseGeneration(record, generation);
|
|
343
|
+
if (this.pending.has(id) || record.operation_uncertain || ['starting', 'restoring', 'binding_pending', 'releasing'].includes(record.state)) {
|
|
344
|
+
integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current lifecycle operation before clearing startup input conditions', 409);
|
|
345
|
+
}
|
|
346
|
+
if (record.startup_input_disabled && !record.profile.startupInput && !record.startup_condition && !record.startup_input)
|
|
347
|
+
return record;
|
|
348
|
+
delete record.profile.startupInput;
|
|
349
|
+
delete record.startup_condition;
|
|
350
|
+
delete record.startup_input;
|
|
351
|
+
record.startup_input_disabled = true;
|
|
352
|
+
record.generation = generation + 1;
|
|
353
|
+
record.updated_at = Date.now();
|
|
354
|
+
this.saveRecord(record);
|
|
355
|
+
return record;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
335
358
|
async confirmResumeConfiguration(id, generation, fingerprint) {
|
|
336
359
|
return this.lifecycle.run(id, async () => {
|
|
337
360
|
const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
|
|
@@ -8,13 +8,26 @@
|
|
|
8
8
|
export function normalizePromptForPaste(prompt) {
|
|
9
9
|
return prompt.replace(/\r\n|\r|\n/g, '\r').replace(/\x1b/g, '␛');
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export function
|
|
17
|
-
return `\x1b[200~${normalizePromptForPaste(prompt)}\x1b[201
|
|
11
|
+
/** Separate the paste and its single unbracketed CR by 50ms. */
|
|
12
|
+
export const PROMPT_SUBMIT_DELAY_MS = 50;
|
|
13
|
+
export function waitForPromptSubmit() {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, PROMPT_SUBMIT_DELAY_MS));
|
|
15
|
+
}
|
|
16
|
+
export function buildBracketedPasteBytes(prompt) {
|
|
17
|
+
return `\x1b[200~${normalizePromptForPaste(prompt)}\x1b[201~`;
|
|
18
|
+
}
|
|
19
|
+
const promptWrites = new WeakMap();
|
|
20
|
+
/** Serialize TD prompt pairs per PTY. Success only records terminal writes. */
|
|
21
|
+
export function writeBracketedPrompt(target, prompt) {
|
|
22
|
+
const previous = promptWrites.get(target) ?? Promise.resolve();
|
|
23
|
+
const operation = previous.catch(() => undefined).then(async () => {
|
|
24
|
+
target.write(buildBracketedPasteBytes(prompt));
|
|
25
|
+
await waitForPromptSubmit();
|
|
26
|
+
target.write('\r');
|
|
27
|
+
}).finally(() => { if (promptWrites.get(target) === operation)
|
|
28
|
+
promptWrites.delete(target); });
|
|
29
|
+
promptWrites.set(target, operation);
|
|
30
|
+
return operation;
|
|
18
31
|
}
|
|
19
32
|
/**
|
|
20
33
|
* Process detection and hook events are independent Agent signals. A target is
|
|
@@ -33,9 +33,9 @@ export class SessionLifecycleCoordinator {
|
|
|
33
33
|
}
|
|
34
34
|
export function assertReleaseGeneration(record, generation) {
|
|
35
35
|
if (!Number.isSafeInteger(generation) || Number(generation) < 1)
|
|
36
|
-
fail('INVALID_SESSION_GENERATION', '
|
|
36
|
+
fail('INVALID_SESSION_GENERATION', 'Operation requires the generation returned by session get');
|
|
37
37
|
if (generation !== (record.generation ?? 1))
|
|
38
|
-
fail('SESSION_GENERATION_MISMATCH', 'Session generation changed; read its current state before
|
|
38
|
+
fail('SESSION_GENERATION_MISMATCH', 'Session generation changed; read its current state before retrying');
|
|
39
39
|
}
|
|
40
40
|
export function assertReleaseFacts(record, facts) {
|
|
41
41
|
if (!record.agent_native_session_id)
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { updateArchitectureField } from './fieldMutation.js';
|
|
5
|
+
import { ARCHITECTURE_FIELDS, ARCHITECTURE_FILE, analysisFile, architectureSourceDiagram, buildArchitecturePrompt, buildOmmScanPrompt, parseArchitecture } from './document.js';
|
|
6
|
+
import { ArchitectureStore } from './store.js';
|
|
7
|
+
import { parseFlowchart } from './flowchart.js';
|
|
8
|
+
import { diffMermaid } from './mermaidDiff.js';
|
|
9
|
+
import { diffArchitecture } from './documentDiff.js';
|
|
10
|
+
export const ARCHITECTURE_HELP = `Termdock architecture — recursive code architecture documents
|
|
11
|
+
Usage: td architecture <command> [--project <directory>] [--file <map.json>] [--format native|omm]
|
|
12
|
+
prompt [--language en|zh] Print the recursive analysis instructions
|
|
13
|
+
setup [claude|codex|cursor|openclaw|antigravity] [--teardown]
|
|
14
|
+
init | list | status Initialize or inspect project maps
|
|
15
|
+
tree [perspective/element] Browse the recursive document tree
|
|
16
|
+
read <element> <field> Read a field
|
|
17
|
+
write <element> <field> <text|-> Write a field (stdin with -)
|
|
18
|
+
show <element> Read all fields and metadata
|
|
19
|
+
delete <element> Delete that element and descendants
|
|
20
|
+
save <json|-> Validate and atomically save a native map, retaining history
|
|
21
|
+
validate [element] Check diagrams, documents and references
|
|
22
|
+
refs <element> Show incoming/outgoing and cross-perspective references
|
|
23
|
+
diff [element] | history Show changes and previous versions
|
|
24
|
+
config language [en|zh|...] Read/write the .omm content language
|
|
25
|
+
export [--format omm] Export native JSON or a portable .omm file bundle
|
|
26
|
+
import <json|-> Import a native map or a .omm file bundle
|
|
27
|
+
view Print the native Termdock viewer link
|
|
28
|
+
Fields: description, diagram, context, constraint, concern, todo, note.
|
|
29
|
+
Examples: td architecture prompt --project .
|
|
30
|
+
td architecture write --format omm overall-architecture/auth description -
|
|
31
|
+
td architecture save --file .termdock/architecture.json -`;
|
|
32
|
+
function elementPath(view, node) {
|
|
33
|
+
if (!node)
|
|
34
|
+
return view.id;
|
|
35
|
+
if (node.documentPath)
|
|
36
|
+
return node.documentPath;
|
|
37
|
+
const parts = [node.id];
|
|
38
|
+
let parent = node.parentId;
|
|
39
|
+
while (parent) {
|
|
40
|
+
parts.unshift(parent);
|
|
41
|
+
parent = view.nodes.find(item => item.id === parent)?.parentId;
|
|
42
|
+
}
|
|
43
|
+
return [view.id, ...parts].join('/');
|
|
44
|
+
}
|
|
45
|
+
function target(document, element) {
|
|
46
|
+
const [perspective, ...parts] = element.split('/');
|
|
47
|
+
const view = document.perspectives.find(view => view.id === perspective);
|
|
48
|
+
if (!view)
|
|
49
|
+
throw new Error(`Perspective not found: ${perspective}`);
|
|
50
|
+
let node;
|
|
51
|
+
for (const [index, part] of parts.entries()) {
|
|
52
|
+
const id = document.origin === 'omm' ? `e_${createHash('sha256').update([perspective, ...parts.slice(0, index + 1)].join('/')).digest('hex').slice(0, 20)}` : part;
|
|
53
|
+
const next = view.nodes.find(item => item.id === id && item.parentId === node?.id);
|
|
54
|
+
if (!next)
|
|
55
|
+
throw new Error(`Element not found: ${element}`);
|
|
56
|
+
node = next;
|
|
57
|
+
}
|
|
58
|
+
return { view, node, value: node ?? view };
|
|
59
|
+
}
|
|
60
|
+
export async function runArchitectureCli(args, io = { write: value => process.stdout.write(`${value}\n`), stdin: async () => { let text = ''; for await (const chunk of process.stdin) {
|
|
61
|
+
text += String(chunk);
|
|
62
|
+
if (text.length > 5_000_000)
|
|
63
|
+
throw new Error('Input exceeds the architecture limit');
|
|
64
|
+
} return text; } }) {
|
|
65
|
+
try {
|
|
66
|
+
const positional = [], options = {};
|
|
67
|
+
for (let index = 0; index < args.length; index++) {
|
|
68
|
+
const arg = args[index];
|
|
69
|
+
if (['--project', '--file', '--format', '--language'].includes(arg)) {
|
|
70
|
+
if (!args[index + 1] || args[index + 1].startsWith('--'))
|
|
71
|
+
throw new Error(`Missing value for ${arg}`);
|
|
72
|
+
options[arg.slice(2)] = args[++index];
|
|
73
|
+
}
|
|
74
|
+
else if (['--teardown', '--list', '--help'].includes(arg))
|
|
75
|
+
options[arg.slice(2)] = 'true';
|
|
76
|
+
else if (arg.startsWith('--'))
|
|
77
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
78
|
+
else
|
|
79
|
+
positional.push(arg);
|
|
80
|
+
}
|
|
81
|
+
const [command = 'help', element, field, ...content] = positional;
|
|
82
|
+
if (command === 'help' || options.help) {
|
|
83
|
+
io.write(ARCHITECTURE_HELP);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
const root = await fs.realpath(path.resolve(options.project ?? process.cwd()));
|
|
87
|
+
if (!(await fs.stat(root)).isDirectory())
|
|
88
|
+
throw new Error('Project root must be a directory');
|
|
89
|
+
const store = new ArchitectureStore(root);
|
|
90
|
+
const omm = options.format === 'omm' || options.file === '.omm';
|
|
91
|
+
if (options.format && !['native', 'omm'].includes(options.format))
|
|
92
|
+
throw new Error('Format must be native or omm');
|
|
93
|
+
const file = options.file ?? (omm ? '.omm' : ARCHITECTURE_FILE);
|
|
94
|
+
const instructions = async () => {
|
|
95
|
+
const language = options.language ?? (omm ? (await store.config()).language : 'en');
|
|
96
|
+
return omm ? buildOmmScanPrompt(root, language) : buildArchitecturePrompt(root, language === 'zh' ? 'zh' : 'en');
|
|
97
|
+
};
|
|
98
|
+
const input = async (values) => values[0] === '-' ? io.stdin() : values.join(' ');
|
|
99
|
+
const json = (value) => io.write(JSON.stringify(value, null, 2));
|
|
100
|
+
if (command === 'prompt' || command === 'scan') {
|
|
101
|
+
io.write(await instructions());
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
if (command === 'setup') {
|
|
105
|
+
const platforms = { claude: '.claude/skills', codex: '.agents/skills', cursor: '.cursor/skills', openclaw: '.openclaw/skills', antigravity: '.agent/skills' };
|
|
106
|
+
if (options.list) {
|
|
107
|
+
json(Object.keys(platforms));
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
const selected = element ? [element] : Object.keys(platforms);
|
|
111
|
+
if (selected.some(platform => !platforms[platform]))
|
|
112
|
+
throw new Error('Unknown AI platform');
|
|
113
|
+
const marker = '<!-- Termdock architecture skill -->';
|
|
114
|
+
for (const platform of selected) {
|
|
115
|
+
const relative = `${platforms[platform]}/termdock-architecture/SKILL.md`, destination = await store.bounded(relative, true);
|
|
116
|
+
let existing = '';
|
|
117
|
+
try {
|
|
118
|
+
existing = await fs.readFile(destination, 'utf8');
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error.code !== 'ENOENT')
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
if (existing && !existing.includes(marker))
|
|
125
|
+
throw new Error(`Refusing to overwrite an unrelated skill: ${relative}`);
|
|
126
|
+
if (options.teardown) {
|
|
127
|
+
if (existing.includes(marker))
|
|
128
|
+
await fs.unlink(destination);
|
|
129
|
+
io.write(`Removed ${relative}`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const prompt = await instructions();
|
|
133
|
+
await fs.writeFile(destination, `---\nname: termdock-architecture\ndescription: Recursively analyze or update this project's Termdock code architecture.\n---\n${marker}\n\n${prompt}\n`, { mode: 0o600 });
|
|
134
|
+
io.write(`Installed ${relative}`);
|
|
135
|
+
}
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
if (command === 'config') {
|
|
139
|
+
if (element !== 'language')
|
|
140
|
+
throw new Error('Use config language [code]');
|
|
141
|
+
json(await store.config(field));
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
if (command === 'init') {
|
|
145
|
+
await store.config();
|
|
146
|
+
if (omm)
|
|
147
|
+
await store.config(options.language ?? 'en');
|
|
148
|
+
io.write('Ready. Use td architecture prompt, or Generate in the Architecture panel.');
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
if (command === 'list') {
|
|
152
|
+
json(await store.list());
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
if (command === 'save' || command === 'import') {
|
|
156
|
+
const raw = await input(positional.slice(1));
|
|
157
|
+
if (!raw)
|
|
158
|
+
throw new Error('Supply JSON or - for stdin');
|
|
159
|
+
const value = JSON.parse(raw);
|
|
160
|
+
if (value?.format === 'termdock-omm-bundle') {
|
|
161
|
+
await store.importOmmBundle(value);
|
|
162
|
+
json(await store.read('.omm'));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const document = parseArchitecture(raw);
|
|
166
|
+
json(await store.save(options.file ?? (document.analysis ? analysisFile(document.analysis) : ARCHITECTURE_FILE), document));
|
|
167
|
+
}
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
if (command === 'export' && omm) {
|
|
171
|
+
const source = options.file && options.file !== '.omm' ? (await store.read(options.file)).document : undefined;
|
|
172
|
+
if (source === null)
|
|
173
|
+
throw new Error('Architecture not found');
|
|
174
|
+
json(await store.exportOmmBundle(source));
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
if (command === 'delete' && omm) {
|
|
178
|
+
if (!element)
|
|
179
|
+
throw new Error('Supply an element path');
|
|
180
|
+
await store.deleteOmmElement(element);
|
|
181
|
+
io.write(`Deleted ${element}`);
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
if (command === 'write' && omm) {
|
|
185
|
+
if (!element || !ARCHITECTURE_FIELDS.includes(field))
|
|
186
|
+
throw new Error('Supply an element and valid field');
|
|
187
|
+
await store.writeOmmField(element, field, await input(content));
|
|
188
|
+
io.write(`Updated ${element}/${field}`);
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
const loaded = await store.read(file), document = loaded.document;
|
|
192
|
+
if (!document)
|
|
193
|
+
throw new Error('No saved architecture. Generate one first, or select --format omm.');
|
|
194
|
+
if (command === 'export') {
|
|
195
|
+
json(document);
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
if (command === 'status') {
|
|
199
|
+
json({ file, generatedAt: document.generatedAt, meta: document.meta, perspectives: document.perspectives.map(view => ({ id: view.id, nodes: view.nodes.length, edges: view.edges.length })) });
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
if (command === 'history') {
|
|
203
|
+
json(await store.history(file));
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
if (command === 'tree' && document.origin === 'omm') {
|
|
207
|
+
for (const entry of await store.ommElements())
|
|
208
|
+
if (!element || entry === element || entry.startsWith(`${element}/`))
|
|
209
|
+
io.write(`${' '.repeat(entry.split('/').length - 1)}${entry.split('/').pop()}`);
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
if (command === 'tree') {
|
|
213
|
+
const views = element ? [target(document, element).view] : document.perspectives;
|
|
214
|
+
for (const view of views) {
|
|
215
|
+
io.write(view.id);
|
|
216
|
+
const walk = (parent, prefix) => { for (const node of view.nodes.filter(node => node.parentId === parent)) {
|
|
217
|
+
io.write(`${prefix}${node.id} — ${node.title}`);
|
|
218
|
+
walk(node.id, `${prefix} `);
|
|
219
|
+
} };
|
|
220
|
+
walk(element ? target(document, element).node?.id : undefined, ' ');
|
|
221
|
+
}
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
if (command === 'validate') {
|
|
225
|
+
const issues = [];
|
|
226
|
+
if (element)
|
|
227
|
+
target(document, element);
|
|
228
|
+
for (const view of document.perspectives) {
|
|
229
|
+
for (const item of [view, ...view.nodes]) {
|
|
230
|
+
const key = elementPath(view, item === view ? undefined : item);
|
|
231
|
+
if (element && key !== element && !key.startsWith(`${element}/`))
|
|
232
|
+
continue;
|
|
233
|
+
if (!item.description && !item.summary)
|
|
234
|
+
issues.push({ element: key, message: 'Missing description' });
|
|
235
|
+
if (item.diagram) {
|
|
236
|
+
const diagram = parseFlowchart(item.diagram);
|
|
237
|
+
for (const issue of diagram.issues)
|
|
238
|
+
issues.push({ element: key, message: issue });
|
|
239
|
+
for (const node of diagram.nodes)
|
|
240
|
+
if (node.ref && (!document.perspectives.some(other => other.id === node.ref) || node.ref === view.id))
|
|
241
|
+
issues.push({ element: key, message: `Unresolved or self-referencing perspective: ${node.ref}` });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
json({ valid: !issues.length, issues });
|
|
246
|
+
return issues.length ? 1 : 0;
|
|
247
|
+
}
|
|
248
|
+
if (command === 'diff' && !element) {
|
|
249
|
+
json(await store.history(file));
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
if (command === 'view') {
|
|
253
|
+
io.write(`Open Termdock → this project → Architecture, or https://localhost:9834/?architecture=${encodeURIComponent(JSON.stringify({ root, file }))}`);
|
|
254
|
+
return 0;
|
|
255
|
+
}
|
|
256
|
+
if (!element)
|
|
257
|
+
throw new Error('Element path is required');
|
|
258
|
+
const selected = target(document, element);
|
|
259
|
+
if (command === 'delete') {
|
|
260
|
+
const removed = new Set();
|
|
261
|
+
if (!selected.node)
|
|
262
|
+
document.perspectives = document.perspectives.filter(view => view.id !== selected.view.id);
|
|
263
|
+
else {
|
|
264
|
+
removed.add(selected.node.id);
|
|
265
|
+
for (let index = 0; index < selected.view.nodes.length; index++)
|
|
266
|
+
for (const node of selected.view.nodes)
|
|
267
|
+
if (node.parentId && removed.has(node.parentId))
|
|
268
|
+
removed.add(node.id);
|
|
269
|
+
selected.view.nodes = selected.view.nodes.filter(node => !removed.has(node.id));
|
|
270
|
+
selected.view.edges = selected.view.edges.filter(edge => !removed.has(edge.from) && !removed.has(edge.to));
|
|
271
|
+
}
|
|
272
|
+
// Validation refuses dangling references and an empty document.
|
|
273
|
+
await store.save(file, document, loaded.revision);
|
|
274
|
+
io.write(`Deleted ${element}`);
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
if (command === 'show') {
|
|
278
|
+
json(selected.value);
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
if (command === 'read') {
|
|
282
|
+
if (!ARCHITECTURE_FIELDS.includes(field))
|
|
283
|
+
throw new Error('Invalid field');
|
|
284
|
+
io.write(selected.value[field] ?? (field === 'description' ? selected.value.summary : field === 'diagram' ? architectureSourceDiagram(selected.view, selected.node?.id) : ''));
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
if (command === 'write') {
|
|
288
|
+
if (!ARCHITECTURE_FIELDS.includes(field))
|
|
289
|
+
throw new Error('Invalid field');
|
|
290
|
+
const updated = updateArchitectureField(document, selected.view.id, selected.node?.id, field, await input(content));
|
|
291
|
+
await store.save(file, updated, loaded.revision);
|
|
292
|
+
io.write(`Updated ${element}/${field}`);
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
if (command === 'refs') {
|
|
296
|
+
const reference = (perspective, id) => {
|
|
297
|
+
const view = document.perspectives.find(view => view.id === perspective);
|
|
298
|
+
const node = id ? view.nodes.find(node => node.id === id) : undefined;
|
|
299
|
+
return { perspective, ...(id ? { node: id } : {}), element: elementPath(view, node), title: node?.title ?? view.title };
|
|
300
|
+
};
|
|
301
|
+
const connections = (selected.node ? selected.view.edges.filter(edge => edge.from === selected.node.id || edge.to === selected.node.id) : selected.view.edges).map(edge => ({ ...edge, fromElement: elementPath(selected.view, selected.view.nodes.find(node => node.id === edge.from)), toElement: elementPath(selected.view, selected.view.nodes.find(node => node.id === edge.to)) }));
|
|
302
|
+
json({ outgoing: (selected.node?.references ?? []).map(ref => reference(ref.perspective, ref.node)), incoming: document.perspectives.flatMap(view => view.nodes.filter(node => node.references?.some(ref => ref.perspective === selected.view.id && (!ref.node || ref.node === selected.node?.id))).map(node => reference(view.id, node.id))), connections });
|
|
303
|
+
return 0;
|
|
304
|
+
}
|
|
305
|
+
if (command === 'diff') {
|
|
306
|
+
if (selected.value.meta?.previousDiagram && selected.value.diagram)
|
|
307
|
+
json(diffMermaid(selected.value.meta.previousDiagram, selected.value.diagram));
|
|
308
|
+
else {
|
|
309
|
+
const versions = await store.history(file);
|
|
310
|
+
json(versions[0] ? diffArchitecture(await store.historical(file, versions[0].id), document).filter(change => change.perspective === selected.view.id && (!selected.node || change.node === selected.node.id)) : []);
|
|
311
|
+
}
|
|
312
|
+
return 0;
|
|
313
|
+
}
|
|
314
|
+
throw new Error(`Unknown architecture command: ${command}`);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
io.write(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
318
|
+
return 1;
|
|
319
|
+
}
|
|
320
|
+
}
|