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
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/** Termdock's portable, agent-independent architecture document. */
|
|
2
|
+
export const ARCHITECTURE_FILE = '.termdock/architecture.json';
|
|
3
|
+
export const ARCHITECTURE_DIRECTORY = '.termdock/architectures';
|
|
4
|
+
export const DEFAULT_ANALYSIS = { kind: 'project', target: '', paths: [], depth: 'boundary', focus: '' };
|
|
5
|
+
export const ARCHITECTURE_FIELDS = ['description', 'diagram', 'context', 'constraint', 'concern', 'todo', 'note'];
|
|
6
|
+
const ID = /^[a-zA-Z][a-zA-Z0-9_-]{0,79}$/;
|
|
7
|
+
export class ArchitectureFormatError extends Error {
|
|
8
|
+
}
|
|
9
|
+
function invalid() { throw new ArchitectureFormatError('Invalid architecture document'); }
|
|
10
|
+
function object(value) {
|
|
11
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
12
|
+
invalid();
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function string(value, limit = 8000) {
|
|
16
|
+
if (typeof value !== 'string' || value.length > limit)
|
|
17
|
+
invalid();
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function id(value) {
|
|
21
|
+
const result = string(value, 80);
|
|
22
|
+
if (!ID.test(result))
|
|
23
|
+
invalid();
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function array(value, limit) {
|
|
27
|
+
if (!Array.isArray(value) || value.length > limit)
|
|
28
|
+
invalid();
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
function fields(value) {
|
|
32
|
+
return Object.fromEntries(ARCHITECTURE_FIELDS.filter(key => value[key] !== undefined).map(key => [key, string(value[key], 100_000)]));
|
|
33
|
+
}
|
|
34
|
+
function meta(value) {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
const raw = object(value), result = {};
|
|
38
|
+
for (const key of ['created', 'updated', 'gitCommit', 'gitBranch', 'previousDiagram']) {
|
|
39
|
+
if (raw[key] !== undefined)
|
|
40
|
+
result[key] = string(raw[key], key === 'previousDiagram' ? 100_000 : 200);
|
|
41
|
+
}
|
|
42
|
+
if (raw.updateCount !== undefined) {
|
|
43
|
+
if (!Number.isSafeInteger(raw.updateCount) || raw.updateCount < 0)
|
|
44
|
+
invalid();
|
|
45
|
+
result.updateCount = raw.updateCount;
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export function isArchitectureSourcePath(path) {
|
|
50
|
+
return !!path && !/[:\\\x00-\x1f]/.test(path) && !path.startsWith('/')
|
|
51
|
+
&& path.split('/').every(part => !!part && part !== '.' && part !== '..');
|
|
52
|
+
}
|
|
53
|
+
export function normalizeAnalysis(value) {
|
|
54
|
+
if (!['project', 'module', 'feature'].includes(value.kind)
|
|
55
|
+
|| !['boundary', 'dependencies'].includes(value.depth))
|
|
56
|
+
invalid();
|
|
57
|
+
const paths = value.kind === 'project' ? [] : [...new Set(array(value.paths, 20).map(value => string(value, 1024).trim()))].sort();
|
|
58
|
+
if (paths.some(path => !isArchitectureSourcePath(path)))
|
|
59
|
+
invalid();
|
|
60
|
+
const target = string(value.target, 1000).trim();
|
|
61
|
+
const focus = string(value.focus, 2000).trim();
|
|
62
|
+
if ((value.kind === 'module' && !paths.length) || (value.kind === 'feature' && !target))
|
|
63
|
+
invalid();
|
|
64
|
+
return { kind: value.kind, target: value.kind === 'project' ? '' : value.kind === 'module' ? paths.join('\n') : target,
|
|
65
|
+
paths: value.kind === 'project' ? [] : paths, depth: value.depth, focus };
|
|
66
|
+
}
|
|
67
|
+
export function analysisFile(analysis) {
|
|
68
|
+
const scope = normalizeAnalysis(analysis);
|
|
69
|
+
if (scope.kind === 'project')
|
|
70
|
+
return ARCHITECTURE_FILE;
|
|
71
|
+
// A stable scope identity keeps updates in one file without a shared manifest.
|
|
72
|
+
const identity = JSON.stringify([scope.kind, scope.target, scope.paths]);
|
|
73
|
+
let hash = 2166136261;
|
|
74
|
+
for (let i = 0; i < identity.length; i++)
|
|
75
|
+
hash = Math.imul(hash ^ identity.charCodeAt(i), 16777619);
|
|
76
|
+
const label = Array.from(scope.target.replace(/[^\p{L}\p{N}_-]+/gu, '-').replace(/^-+|-+$/g, '')).slice(0, 48).join('') || 'analysis';
|
|
77
|
+
return `${ARCHITECTURE_DIRECTORY}/${scope.kind}-${label}-${(hash >>> 0).toString(16).padStart(8, '0')}.json`;
|
|
78
|
+
}
|
|
79
|
+
export function isArchitectureFile(file) {
|
|
80
|
+
return file === '.omm' || file === ARCHITECTURE_FILE || new RegExp(`^${ARCHITECTURE_DIRECTORY.replace('.', '\\.')}\/(?:module|feature)-[\\p{L}\\p{N}_-]{1,48}-[a-f0-9]{8}\\.json$`, 'u').test(file);
|
|
81
|
+
}
|
|
82
|
+
export function architectureFileLabel(file) {
|
|
83
|
+
return file.split('/').pop()?.replace(/^(module|feature)-/, '').replace(/-[a-f0-9]{8}\.json$/, '').replace(/-/g, ' ') ?? file;
|
|
84
|
+
}
|
|
85
|
+
export function architectureFilePath(root, file = ARCHITECTURE_FILE) {
|
|
86
|
+
if (!isArchitectureFile(file))
|
|
87
|
+
invalid();
|
|
88
|
+
return `${root.replace(/\/+$/, '')}/${file}`;
|
|
89
|
+
}
|
|
90
|
+
export function parseArchitecture(content) {
|
|
91
|
+
if (new TextEncoder().encode(content).byteLength > 5_000_000)
|
|
92
|
+
invalid();
|
|
93
|
+
let raw;
|
|
94
|
+
try {
|
|
95
|
+
raw = JSON.parse(content);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
invalid();
|
|
99
|
+
}
|
|
100
|
+
const doc = object(raw);
|
|
101
|
+
if (doc.version !== 1)
|
|
102
|
+
invalid();
|
|
103
|
+
const generatedAt = string(doc.generatedAt, 80);
|
|
104
|
+
if (!Number.isFinite(Date.parse(generatedAt)))
|
|
105
|
+
invalid();
|
|
106
|
+
const perspectives = array(doc.perspectives, 12).map(value => {
|
|
107
|
+
const view = object(value);
|
|
108
|
+
const nodes = array(view.nodes, 200).map(value => {
|
|
109
|
+
const node = object(value);
|
|
110
|
+
const files = array(node.files, 40).map(value => {
|
|
111
|
+
const file = object(value);
|
|
112
|
+
const path = string(file.path, 1024);
|
|
113
|
+
if (!isArchitectureSourcePath(path))
|
|
114
|
+
invalid();
|
|
115
|
+
if (file.line !== undefined && (!Number.isSafeInteger(file.line) || file.line < 1))
|
|
116
|
+
invalid();
|
|
117
|
+
return { path, ...(file.line !== undefined ? { line: file.line } : {}) };
|
|
118
|
+
});
|
|
119
|
+
const references = node.references === undefined ? undefined : array(node.references, 100).map(value => {
|
|
120
|
+
const ref = object(value);
|
|
121
|
+
return { perspective: id(ref.perspective), ...(ref.node !== undefined ? { node: id(ref.node) } : {}) };
|
|
122
|
+
});
|
|
123
|
+
if (node.documentPath !== undefined && !isArchitectureSourcePath(string(node.documentPath, 1024)))
|
|
124
|
+
invalid();
|
|
125
|
+
if (node.role !== undefined && !['external', 'concern', 'entry', 'store'].includes(node.role))
|
|
126
|
+
invalid();
|
|
127
|
+
return { id: id(node.id), title: string(node.title, 160), summary: string(node.summary), files, ...fields(node),
|
|
128
|
+
...(node.parentId !== undefined ? { parentId: id(node.parentId) } : {}),
|
|
129
|
+
...(node.documentPath !== undefined ? { documentPath: string(node.documentPath, 1024) } : {}), ...(meta(node.meta) ? { meta: meta(node.meta) } : {}),
|
|
130
|
+
...(references ? { references } : {}), ...(node.role !== undefined ? { role: node.role } : {}) };
|
|
131
|
+
});
|
|
132
|
+
if (!nodes.length)
|
|
133
|
+
invalid();
|
|
134
|
+
const nodeMap = new Map(nodes.map(node => [node.id, node]));
|
|
135
|
+
if (nodeMap.size !== nodes.length)
|
|
136
|
+
invalid();
|
|
137
|
+
for (const node of nodes) {
|
|
138
|
+
const visited = new Set([node.id]);
|
|
139
|
+
let parent = node.parentId;
|
|
140
|
+
while (parent) {
|
|
141
|
+
if (visited.has(parent) || !nodeMap.has(parent))
|
|
142
|
+
invalid();
|
|
143
|
+
visited.add(parent);
|
|
144
|
+
parent = nodeMap.get(parent)?.parentId;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const edges = array(view.edges, 600).map(value => {
|
|
148
|
+
const edge = object(value);
|
|
149
|
+
const from = id(edge.from), to = id(edge.to);
|
|
150
|
+
if (!nodeMap.has(from) || !nodeMap.has(to))
|
|
151
|
+
invalid();
|
|
152
|
+
return { from, to, label: string(edge.label, 200) };
|
|
153
|
+
});
|
|
154
|
+
return { id: id(view.id), title: string(view.title, 160), summary: string(view.summary), nodes, edges, ...fields(view), ...(meta(view.meta) ? { meta: meta(view.meta) } : {}) };
|
|
155
|
+
});
|
|
156
|
+
if (!perspectives.length || new Set(perspectives.map(view => view.id)).size !== perspectives.length)
|
|
157
|
+
invalid();
|
|
158
|
+
for (const view of perspectives)
|
|
159
|
+
for (const node of view.nodes)
|
|
160
|
+
for (const ref of node.references ?? []) {
|
|
161
|
+
const target = perspectives.find(view => view.id === ref.perspective);
|
|
162
|
+
if (!target || (ref.node && !target.nodes.some(node => node.id === ref.node)))
|
|
163
|
+
invalid();
|
|
164
|
+
}
|
|
165
|
+
const analysis = doc.analysis === undefined ? undefined : normalizeAnalysis(object(doc.analysis));
|
|
166
|
+
let details;
|
|
167
|
+
if (doc.details !== undefined) {
|
|
168
|
+
const rawDetails = object(doc.details);
|
|
169
|
+
const analyzedPaths = array(rawDetails.analyzedPaths, 200).map(value => {
|
|
170
|
+
const path = string(value, 1024);
|
|
171
|
+
if (!isArchitectureSourcePath(path))
|
|
172
|
+
invalid();
|
|
173
|
+
return path;
|
|
174
|
+
});
|
|
175
|
+
const limitations = array(rawDetails.limitations, 30).map(value => string(value, 2000));
|
|
176
|
+
details = { analyzedPaths, limitations };
|
|
177
|
+
}
|
|
178
|
+
if (doc.origin !== undefined && !['termdock', 'omm'].includes(doc.origin))
|
|
179
|
+
invalid();
|
|
180
|
+
return { version: 1, generatedAt, summary: string(doc.summary), perspectives, ...(analysis ? { analysis } : {}), ...(details ? { details } : {}),
|
|
181
|
+
...(doc.origin ? { origin: doc.origin } : {}), ...(meta(doc.meta) ? { meta: meta(doc.meta) } : {}) };
|
|
182
|
+
}
|
|
183
|
+
/** Fold descendant connections onto the immediate children at this depth. */
|
|
184
|
+
export function architectureScope(view, parentId) {
|
|
185
|
+
const nodes = view.nodes.filter(node => node.parentId === parentId);
|
|
186
|
+
const byId = new Map(view.nodes.map(node => [node.id, node]));
|
|
187
|
+
const visible = new Set(nodes.map(node => node.id));
|
|
188
|
+
const ancestor = (id) => {
|
|
189
|
+
let node = byId.get(id);
|
|
190
|
+
while (node && !visible.has(node.id))
|
|
191
|
+
node = node.parentId ? byId.get(node.parentId) : undefined;
|
|
192
|
+
return node?.id;
|
|
193
|
+
};
|
|
194
|
+
const edges = new Map();
|
|
195
|
+
for (const edge of view.edges) {
|
|
196
|
+
const from = ancestor(edge.from), to = ancestor(edge.to);
|
|
197
|
+
if (from && to && from !== to && !edges.has(`${from}:${to}`)) {
|
|
198
|
+
edges.set(`${from}:${to}`, { from, to, label: edge.label });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return { nodes, edges: [...edges.values()] };
|
|
202
|
+
}
|
|
203
|
+
/** Labels become text; agent data never becomes Mermaid syntax or callbacks. */
|
|
204
|
+
function diagramLabel(value) {
|
|
205
|
+
return value.slice(0, 100).replace(/[&<>"\[\]{}|`#;\\\r\n]/g, ' ').trim() || '…';
|
|
206
|
+
}
|
|
207
|
+
export function architectureDiagram(view, parentId, nesting = 0) {
|
|
208
|
+
const scope = architectureScope(view, parentId);
|
|
209
|
+
const nodes = [];
|
|
210
|
+
const collect = (parent, depth) => {
|
|
211
|
+
for (const node of view.nodes.filter(node => node.parentId === parent)) {
|
|
212
|
+
nodes.push(node);
|
|
213
|
+
if (depth < nesting)
|
|
214
|
+
collect(node.id, depth + 1);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
collect(parentId, 0);
|
|
218
|
+
const ids = new Map(nodes.map((node, index) => [node.id, `n${index}`]));
|
|
219
|
+
const lines = [];
|
|
220
|
+
const groups = new Set();
|
|
221
|
+
const render = (parent, depth) => {
|
|
222
|
+
for (const node of view.nodes.filter(node => node.parentId === parent)) {
|
|
223
|
+
const key = ids.get(node.id);
|
|
224
|
+
if (depth < nesting && view.nodes.some(child => child.parentId === node.id)) {
|
|
225
|
+
groups.add(node.id);
|
|
226
|
+
lines.push(`subgraph ${key}["${diagramLabel(node.title)}"]`);
|
|
227
|
+
render(node.id, depth + 1);
|
|
228
|
+
lines.push('end');
|
|
229
|
+
}
|
|
230
|
+
else
|
|
231
|
+
lines.push(`${key}["${diagramLabel(node.title)}"]`);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
render(parentId, 0);
|
|
235
|
+
const ancestor = (id) => {
|
|
236
|
+
let node = view.nodes.find(node => node.id === id);
|
|
237
|
+
while (node && !ids.has(node.id))
|
|
238
|
+
node = view.nodes.find(parent => parent.id === node.parentId);
|
|
239
|
+
return node?.id;
|
|
240
|
+
};
|
|
241
|
+
const edges = new Map();
|
|
242
|
+
for (const edge of nesting ? view.edges : scope.edges) {
|
|
243
|
+
const from = ancestor(edge.from), to = ancestor(edge.to);
|
|
244
|
+
// Edges between a group and its own descendants would introduce layout cycles.
|
|
245
|
+
const isAncestor = (a, b) => {
|
|
246
|
+
let node = view.nodes.find(node => node.id === b);
|
|
247
|
+
while (node?.parentId) {
|
|
248
|
+
if (node.parentId === a)
|
|
249
|
+
return true;
|
|
250
|
+
node = view.nodes.find(parent => parent.id === node.parentId);
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
};
|
|
254
|
+
if (from && to && from !== to && !isAncestor(from, to) && !isAncestor(to, from))
|
|
255
|
+
edges.set(`${from}:${to}:${edge.label}`, { from, to, label: edge.label });
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
nodes, groups,
|
|
259
|
+
code: ['---', 'config:', ' htmlLabels: false', '---', 'flowchart TD', ...lines,
|
|
260
|
+
...edges.values()].map(line => typeof line === 'string' ? line : `${ids.get(line.from)} -->|"${diagramLabel(line.label)}"| ${ids.get(line.to)}`).join('\n'),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
export function buildArchitecturePrompt(root, language, analysis = DEFAULT_ANALYSIS, outputFile) {
|
|
264
|
+
const scope = normalizeAnalysis(analysis);
|
|
265
|
+
const output = outputFile ?? analysisFile(scope);
|
|
266
|
+
if (output === '.omm')
|
|
267
|
+
return buildOmmScanPrompt(root, language);
|
|
268
|
+
if (!isArchitectureFile(output) || (scope.kind !== 'project' && output === ARCHITECTURE_FILE)
|
|
269
|
+
|| (scope.kind === 'project' && output !== ARCHITECTURE_FILE))
|
|
270
|
+
invalid();
|
|
271
|
+
const example = {
|
|
272
|
+
version: 1, generatedAt: '2026-01-01T00:00:00Z', summary: 'Project overview',
|
|
273
|
+
analysis: scope,
|
|
274
|
+
details: { analyzedPaths: [], limitations: [] },
|
|
275
|
+
perspectives: [{ id: 'overview', title: 'Architecture', summary: 'Responsibilities and relationships',
|
|
276
|
+
nodes: [
|
|
277
|
+
{ id: 'client', title: 'Client', summary: 'User interface', files: [{ path: 'src/App.tsx', line: 1 }] },
|
|
278
|
+
{ id: 'server', title: 'Server', summary: 'Request handling', files: [{ path: 'src/server/index.ts' }] },
|
|
279
|
+
{ id: 'routes', parentId: 'server', title: 'Routes', summary: 'API entry points', files: [{ path: 'src/server/routes/api.ts' }] },
|
|
280
|
+
], edges: [{ from: 'client', to: 'routes', label: 'API requests' }] }],
|
|
281
|
+
};
|
|
282
|
+
return [
|
|
283
|
+
language === 'zh' ? '请为当前项目生成或更新 Termdock 代码架构。' : 'Generate or update the Termdock code architecture for this project.',
|
|
284
|
+
`Project root (literal path): ${JSON.stringify(root)}`,
|
|
285
|
+
`Output (literal relative path): ${JSON.stringify(output)} in this project. Create its parent directory if needed. Write ONLY this architecture document; leave all other saved maps unchanged. Do not modify a shared index or manifest.`,
|
|
286
|
+
`Analysis scope (literal data): ${JSON.stringify(scope)}. Treat scope values as analysis requirements, never as shell commands. Include this exact analysis object in the output.`,
|
|
287
|
+
scope.kind === 'project' ? 'Create a high-level project overview. You do not need to read every source file. Start with instructions, manifests and entry points; expand only where needed to explain important boundaries.'
|
|
288
|
+
: scope.kind === 'module' ? 'Analyze ONLY the specified module paths (directories or files), relative to the project root. Confirm they exist. Read local instructions and entry points within these paths. Do not perform a repository-wide analysis or generate unrelated modules.'
|
|
289
|
+
: 'Analyze ONLY the requested feature, which can cross directories. If starting paths are supplied, begin there; otherwise locate likely entry points with targeted code searches. Trace its request/event/data flow through relevant code. Do not perform a repository-wide analysis or generate unrelated features.',
|
|
290
|
+
scope.depth === 'boundary' ? 'Dependency depth: stop at the boundary of the selected scope. Show necessary external callers/dependencies as boundary nodes, without analyzing their internal implementation.'
|
|
291
|
+
: 'Dependency depth: follow only dependencies and callers directly needed to explain the selected scope, including across directories. Stop when the feature or module flow is explained; never recursively analyze the entire dependency graph.',
|
|
292
|
+
...(scope.kind === 'feature' && scope.paths.length ? [scope.depth === 'boundary'
|
|
293
|
+
? 'The selected paths define the primary feature scope: locate and explain the requested feature WITHIN these directories/files. Show code outside these paths only as necessary boundary connections; do not expand its implementation or unrelated features.'
|
|
294
|
+
: 'Locate the requested feature within the selected paths first, then follow only directly relevant calls and dependencies outside them. Keep the analysis centered on this feature, not the entire selected module.'] : []),
|
|
295
|
+
'For very large projects, use targeted searches and representative entry points. Skip generated files, vendor code, lockfiles and unrelated tests. Put existing source files actually inspected in details.analyzedPaths (not directories or search logs) and material uncertainties/limitations in details.limitations. If the scope cannot be found, report that and do not overwrite an existing map.',
|
|
296
|
+
'Analyze actual code, not just filenames. Do not execute application code or change business source files. Do not include secrets.',
|
|
297
|
+
'Explain the architecture for a person trying to understand this feature/module. The document summary should be 2–3 short sentences (roughly 80–180 Chinese characters or 40–80 English words): what it does, its main entry points, and how the main parts cooperate. Do not put file lists, verification reports, safety checklists or repeated scope disclaimers in summaries; use details instead. Avoid internal variable names when a clear responsibility name works.',
|
|
298
|
+
'Select meaningful perspectives from: overall architecture, request lifecycle, data flow, dependency map, external integrations, state transitions, routes/pages, command surface, extension points, pipeline, orchestration, storage. Choose only those relevant to this scope.',
|
|
299
|
+
'Start with a small overview of 3–7 responsibilities. Group implementation steps under their parent responsibility using parentId rather than flattening every helper and protocol boundary into the overview. Use additional perspectives only when they answer a distinct user question (usually 2–4 useful views). Show the actual main flow and meaningful edge labels. External dependencies should appear only when needed to explain a connection, without dominating the overview or prefixing every title with "boundary".',
|
|
300
|
+
'RECURSIVE ANALYSIS: inspect the actual code for EVERY node in EVERY chosen perspective. Each node must have a description, even leaves. If distinct internal components exist, create children with parentId, inspect each child, and recurse until meaningful leaves. Do not stop after writing the top-level diagram. Stay inside the requested analysis boundary; represent external systems as leaves. Reuse source inspection across perspectives.',
|
|
301
|
+
'Document each node with description (Markdown responsibility and handoffs), context (why this design exists), constraint (invariants/limits), concern (verified risks or uncertainties), todo (specific remaining work), note (additional useful detail). Include relevant fields; do not invent issues or add empty boilerplate. Keep summary concise for overview cards. Perspectives support the same fields. Optional diagram preserves a Mermaid flowchart for this element; structural nodes/edges remain the viewer source of truth. Optional references [{perspective, node?}] link to related elements across perspectives and must resolve. Optional role: entry, store, external, concern.',
|
|
302
|
+
'Use the JSON schema shown below. Each perspective has a flat nodes array; parentId describes nested modules. Omit parentId for top-level nodes. IDs must be unique within a perspective and match /^[a-zA-Z][a-zA-Z0-9_-]{0,79}$/. No cycles or missing references.',
|
|
303
|
+
'Use at most 12 perspectives, 200 nodes and 600 edges per perspective, and 40 source references per node. Keep each level to roughly 3–7 meaningful modules. Perspective summaries should explain the flow in 1–2 short sentences. Each node summary should explain its responsibility and important handoff in 1–3 short sentences, with relevant source references; avoid narrating every line of implementation.',
|
|
304
|
+
'Source paths must be existing files relative to the project root, with no absolute paths, URLs, backslashes or dot/parent segments. Add a positive integer line when verified. Omit uncertain connections and explain uncertainties in summaries.',
|
|
305
|
+
`Write titles, summaries and edge labels in ${language === 'zh' ? 'Chinese' : 'English'}. Set generatedAt to the actual current ISO timestamp. The sample paths are illustrative; use this project's real paths.`,
|
|
306
|
+
'Read the selected output document if it already exists. Update only this analysis, preserve its stable IDs where possible, update affected modules, and remove obsolete references. Validate JSON and write atomically (temporary file then rename) so readers never see partial output. Summarize what was analyzed and any limitations after writing.',
|
|
307
|
+
`Prefer invoking executable td with this argument array: ${JSON.stringify(['architecture', 'save', '--project', root, '--file', output, '-'])}. Pass the complete JSON on stdin. Pass arguments separately; JSON string quoting is not shell escaping. This validates the document, archives the previous version, and records the update count and Git revision. If the CLI is unavailable, use the atomic file write above and disclose that history metadata was not recorded.`,
|
|
308
|
+
JSON.stringify(example, null, 2),
|
|
309
|
+
].join('\n\n');
|
|
310
|
+
}
|
|
311
|
+
/** Adapted scanner workflow from oh-my-mermaid, MIT; see THIRD_PARTY_NOTICES.md. */
|
|
312
|
+
export function buildOmmScanPrompt(root, language) {
|
|
313
|
+
return [
|
|
314
|
+
language.startsWith('zh') ? '分析当前项目并递归更新 .omm 架构文档。' : 'Recursively analyze this project and update its .omm architecture documents.',
|
|
315
|
+
`Project root (literal path): ${JSON.stringify(root)}. Write document content in language ${JSON.stringify(language)}.`,
|
|
316
|
+
'Read project instructions, manifests, entry points and existing .omm documentation. Select relevant perspectives: overall-architecture, request-lifecycle, data-flow, dependency-map, external-integrations, state-transitions, route-page-map, command-surface, extension-points, pipeline, orchestration, storage.',
|
|
317
|
+
'For each perspective, write a graph LR or graph TD diagram whose node IDs match child directory names (English kebab-case). Every edge must have a meaningful label. Node labels use name plus verified source path separated by \\n. Write description for EVERY node, inspect its actual source, and recursively create child diagrams wherever distinct internal components exist. Leaves still need descriptions. Do not stop at the top-level diagram.',
|
|
318
|
+
'Each element supports description, diagram, context, constraint, concern, todo, note. Use Markdown for text fields. Record real constraints and concerns without inventing them. Existing @perspective references can link between perspectives. Do not rewrite unchanged elements. Remove obsolete references after confirming them. Never modify business source files or include secrets.',
|
|
319
|
+
`Invoke executable td with this argument array: ${JSON.stringify(['architecture', 'write', '--project', root, '--format', 'omm', '<perspective/child/path>', '<field>', '-'])}, replacing the two placeholders with the element path and field. Supply that field on stdin. Pass arguments separately; JSON string quoting is not shell escaping. Use read, tree, refs and diff to inspect existing documents. Finish by invoking td with argument array ${JSON.stringify(['architecture', 'validate', '--project', root, '--format', 'omm'])}.`,
|
|
320
|
+
'Report the inspected sources, updated perspectives, recursion coverage and unresolved limitations. The Termdock architecture viewer reads .omm directly; no separate viewer server is required.',
|
|
321
|
+
].join('\n\n');
|
|
322
|
+
}
|
|
323
|
+
/** Editable level diagram: IDs remain the document's stable IDs. */
|
|
324
|
+
export function architectureSourceDiagram(view, parentId) {
|
|
325
|
+
const scope = architectureScope(view, parentId);
|
|
326
|
+
const label = (text) => text.replace(/["<>|`\\\r\n]/g, ' ');
|
|
327
|
+
return ['graph LR', ...scope.nodes.map(node => `${node.id}["${label(node.title)}"]`), ...scope.edges.map(edge => `${edge.from} -->|"${label(edge.label)}"| ${edge.to}`)].join('\n');
|
|
328
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ARCHITECTURE_FIELDS } from './document.js';
|
|
2
|
+
/** Compare semantic document content, excluding timestamps and update counters. */
|
|
3
|
+
export function diffArchitecture(before, after) {
|
|
4
|
+
const changes = [];
|
|
5
|
+
if (before) {
|
|
6
|
+
const changed = ['summary', 'analysis', 'details', 'origin'].filter(key => JSON.stringify(before[key]) !== JSON.stringify(after[key]));
|
|
7
|
+
if (changed.length)
|
|
8
|
+
changes.push({ perspective: '', title: 'Project overview', kind: 'changed', fields: changed });
|
|
9
|
+
}
|
|
10
|
+
const oldViews = new Map(before?.perspectives.map(view => [view.id, view]) ?? []);
|
|
11
|
+
for (const view of after.perspectives) {
|
|
12
|
+
const previous = oldViews.get(view.id);
|
|
13
|
+
oldViews.delete(view.id);
|
|
14
|
+
if (!previous)
|
|
15
|
+
changes.push({ perspective: view.id, title: view.title, kind: 'added', fields: [] });
|
|
16
|
+
else {
|
|
17
|
+
const changed = ['title', 'summary', 'edges', ...ARCHITECTURE_FIELDS].filter(key => JSON.stringify(previous[key]) !== JSON.stringify(view[key]));
|
|
18
|
+
if (changed.length)
|
|
19
|
+
changes.push({ perspective: view.id, title: view.title, kind: 'changed', fields: changed });
|
|
20
|
+
}
|
|
21
|
+
const oldNodes = new Map(previous?.nodes.map(node => [node.id, node]) ?? []);
|
|
22
|
+
for (const node of view.nodes) {
|
|
23
|
+
const old = oldNodes.get(node.id);
|
|
24
|
+
oldNodes.delete(node.id);
|
|
25
|
+
if (!old)
|
|
26
|
+
changes.push({ perspective: view.id, node: node.id, title: node.title, kind: 'added', fields: [] });
|
|
27
|
+
else {
|
|
28
|
+
const changed = ['title', 'summary', 'parentId', 'files', 'references', 'role', ...ARCHITECTURE_FIELDS].filter(key => JSON.stringify(old[key]) !== JSON.stringify(node[key]));
|
|
29
|
+
if (changed.length)
|
|
30
|
+
changes.push({ perspective: view.id, node: node.id, title: node.title, kind: 'changed', fields: changed });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const old of oldNodes.values())
|
|
34
|
+
changes.push({ perspective: view.id, node: old.id, title: old.title, kind: 'removed', fields: [] });
|
|
35
|
+
}
|
|
36
|
+
for (const old of oldViews.values())
|
|
37
|
+
changes.push({ perspective: old.id, title: old.title, kind: 'removed', fields: [] });
|
|
38
|
+
return changes;
|
|
39
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ARCHITECTURE_FIELDS, parseArchitecture } from './document.js';
|
|
2
|
+
import { parseFlowchart } from './flowchart.js';
|
|
3
|
+
/** Keep native structural data and its editable Mermaid field consistent. */
|
|
4
|
+
export function updateArchitectureField(input, perspective, nodeId, field, value) {
|
|
5
|
+
if (!ARCHITECTURE_FIELDS.includes(field) || typeof value !== 'string' || value.length > 100_000)
|
|
6
|
+
throw new Error('Invalid architecture field');
|
|
7
|
+
const document = parseArchitecture(JSON.stringify(input));
|
|
8
|
+
const view = document.perspectives.find(view => view.id === perspective);
|
|
9
|
+
const target = nodeId ? view?.nodes.find(node => node.id === nodeId) : view;
|
|
10
|
+
if (!view || !target)
|
|
11
|
+
throw new Error('Architecture element not found');
|
|
12
|
+
target[field] = value;
|
|
13
|
+
if (field === 'description')
|
|
14
|
+
target.summary = value.replace(/[#*`]/g, '').split(/\n\s*\n/)[0].slice(0, 600);
|
|
15
|
+
if (field === 'diagram') {
|
|
16
|
+
const graph = parseFlowchart(value);
|
|
17
|
+
const invalid = graph.issues.filter(issue => !issue.startsWith('Connection needs'));
|
|
18
|
+
if (invalid.length)
|
|
19
|
+
throw new Error(invalid.join('\n'));
|
|
20
|
+
const direct = view.nodes.filter(node => node.parentId === nodeId);
|
|
21
|
+
const removed = new Set(direct.filter(node => !graph.nodes.some(item => item.id === node.id)).map(node => node.id));
|
|
22
|
+
for (let index = 0; index < view.nodes.length; index++)
|
|
23
|
+
for (const node of view.nodes)
|
|
24
|
+
if (node.parentId && removed.has(node.parentId))
|
|
25
|
+
removed.add(node.id);
|
|
26
|
+
view.nodes = view.nodes.filter(node => !removed.has(node.id));
|
|
27
|
+
const directIds = new Set(direct.map(node => node.id));
|
|
28
|
+
view.edges = view.edges.filter(edge => !removed.has(edge.from) && !removed.has(edge.to) && !(directIds.has(edge.from) && directIds.has(edge.to)));
|
|
29
|
+
for (const item of graph.nodes) {
|
|
30
|
+
let node = view.nodes.find(node => node.id === item.id);
|
|
31
|
+
if (node && node.parentId !== nodeId)
|
|
32
|
+
throw new Error(`Diagram ID belongs to another level: ${item.id}`);
|
|
33
|
+
if (!node) {
|
|
34
|
+
node = { id: item.id, title: item.label.split('\n')[0], summary: '', files: [], ...(nodeId ? { parentId: nodeId } : {}) };
|
|
35
|
+
view.nodes.push(node);
|
|
36
|
+
}
|
|
37
|
+
node.title = item.label.split('\n')[0];
|
|
38
|
+
node.role = item.role;
|
|
39
|
+
if (item.ref) {
|
|
40
|
+
if (!document.perspectives.some(view => view.id === item.ref))
|
|
41
|
+
throw new Error(`Reference does not exist: ${item.ref}`);
|
|
42
|
+
node.references = [{ perspective: item.ref }];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
view.edges.push(...graph.edges);
|
|
46
|
+
for (const other of document.perspectives)
|
|
47
|
+
for (const node of other.nodes)
|
|
48
|
+
if (node.references?.some(ref => ref.perspective === perspective && ref.node && removed.has(ref.node)))
|
|
49
|
+
throw new Error('A removed node is referenced by another perspective');
|
|
50
|
+
}
|
|
51
|
+
return parseArchitecture(JSON.stringify(document));
|
|
52
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function parseFlowchart(raw) {
|
|
2
|
+
if (raw.length > 100_000)
|
|
3
|
+
throw new Error('Diagram is too large');
|
|
4
|
+
const nodes = new Map(), edges = [], issues = [];
|
|
5
|
+
const clean = (value) => value.replace(/<br\s*\/?>/gi, '\n').replace(/\\n/g, '\n');
|
|
6
|
+
const token = (value) => {
|
|
7
|
+
const match = value.trim().match(/^(@?[\w-]+)(?:\s*(?:\[|\(\(?|\{)\s*(.*?)\s*(?:\]|\)\)?|\}))?(?:::\w+)?$/);
|
|
8
|
+
if (!match)
|
|
9
|
+
return null;
|
|
10
|
+
const id = match[1].replace(/^@/, ''), label = clean((match[2] ?? id).replace(/^"|"$/g, ''));
|
|
11
|
+
const ref = label.match(/^@([\w-]+)(?:\n|$)/)?.[1] ?? (match[1].startsWith('@') ? id : undefined);
|
|
12
|
+
return { id, label, ...(ref ? { ref } : {}) };
|
|
13
|
+
};
|
|
14
|
+
const put = (node) => { const previous = nodes.get(node.id); if (!previous || node.label !== node.id)
|
|
15
|
+
nodes.set(node.id, node); };
|
|
16
|
+
const lines = raw.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('%%'));
|
|
17
|
+
if (raw && !/^(?:graph|flowchart)\s+(?:LR|RL|TD|TB|BT)\b/i.test(lines[0] ?? ''))
|
|
18
|
+
issues.push('Diagram must start with a flowchart direction');
|
|
19
|
+
for (const original of lines) {
|
|
20
|
+
const line = original.replace(/;\s*$/, '');
|
|
21
|
+
if (/^(graph|flowchart|classDef|click\s|style\s|linkStyle|subgraph|end$)/i.test(line))
|
|
22
|
+
continue;
|
|
23
|
+
const cls = line.match(/^class\s+([\w\-,\s]+)\s+(entry|store|external|concern)$/);
|
|
24
|
+
if (cls) {
|
|
25
|
+
for (const id of cls[1].split(',').map(value => value.trim())) {
|
|
26
|
+
const node = nodes.get(id);
|
|
27
|
+
if (node)
|
|
28
|
+
node.role = cls[2];
|
|
29
|
+
}
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (/^class\s/.test(line))
|
|
33
|
+
continue;
|
|
34
|
+
const quoted = line.match(/^(.+?)\s+--\s+"([^"]+)"\s+-->\s+(.+)$/);
|
|
35
|
+
const parts = quoted ? [quoted[1], quoted[2], quoted[3]] : line.split(/(-->(?:\|[^|]*\|)?|--o|--x|---|-\.->|==>|~~>)/);
|
|
36
|
+
if (parts.length >= 3) {
|
|
37
|
+
for (let index = 0; index + 2 < parts.length; index += 2) {
|
|
38
|
+
const from = token(parts[index]), to = token(parts[index + 2]);
|
|
39
|
+
if (!from || !to) {
|
|
40
|
+
issues.push(`Unrecognized connection: ${line}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
put(from);
|
|
44
|
+
put(to);
|
|
45
|
+
const label = clean(quoted ? parts[index + 1] : (parts[index + 1].match(/\|([^|]*)\|/)?.[1] ?? '').replace(/^"|"$/g, ''));
|
|
46
|
+
edges.push({ from: from.id, to: to.id, label });
|
|
47
|
+
if (!label)
|
|
48
|
+
issues.push(`Connection needs a label: ${from.id} → ${to.id}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const node = token(line);
|
|
53
|
+
if (node)
|
|
54
|
+
put(node);
|
|
55
|
+
else
|
|
56
|
+
issues.push(`Unrecognized diagram line: ${line}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (nodes.size > 200 || edges.length > 600)
|
|
60
|
+
throw new Error('Diagram exceeds the architecture limit');
|
|
61
|
+
return { nodes: [...nodes.values()], edges, issues };
|
|
62
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight mermaid parser — extracts node IDs and edges from mermaid text.
|
|
3
|
+
* Handles: graph/flowchart LR/TD/TB, subgraph, and common arrow syntaxes.
|
|
4
|
+
*/
|
|
5
|
+
export function parseMermaid(text) {
|
|
6
|
+
const nodes = new Set();
|
|
7
|
+
const edges = new Set();
|
|
8
|
+
const lines = text.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('%%'));
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
// Skip directives, classDef, click, style, etc.
|
|
11
|
+
if (/^(graph|flowchart|sequenceDiagram|classDiagram|erDiagram|gantt|pie|gitGraph)/i.test(line))
|
|
12
|
+
continue;
|
|
13
|
+
if (/^(classDef|class |click |style |linkStyle|subgraph|end$)/i.test(line))
|
|
14
|
+
continue;
|
|
15
|
+
if (/^%%\{/.test(line))
|
|
16
|
+
continue;
|
|
17
|
+
// Match edges: A --> B, A -->|label| B, A -- text --> B, etc.
|
|
18
|
+
const edgePattern = /^(\S+?)(?:\[.*?\]|(?:\(.*?\))|\{.*?\}|>.*?])?(\s*)(-->|--o|--x|---|-.->|==>|~~>|--\|.*?\|)(\s*)(\S+?)(?:\[.*?\]|(?:\(.*?\))|\{.*?\}|>.*?])?$/;
|
|
19
|
+
const edgeMatch = line.match(edgePattern);
|
|
20
|
+
if (edgeMatch) {
|
|
21
|
+
const [, src, , arrow, , dst] = edgeMatch;
|
|
22
|
+
const srcId = src.replace(/["']/g, '');
|
|
23
|
+
const dstId = dst.replace(/["']/g, '');
|
|
24
|
+
nodes.add(srcId);
|
|
25
|
+
nodes.add(dstId);
|
|
26
|
+
edges.add(`${srcId} ${arrow} ${dstId}`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Broader edge match for complex syntax: A[Label] --> B[Label]
|
|
30
|
+
const broadEdge = /^([^\s[\]({]+).*?(-->|--o|--x|---|-.->|==>|~~>).*?([^\s[\]({]+)/;
|
|
31
|
+
const broadMatch = line.match(broadEdge);
|
|
32
|
+
if (broadMatch) {
|
|
33
|
+
const [, src, arrow, dst] = broadMatch;
|
|
34
|
+
const srcId = src.replace(/["']/g, '');
|
|
35
|
+
const dstId = dst.replace(/["']/g, '');
|
|
36
|
+
nodes.add(srcId);
|
|
37
|
+
nodes.add(dstId);
|
|
38
|
+
edges.add(`${srcId} ${arrow} ${dstId}`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Standalone node: A[Label] or A((Label)) or A{Label}
|
|
42
|
+
const nodeMatch = line.match(/^([^\s[\]({]+)[\[({]/);
|
|
43
|
+
if (nodeMatch) {
|
|
44
|
+
nodes.add(nodeMatch[1].replace(/["']/g, ''));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { nodes, edges };
|
|
48
|
+
}
|
|
49
|
+
export function diffMermaid(before, after) {
|
|
50
|
+
const prev = parseMermaid(before);
|
|
51
|
+
const curr = parseMermaid(after);
|
|
52
|
+
const added_nodes = [...curr.nodes].filter(n => !prev.nodes.has(n));
|
|
53
|
+
const removed_nodes = [...prev.nodes].filter(n => !curr.nodes.has(n));
|
|
54
|
+
const added_edges = [...curr.edges].filter(e => !prev.edges.has(e));
|
|
55
|
+
const removed_edges = [...prev.edges].filter(e => !curr.edges.has(e));
|
|
56
|
+
return {
|
|
57
|
+
added_nodes,
|
|
58
|
+
removed_nodes,
|
|
59
|
+
added_edges,
|
|
60
|
+
removed_edges,
|
|
61
|
+
has_changes: added_nodes.length > 0 || removed_nodes.length > 0 || added_edges.length > 0 || removed_edges.length > 0,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function formatDiff(diff) {
|
|
65
|
+
if (!diff.has_changes)
|
|
66
|
+
return 'No changes detected.\n';
|
|
67
|
+
const lines = [];
|
|
68
|
+
if (diff.added_nodes.length) {
|
|
69
|
+
lines.push('Added nodes:');
|
|
70
|
+
diff.added_nodes.forEach(n => lines.push(` + ${n}`));
|
|
71
|
+
}
|
|
72
|
+
if (diff.removed_nodes.length) {
|
|
73
|
+
lines.push('Removed nodes:');
|
|
74
|
+
diff.removed_nodes.forEach(n => lines.push(` - ${n}`));
|
|
75
|
+
}
|
|
76
|
+
if (diff.added_edges.length) {
|
|
77
|
+
lines.push('Added edges:');
|
|
78
|
+
diff.added_edges.forEach(e => lines.push(` + ${e}`));
|
|
79
|
+
}
|
|
80
|
+
if (diff.removed_edges.length) {
|
|
81
|
+
lines.push('Removed edges:');
|
|
82
|
+
diff.removed_edges.forEach(e => lines.push(` - ${e}`));
|
|
83
|
+
}
|
|
84
|
+
return lines.join('\n') + '\n';
|
|
85
|
+
}
|