termdock 1.4.174 → 1.4.175

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.
Files changed (355) hide show
  1. package/.desktop-dist/main.js +154 -7
  2. package/dist/client/assets/App-BXYZyI_k.js +150 -0
  3. package/dist/client/assets/App-BXYZyI_k.js.br +0 -0
  4. package/dist/client/assets/App-BXYZyI_k.js.gz +0 -0
  5. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js +2 -0
  6. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js.br +0 -0
  7. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js.gz +0 -0
  8. package/dist/client/assets/DagPlayground-ZIqLZoMo.js +1 -0
  9. package/dist/client/assets/DagPlayground-ZIqLZoMo.js.br +0 -0
  10. package/dist/client/assets/DagPlayground-ZIqLZoMo.js.gz +0 -0
  11. package/dist/client/assets/{DiffLab-CdbPsjKS.js → DiffLab-CSMf8So2.js} +2 -2
  12. package/dist/client/assets/DiffLab-CSMf8So2.js.br +0 -0
  13. package/dist/client/assets/DiffLab-CSMf8So2.js.gz +0 -0
  14. package/dist/client/assets/DiffReview-CE5lW1zQ.js +1 -0
  15. package/dist/client/assets/DiffReview-CE5lW1zQ.js.br +0 -0
  16. package/dist/client/assets/DiffReview-CE5lW1zQ.js.gz +0 -0
  17. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js +2 -0
  18. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js.br +0 -0
  19. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js.gz +0 -0
  20. package/dist/client/assets/{DiffViewer-hdxcM9yF.js → DiffViewer-BomvZ4kq.js} +5 -5
  21. package/dist/client/assets/DiffViewer-BomvZ4kq.js.br +0 -0
  22. package/dist/client/assets/DiffViewer-BomvZ4kq.js.gz +0 -0
  23. package/dist/client/assets/{ModelPreview-BZ454pgM.js → ModelPreview-BWdZFyhh.js} +3 -3
  24. package/dist/client/assets/ModelPreview-BWdZFyhh.js.br +0 -0
  25. package/dist/client/assets/ModelPreview-BWdZFyhh.js.gz +0 -0
  26. package/dist/client/assets/RightSidebar-CYVwFbOc.js +79 -0
  27. package/dist/client/assets/RightSidebar-CYVwFbOc.js.br +0 -0
  28. package/dist/client/assets/RightSidebar-CYVwFbOc.js.gz +0 -0
  29. package/dist/client/assets/{abnfDiagram-VCTEODGH-C185Omck.js → abnfDiagram-VCTEODGH-BIPsLStE.js} +1 -1
  30. package/dist/client/assets/abnfDiagram-VCTEODGH-BIPsLStE.js.br +0 -0
  31. package/dist/client/assets/abnfDiagram-VCTEODGH-BIPsLStE.js.gz +0 -0
  32. package/dist/client/assets/app-D6KzR8B3.js +34 -0
  33. package/dist/client/assets/app-D6KzR8B3.js.br +0 -0
  34. package/dist/client/assets/app-D6KzR8B3.js.gz +0 -0
  35. package/dist/client/assets/{arc-DNt-DTCl.js → arc-DzeT6hBj.js} +1 -1
  36. package/dist/client/assets/arc-DzeT6hBj.js.br +0 -0
  37. package/dist/client/assets/arc-DzeT6hBj.js.gz +0 -0
  38. package/dist/client/assets/{architectureDiagram-5GKGNRK7-C5Nwm_Qz.js → architectureDiagram-5GKGNRK7-B1qsxd_5.js} +1 -1
  39. package/dist/client/assets/architectureDiagram-5GKGNRK7-B1qsxd_5.js.br +0 -0
  40. package/dist/client/assets/architectureDiagram-5GKGNRK7-B1qsxd_5.js.gz +0 -0
  41. package/dist/client/assets/{blockDiagram-I7D4REHJ-C5aR_7V9.js → blockDiagram-I7D4REHJ-NLsa29Jp.js} +1 -1
  42. package/dist/client/assets/blockDiagram-I7D4REHJ-NLsa29Jp.js.br +0 -0
  43. package/dist/client/assets/blockDiagram-I7D4REHJ-NLsa29Jp.js.gz +0 -0
  44. package/dist/client/assets/{c4Diagram-7LVT6UL2-DjV6ZNwd.js → c4Diagram-7LVT6UL2-DBAUvou3.js} +1 -1
  45. package/dist/client/assets/c4Diagram-7LVT6UL2-DBAUvou3.js.br +0 -0
  46. package/dist/client/assets/c4Diagram-7LVT6UL2-DBAUvou3.js.gz +0 -0
  47. package/dist/client/assets/channel-BhwBAWhq.js +1 -0
  48. package/dist/client/assets/{chunk-2Q5K7J3B-Ct7nd4cL.js → chunk-2Q5K7J3B-BsVAXGLa.js} +1 -1
  49. package/dist/client/assets/{chunk-5VM5RSS4-CXem4UYP.js → chunk-5VM5RSS4-BKtILsst.js} +1 -1
  50. package/dist/client/assets/{chunk-F27PBJKO-DyMNEawE.js → chunk-F27PBJKO-Dn9zcQZG.js} +1 -1
  51. package/dist/client/assets/chunk-F27PBJKO-Dn9zcQZG.js.br +0 -0
  52. package/dist/client/assets/chunk-F27PBJKO-Dn9zcQZG.js.gz +0 -0
  53. package/dist/client/assets/{chunk-IMKFNOWR-BsW7iIrh.js → chunk-IMKFNOWR-MVtVQeTr.js} +1 -1
  54. package/dist/client/assets/chunk-IMKFNOWR-MVtVQeTr.js.br +0 -0
  55. package/dist/client/assets/{chunk-IMKFNOWR-BsW7iIrh.js.gz → chunk-IMKFNOWR-MVtVQeTr.js.gz} +0 -0
  56. package/dist/client/assets/{chunk-JWPE2WC7-EO8E1q1J.js → chunk-JWPE2WC7-DliIIMe7.js} +1 -1
  57. package/dist/client/assets/{chunk-POPQ4Y6H-0One8T9x.js → chunk-POPQ4Y6H-XBSus3IC.js} +1 -1
  58. package/dist/client/assets/{chunk-SVP7TREG-CDu41dkj.js → chunk-SVP7TREG-wleSQcJR.js} +1 -1
  59. package/dist/client/assets/chunk-SVP7TREG-wleSQcJR.js.br +0 -0
  60. package/dist/client/assets/chunk-SVP7TREG-wleSQcJR.js.gz +0 -0
  61. package/dist/client/assets/{chunk-TICWLB2K-BACjgX9v.js → chunk-TICWLB2K-Dq6LdswN.js} +1 -1
  62. package/dist/client/assets/chunk-TICWLB2K-Dq6LdswN.js.br +0 -0
  63. package/dist/client/assets/chunk-TICWLB2K-Dq6LdswN.js.gz +0 -0
  64. package/dist/client/assets/{chunk-XXDRQBXY-BJWowF6E.js → chunk-XXDRQBXY-xafyKlM-.js} +1 -1
  65. package/dist/client/assets/classDiagram-ZZMXUADV-slQB0ns2.js +1 -0
  66. package/dist/client/assets/classDiagram-v2-VYDZK3BY-slQB0ns2.js +1 -0
  67. package/dist/client/assets/{cose-bilkent-JH36ORCC-WTwHOCdm.js → cose-bilkent-JH36ORCC-BR7Ohnm_.js} +1 -1
  68. package/dist/client/assets/cose-bilkent-JH36ORCC-BR7Ohnm_.js.br +0 -0
  69. package/dist/client/assets/cose-bilkent-JH36ORCC-BR7Ohnm_.js.gz +0 -0
  70. package/dist/client/assets/{cynefin-OW5HDTMX-D4y8TkaO.js → cynefin-OW5HDTMX-CmPjQgER.js} +1 -1
  71. package/dist/client/assets/cynefin-OW5HDTMX-CmPjQgER.js.br +0 -0
  72. package/dist/client/assets/cynefin-OW5HDTMX-CmPjQgER.js.gz +0 -0
  73. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js → cynefinDiagram-5FMLGOSQ-CFyR9RvM.js} +1 -1
  74. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CFyR9RvM.js.br +0 -0
  75. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CFyR9RvM.js.gz +0 -0
  76. package/dist/client/assets/{dagre-GXQ25YYZ-CwMYtt5E.js → dagre-GXQ25YYZ-D_RVMRO1.js} +1 -1
  77. package/dist/client/assets/dagre-GXQ25YYZ-D_RVMRO1.js.br +0 -0
  78. package/dist/client/assets/dagre-GXQ25YYZ-D_RVMRO1.js.gz +0 -0
  79. package/dist/client/assets/{diagram-S7CK7UJ4-BnTeHiAb.js → diagram-S7CK7UJ4-6fr-ZoPj.js} +1 -1
  80. package/dist/client/assets/diagram-S7CK7UJ4-6fr-ZoPj.js.br +0 -0
  81. package/dist/client/assets/diagram-S7CK7UJ4-6fr-ZoPj.js.gz +0 -0
  82. package/dist/client/assets/{diagram-UQ7AKVKN-BNlh251g.js → diagram-UQ7AKVKN-CgwiUtz0.js} +1 -1
  83. package/dist/client/assets/diagram-UQ7AKVKN-CgwiUtz0.js.br +0 -0
  84. package/dist/client/assets/diagram-UQ7AKVKN-CgwiUtz0.js.gz +0 -0
  85. package/dist/client/assets/{diagram-VSXAHHWV-B5FftXkQ.js → diagram-VSXAHHWV-CLxzTB9k.js} +1 -1
  86. package/dist/client/assets/diagram-VSXAHHWV-CLxzTB9k.js.br +0 -0
  87. package/dist/client/assets/diagram-VSXAHHWV-CLxzTB9k.js.gz +0 -0
  88. package/dist/client/assets/{diagram-VX7I27RA-C51ZNXR2.js → diagram-VX7I27RA-DjxDAvdZ.js} +1 -1
  89. package/dist/client/assets/diagram-VX7I27RA-DjxDAvdZ.js.br +0 -0
  90. package/dist/client/assets/diagram-VX7I27RA-DjxDAvdZ.js.gz +0 -0
  91. package/dist/client/assets/{diagram-Z3DM3KII-CXoZH2qf.js → diagram-Z3DM3KII-CDPOjiz4.js} +1 -1
  92. package/dist/client/assets/diagram-Z3DM3KII-CDPOjiz4.js.br +0 -0
  93. package/dist/client/assets/diagram-Z3DM3KII-CDPOjiz4.js.gz +0 -0
  94. package/dist/client/assets/{ebnfDiagram-PWID7BFC-C7YFLlx4.js → ebnfDiagram-PWID7BFC-BLbwyF1O.js} +1 -1
  95. package/dist/client/assets/ebnfDiagram-PWID7BFC-BLbwyF1O.js.br +0 -0
  96. package/dist/client/assets/ebnfDiagram-PWID7BFC-BLbwyF1O.js.gz +0 -0
  97. package/dist/client/assets/{erDiagram-RLTQ6QDP-BNQlS7-g.js → erDiagram-RLTQ6QDP-DbjtZnJx.js} +1 -1
  98. package/dist/client/assets/erDiagram-RLTQ6QDP-DbjtZnJx.js.br +0 -0
  99. package/dist/client/assets/erDiagram-RLTQ6QDP-DbjtZnJx.js.gz +0 -0
  100. package/dist/client/assets/{flowDiagram-HODETNUW-DIQXZ06I.js → flowDiagram-HODETNUW-BirJInAN.js} +1 -1
  101. package/dist/client/assets/flowDiagram-HODETNUW-BirJInAN.js.br +0 -0
  102. package/dist/client/assets/flowDiagram-HODETNUW-BirJInAN.js.gz +0 -0
  103. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-BaJQfOqD.js → ganttDiagram-EL5Y4UJY-d6Q9vSbv.js} +1 -1
  104. package/dist/client/assets/ganttDiagram-EL5Y4UJY-d6Q9vSbv.js.br +0 -0
  105. package/dist/client/assets/ganttDiagram-EL5Y4UJY-d6Q9vSbv.js.gz +0 -0
  106. package/dist/client/assets/gestureArbiter-C2J0D0kV.css +1 -0
  107. package/dist/client/assets/gestureArbiter-C2J0D0kV.css.br +0 -0
  108. package/dist/client/assets/gestureArbiter-C2J0D0kV.css.gz +0 -0
  109. package/dist/client/assets/gestureArbiter-D1SNS_gK.js +1 -0
  110. package/dist/client/assets/gestureArbiter-D1SNS_gK.js.br +0 -0
  111. package/dist/client/assets/gestureArbiter-D1SNS_gK.js.gz +0 -0
  112. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js → gitGraphDiagram-WWUBYQGX-BWBoIeS6.js} +1 -1
  113. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BWBoIeS6.js.br +0 -0
  114. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BWBoIeS6.js.gz +0 -0
  115. package/dist/client/assets/{index-DlxiaPv1.css → index-DUI8KRf6.css} +1 -1
  116. package/dist/client/assets/index-DUI8KRf6.css.br +0 -0
  117. package/dist/client/assets/index-DUI8KRf6.css.gz +0 -0
  118. package/dist/client/assets/{infoDiagram-27XIBGKW-DTOUeQrN.js → infoDiagram-27XIBGKW-BH4AynkM.js} +1 -1
  119. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-8sBi-gla.js → ishikawaDiagram-5VMMS53U-BQw90AKR.js} +1 -1
  120. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-8sBi-gla.js.br → ishikawaDiagram-5VMMS53U-BQw90AKR.js.br} +0 -0
  121. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BQw90AKR.js.gz +0 -0
  122. package/dist/client/assets/{journeyDiagram-3NMN7TZE-ZwikziWh.js → journeyDiagram-3NMN7TZE-DISkQocf.js} +1 -1
  123. package/dist/client/assets/journeyDiagram-3NMN7TZE-DISkQocf.js.br +0 -0
  124. package/dist/client/assets/{journeyDiagram-3NMN7TZE-ZwikziWh.js.gz → journeyDiagram-3NMN7TZE-DISkQocf.js.gz} +0 -0
  125. package/dist/client/assets/{kanban-definition-UXKFOSKX-wjuw2jQ4.js → kanban-definition-UXKFOSKX-Qg2LyEVy.js} +1 -1
  126. package/dist/client/assets/kanban-definition-UXKFOSKX-Qg2LyEVy.js.br +0 -0
  127. package/dist/client/assets/kanban-definition-UXKFOSKX-Qg2LyEVy.js.gz +0 -0
  128. package/dist/client/assets/{layout-nASMIj-E.js → layout-Cd7-4_Vr.js} +1 -1
  129. package/dist/client/assets/layout-Cd7-4_Vr.js.br +0 -0
  130. package/dist/client/assets/layout-Cd7-4_Vr.js.gz +0 -0
  131. package/dist/client/assets/{linear-pGaQeqW5.js → linear-DFTi2fTn.js} +1 -1
  132. package/dist/client/assets/linear-DFTi2fTn.js.br +0 -0
  133. package/dist/client/assets/linear-DFTi2fTn.js.gz +0 -0
  134. package/dist/client/assets/{mermaid.core-CKEBWbQz.js → mermaid.core-2v726lUU.js} +5 -5
  135. package/dist/client/assets/mermaid.core-2v726lUU.js.br +0 -0
  136. package/dist/client/assets/mermaid.core-2v726lUU.js.gz +0 -0
  137. package/dist/client/assets/{mindmap-definition-YA3MSWOX-CBjYcnwd.js → mindmap-definition-YA3MSWOX-_FpwteCy.js} +4 -4
  138. package/dist/client/assets/mindmap-definition-YA3MSWOX-_FpwteCy.js.br +0 -0
  139. package/dist/client/assets/mindmap-definition-YA3MSWOX-_FpwteCy.js.gz +0 -0
  140. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js +2 -0
  141. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js.br +0 -0
  142. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js.gz +0 -0
  143. package/dist/client/assets/{pegDiagram-XKGWAZYB-DJqvclIp.js → pegDiagram-XKGWAZYB-DLFf-HmZ.js} +1 -1
  144. package/dist/client/assets/pegDiagram-XKGWAZYB-DLFf-HmZ.js.br +0 -0
  145. package/dist/client/assets/pegDiagram-XKGWAZYB-DLFf-HmZ.js.gz +0 -0
  146. package/dist/client/assets/{pieDiagram-E7YTZNPT-DLV4WPwc.js → pieDiagram-E7YTZNPT-DqTnfXHG.js} +1 -1
  147. package/dist/client/assets/pieDiagram-E7YTZNPT-DqTnfXHG.js.br +0 -0
  148. package/dist/client/assets/pieDiagram-E7YTZNPT-DqTnfXHG.js.gz +0 -0
  149. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BN7Zpsb9.js → quadrantDiagram-AXDQQJYC-B_oBH52Q.js} +1 -1
  150. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B_oBH52Q.js.br +0 -0
  151. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B_oBH52Q.js.gz +0 -0
  152. package/dist/client/assets/{railroadDiagram-O6MQD6OU-DfHX6MUm.js → railroadDiagram-O6MQD6OU-HxFQ7Pce.js} +1 -1
  153. package/dist/client/assets/railroadDiagram-O6MQD6OU-HxFQ7Pce.js.br +0 -0
  154. package/dist/client/assets/railroadDiagram-O6MQD6OU-HxFQ7Pce.js.gz +0 -0
  155. package/dist/client/assets/referenceLongPress-B3NGIjvv.js +1 -0
  156. package/dist/client/assets/referenceLongPress-B3NGIjvv.js.br +0 -0
  157. package/dist/client/assets/referenceLongPress-B3NGIjvv.js.gz +0 -0
  158. package/dist/client/assets/{requirementDiagram-BXWQKSXE-tQVSFg_k.js → requirementDiagram-BXWQKSXE-NZdfaZFk.js} +1 -1
  159. package/dist/client/assets/requirementDiagram-BXWQKSXE-NZdfaZFk.js.br +0 -0
  160. package/dist/client/assets/requirementDiagram-BXWQKSXE-NZdfaZFk.js.gz +0 -0
  161. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-C7JW1-Wh.js → sankeyDiagram-P5KCCOFB-BgCctv6X.js} +1 -1
  162. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BgCctv6X.js.br +0 -0
  163. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BgCctv6X.js.gz +0 -0
  164. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BVeDiFDI.js → sequenceDiagram-WJ2MYXX4-Br42Za1R.js} +1 -1
  165. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Br42Za1R.js.br +0 -0
  166. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Br42Za1R.js.gz +0 -0
  167. package/dist/client/assets/{sizeCapture-INFHLROL-CBRaCpeP.js → sizeCapture-INFHLROL-FT4z4S1b.js} +1 -1
  168. package/dist/client/assets/sizeCapture-INFHLROL-FT4z4S1b.js.br +0 -0
  169. package/dist/client/assets/sizeCapture-INFHLROL-FT4z4S1b.js.gz +0 -0
  170. package/dist/client/assets/sparkles-BaGaevME.js +1 -0
  171. package/dist/client/assets/{stateDiagram-D77RDMKH-CiLpGRuf.js → stateDiagram-D77RDMKH-DD0t9f84.js} +1 -1
  172. package/dist/client/assets/stateDiagram-D77RDMKH-DD0t9f84.js.br +0 -0
  173. package/dist/client/assets/stateDiagram-D77RDMKH-DD0t9f84.js.gz +0 -0
  174. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BhvVVB56.js +1 -0
  175. package/dist/client/assets/{swimlanes-42K2YHIH-BkzVtkVY.js → swimlanes-42K2YHIH-DcC8pGLx.js} +1 -1
  176. package/dist/client/assets/swimlanes-42K2YHIH-DcC8pGLx.js.br +0 -0
  177. package/dist/client/assets/swimlanes-42K2YHIH-DcC8pGLx.js.gz +0 -0
  178. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DSC5lz0i.js +8 -0
  179. package/dist/client/assets/{timeline-definition-24CTP7MA-DKyfGITP.js → timeline-definition-24CTP7MA-DnwO_Pxd.js} +1 -1
  180. package/dist/client/assets/timeline-definition-24CTP7MA-DnwO_Pxd.js.br +0 -0
  181. package/dist/client/assets/timeline-definition-24CTP7MA-DnwO_Pxd.js.gz +0 -0
  182. package/dist/client/assets/triangle-alert-BCQO9Ap9.js +1 -0
  183. package/dist/client/assets/{vennDiagram-4TSXK5OY-CRgkkrgx.js → vennDiagram-4TSXK5OY-IVNSrZDM.js} +1 -1
  184. package/dist/client/assets/vennDiagram-4TSXK5OY-IVNSrZDM.js.br +0 -0
  185. package/dist/client/assets/vennDiagram-4TSXK5OY-IVNSrZDM.js.gz +0 -0
  186. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js → wardleyDiagram-VM6X3IG4-BnGetaQL.js} +1 -1
  187. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BnGetaQL.js.br +0 -0
  188. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BnGetaQL.js.gz +0 -0
  189. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DkPYl6E0.js → xychartDiagram-S5SC5T6Z-C01eBN-W.js} +1 -1
  190. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C01eBN-W.js.br +0 -0
  191. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C01eBN-W.js.gz +0 -0
  192. package/dist/client/index.html +2 -2
  193. package/dist/client/index.html.br +0 -0
  194. package/dist/client/index.html.gz +0 -0
  195. package/dist/client/preview-shell.html +1 -0
  196. package/dist/client/preview-shell.js +20 -0
  197. package/dist/client/preview-shell.js.br +0 -0
  198. package/dist/client/preview-shell.js.gz +0 -0
  199. package/dist/client/sw-secure-api.js +132 -0
  200. package/dist/client/sw-secure-api.js.br +0 -0
  201. package/dist/client/sw-secure-api.js.gz +0 -0
  202. package/dist/client/sw.js +1 -1
  203. package/dist/client/sw.js.br +0 -0
  204. package/dist/client/sw.js.gz +0 -0
  205. package/dist/server/agent/collaborationCli.js +298 -0
  206. package/dist/server/agent/collaborationPrompt.js +10 -2
  207. package/dist/server/agent/collaborationProtocol.js +50 -0
  208. package/dist/server/agent/collaborationRoutes.js +86 -0
  209. package/dist/server/agent/collaborationStore.js +249 -21
  210. package/dist/server/cli.js +28 -168
  211. package/dist/server/entry.js +114 -51
  212. package/dist/server/federation/accessPolicy.js +122 -0
  213. package/dist/server/federation/authorization.js +226 -0
  214. package/dist/server/federation/bootstrapCors.js +23 -0
  215. package/dist/server/federation/cli.js +185 -0
  216. package/dist/server/federation/deviceNames.js +29 -0
  217. package/dist/server/federation/directRoutes.js +72 -0
  218. package/dist/server/federation/invitations.js +123 -0
  219. package/dist/server/federation/openAccess.js +25 -0
  220. package/dist/server/federation/originPolicy.js +19 -0
  221. package/dist/server/federation/packets.js +116 -0
  222. package/dist/server/federation/passwordBootstrap.js +86 -0
  223. package/dist/server/federation/passwordLoginRoutes.js +98 -0
  224. package/dist/server/federation/relay.js +346 -0
  225. package/dist/server/federation/requestContext.js +4 -0
  226. package/dist/server/federation/routeAccess.js +124 -0
  227. package/dist/server/federation/routeInvitations.js +160 -0
  228. package/dist/server/federation/runtime.js +537 -0
  229. package/dist/server/federation/secureProtocol.js +223 -0
  230. package/dist/server/federation/socketDuplex.js +42 -0
  231. package/dist/server/federation/streamLimits.js +5 -0
  232. package/dist/server/routes/filesystem.js +2 -1
  233. package/dist/server/routes/terminal.js +40 -72
  234. package/dist/server/utils/authProtection.js +13 -0
  235. package/dist/server/utils/csrfProtection.js +3 -0
  236. package/dist/server/utils/publicSecurity.js +8 -3
  237. package/package.json +10 -3
  238. package/runtime-manifest.json +4 -4
  239. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js +0 -2
  240. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js.br +0 -0
  241. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js.gz +0 -0
  242. package/dist/client/assets/DagPlayground-BRoB8JX5.js +0 -1
  243. package/dist/client/assets/DagPlayground-BRoB8JX5.js.br +0 -0
  244. package/dist/client/assets/DagPlayground-BRoB8JX5.js.gz +0 -0
  245. package/dist/client/assets/DiffLab-CdbPsjKS.js.br +0 -0
  246. package/dist/client/assets/DiffLab-CdbPsjKS.js.gz +0 -0
  247. package/dist/client/assets/DiffReview-MQXjrRsW.js +0 -1
  248. package/dist/client/assets/DiffReview-MQXjrRsW.js.br +0 -0
  249. package/dist/client/assets/DiffReview-MQXjrRsW.js.gz +0 -0
  250. package/dist/client/assets/DiffReviewLab-C47CNvDM.js +0 -2
  251. package/dist/client/assets/DiffReviewLab-C47CNvDM.js.br +0 -0
  252. package/dist/client/assets/DiffReviewLab-C47CNvDM.js.gz +0 -0
  253. package/dist/client/assets/DiffViewer-hdxcM9yF.js.br +0 -0
  254. package/dist/client/assets/DiffViewer-hdxcM9yF.js.gz +0 -0
  255. package/dist/client/assets/ModelPreview-BZ454pgM.js.br +0 -0
  256. package/dist/client/assets/ModelPreview-BZ454pgM.js.gz +0 -0
  257. package/dist/client/assets/RightSidebar-i0Oq68YI.js +0 -55
  258. package/dist/client/assets/RightSidebar-i0Oq68YI.js.br +0 -0
  259. package/dist/client/assets/RightSidebar-i0Oq68YI.js.gz +0 -0
  260. package/dist/client/assets/abnfDiagram-VCTEODGH-C185Omck.js.br +0 -0
  261. package/dist/client/assets/abnfDiagram-VCTEODGH-C185Omck.js.gz +0 -0
  262. package/dist/client/assets/app-DAp8rVMc.js +0 -175
  263. package/dist/client/assets/app-DAp8rVMc.js.br +0 -0
  264. package/dist/client/assets/app-DAp8rVMc.js.gz +0 -0
  265. package/dist/client/assets/arc-DNt-DTCl.js.br +0 -0
  266. package/dist/client/assets/arc-DNt-DTCl.js.gz +0 -0
  267. package/dist/client/assets/architectureDiagram-5GKGNRK7-C5Nwm_Qz.js.br +0 -0
  268. package/dist/client/assets/architectureDiagram-5GKGNRK7-C5Nwm_Qz.js.gz +0 -0
  269. package/dist/client/assets/blockDiagram-I7D4REHJ-C5aR_7V9.js.br +0 -0
  270. package/dist/client/assets/blockDiagram-I7D4REHJ-C5aR_7V9.js.gz +0 -0
  271. package/dist/client/assets/c4Diagram-7LVT6UL2-DjV6ZNwd.js.br +0 -0
  272. package/dist/client/assets/c4Diagram-7LVT6UL2-DjV6ZNwd.js.gz +0 -0
  273. package/dist/client/assets/channel-uhLrATdy.js +0 -1
  274. package/dist/client/assets/chunk-F27PBJKO-DyMNEawE.js.br +0 -0
  275. package/dist/client/assets/chunk-F27PBJKO-DyMNEawE.js.gz +0 -0
  276. package/dist/client/assets/chunk-IMKFNOWR-BsW7iIrh.js.br +0 -0
  277. package/dist/client/assets/chunk-SVP7TREG-CDu41dkj.js.br +0 -0
  278. package/dist/client/assets/chunk-SVP7TREG-CDu41dkj.js.gz +0 -0
  279. package/dist/client/assets/chunk-TICWLB2K-BACjgX9v.js.br +0 -0
  280. package/dist/client/assets/chunk-TICWLB2K-BACjgX9v.js.gz +0 -0
  281. package/dist/client/assets/classDiagram-ZZMXUADV-CnxFfzm9.js +0 -1
  282. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CnxFfzm9.js +0 -1
  283. package/dist/client/assets/cose-bilkent-JH36ORCC-WTwHOCdm.js.br +0 -0
  284. package/dist/client/assets/cose-bilkent-JH36ORCC-WTwHOCdm.js.gz +0 -0
  285. package/dist/client/assets/cynefin-OW5HDTMX-D4y8TkaO.js.br +0 -0
  286. package/dist/client/assets/cynefin-OW5HDTMX-D4y8TkaO.js.gz +0 -0
  287. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js.br +0 -0
  288. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js.gz +0 -0
  289. package/dist/client/assets/dagre-GXQ25YYZ-CwMYtt5E.js.br +0 -0
  290. package/dist/client/assets/dagre-GXQ25YYZ-CwMYtt5E.js.gz +0 -0
  291. package/dist/client/assets/diagram-S7CK7UJ4-BnTeHiAb.js.br +0 -0
  292. package/dist/client/assets/diagram-S7CK7UJ4-BnTeHiAb.js.gz +0 -0
  293. package/dist/client/assets/diagram-UQ7AKVKN-BNlh251g.js.br +0 -0
  294. package/dist/client/assets/diagram-UQ7AKVKN-BNlh251g.js.gz +0 -0
  295. package/dist/client/assets/diagram-VSXAHHWV-B5FftXkQ.js.br +0 -0
  296. package/dist/client/assets/diagram-VSXAHHWV-B5FftXkQ.js.gz +0 -0
  297. package/dist/client/assets/diagram-VX7I27RA-C51ZNXR2.js.br +0 -0
  298. package/dist/client/assets/diagram-VX7I27RA-C51ZNXR2.js.gz +0 -0
  299. package/dist/client/assets/diagram-Z3DM3KII-CXoZH2qf.js.br +0 -0
  300. package/dist/client/assets/diagram-Z3DM3KII-CXoZH2qf.js.gz +0 -0
  301. package/dist/client/assets/ebnfDiagram-PWID7BFC-C7YFLlx4.js.br +0 -0
  302. package/dist/client/assets/ebnfDiagram-PWID7BFC-C7YFLlx4.js.gz +0 -0
  303. package/dist/client/assets/erDiagram-RLTQ6QDP-BNQlS7-g.js.br +0 -0
  304. package/dist/client/assets/erDiagram-RLTQ6QDP-BNQlS7-g.js.gz +0 -0
  305. package/dist/client/assets/flowDiagram-HODETNUW-DIQXZ06I.js.br +0 -0
  306. package/dist/client/assets/flowDiagram-HODETNUW-DIQXZ06I.js.gz +0 -0
  307. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BaJQfOqD.js.br +0 -0
  308. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BaJQfOqD.js.gz +0 -0
  309. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js.br +0 -0
  310. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js.gz +0 -0
  311. package/dist/client/assets/index-DlxiaPv1.css.br +0 -0
  312. package/dist/client/assets/index-DlxiaPv1.css.gz +0 -0
  313. package/dist/client/assets/ishikawaDiagram-5VMMS53U-8sBi-gla.js.gz +0 -0
  314. package/dist/client/assets/journeyDiagram-3NMN7TZE-ZwikziWh.js.br +0 -0
  315. package/dist/client/assets/kanban-definition-UXKFOSKX-wjuw2jQ4.js.br +0 -0
  316. package/dist/client/assets/kanban-definition-UXKFOSKX-wjuw2jQ4.js.gz +0 -0
  317. package/dist/client/assets/layout-nASMIj-E.js.br +0 -0
  318. package/dist/client/assets/layout-nASMIj-E.js.gz +0 -0
  319. package/dist/client/assets/linear-pGaQeqW5.js.br +0 -0
  320. package/dist/client/assets/linear-pGaQeqW5.js.gz +0 -0
  321. package/dist/client/assets/mermaid.core-CKEBWbQz.js.br +0 -0
  322. package/dist/client/assets/mermaid.core-CKEBWbQz.js.gz +0 -0
  323. package/dist/client/assets/mindmap-definition-YA3MSWOX-CBjYcnwd.js.br +0 -0
  324. package/dist/client/assets/mindmap-definition-YA3MSWOX-CBjYcnwd.js.gz +0 -0
  325. package/dist/client/assets/pegDiagram-XKGWAZYB-DJqvclIp.js.br +0 -0
  326. package/dist/client/assets/pegDiagram-XKGWAZYB-DJqvclIp.js.gz +0 -0
  327. package/dist/client/assets/pieDiagram-E7YTZNPT-DLV4WPwc.js.br +0 -0
  328. package/dist/client/assets/pieDiagram-E7YTZNPT-DLV4WPwc.js.gz +0 -0
  329. package/dist/client/assets/quadrantDiagram-AXDQQJYC-BN7Zpsb9.js.br +0 -0
  330. package/dist/client/assets/quadrantDiagram-AXDQQJYC-BN7Zpsb9.js.gz +0 -0
  331. package/dist/client/assets/railroadDiagram-O6MQD6OU-DfHX6MUm.js.br +0 -0
  332. package/dist/client/assets/railroadDiagram-O6MQD6OU-DfHX6MUm.js.gz +0 -0
  333. package/dist/client/assets/requirementDiagram-BXWQKSXE-tQVSFg_k.js.br +0 -0
  334. package/dist/client/assets/requirementDiagram-BXWQKSXE-tQVSFg_k.js.gz +0 -0
  335. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C7JW1-Wh.js.br +0 -0
  336. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C7JW1-Wh.js.gz +0 -0
  337. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BVeDiFDI.js.br +0 -0
  338. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BVeDiFDI.js.gz +0 -0
  339. package/dist/client/assets/sizeCapture-INFHLROL-CBRaCpeP.js.br +0 -0
  340. package/dist/client/assets/sizeCapture-INFHLROL-CBRaCpeP.js.gz +0 -0
  341. package/dist/client/assets/sparkles-D0cwIvB0.js +0 -1
  342. package/dist/client/assets/stateDiagram-D77RDMKH-CiLpGRuf.js.br +0 -0
  343. package/dist/client/assets/stateDiagram-D77RDMKH-CiLpGRuf.js.gz +0 -0
  344. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BRbS0rv2.js +0 -1
  345. package/dist/client/assets/swimlanes-42K2YHIH-BkzVtkVY.js.br +0 -0
  346. package/dist/client/assets/swimlanes-42K2YHIH-BkzVtkVY.js.gz +0 -0
  347. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CeWFezkt.js +0 -8
  348. package/dist/client/assets/timeline-definition-24CTP7MA-DKyfGITP.js.br +0 -0
  349. package/dist/client/assets/timeline-definition-24CTP7MA-DKyfGITP.js.gz +0 -0
  350. package/dist/client/assets/vennDiagram-4TSXK5OY-CRgkkrgx.js.br +0 -0
  351. package/dist/client/assets/vennDiagram-4TSXK5OY-CRgkkrgx.js.gz +0 -0
  352. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js.br +0 -0
  353. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js.gz +0 -0
  354. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DkPYl6E0.js.br +0 -0
  355. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DkPYl6E0.js.gz +0 -0
@@ -0,0 +1,223 @@
1
+ /** End-to-end byte transport. Cryptographic handshake and records are owned by noise-libp2p. */
2
+ import { noise, pureJsCrypto } from '@chainsafe/libp2p-noise';
3
+ import { generateKeyPair, privateKeyFromProtobuf, privateKeyToProtobuf } from '@libp2p/crypto/keys';
4
+ import { peerIdFromPublicKey, peerIdFromString } from '@libp2p/peer-id';
5
+ import { AbstractMessageStream } from '@libp2p/utils';
6
+ export const SECURE_PROTOCOL = 'termdock-e2ee-v1';
7
+ export const MAX_SECURE_CONNECTION_AGE_MS = 60 * 60 * 1000;
8
+ export const MAX_SECURE_CONNECTION_BYTES_PER_DIRECTION = 512 * 1024 * 1024;
9
+ const MAX_BUFFER_BYTES = 4 * 1024 * 1024;
10
+ const noop = () => { };
11
+ const silentLogger = Object.assign(noop, {
12
+ enabled: false, error: noop, trace: noop, newScope: () => silentLogger,
13
+ });
14
+ Object.freeze(silentLogger);
15
+ export async function createIdentity() {
16
+ const privateKey = await generateKeyPair('Ed25519');
17
+ return { privateKey, peerId: peerIdFromPublicKey(privateKey.publicKey).toString() };
18
+ }
19
+ /** Contains a private key. Store with device-private permissions, never include in pairing URLs. */
20
+ export function exportIdentity(identity) {
21
+ return btoa(String.fromCharCode(...privateKeyToProtobuf(identity.privateKey)));
22
+ }
23
+ export function importIdentity(serialized) {
24
+ if (serialized.length > 512 || !/^[A-Za-z0-9+/]+={0,2}$/.test(serialized))
25
+ throw new Error('Invalid identity encoding');
26
+ const privateKey = privateKeyFromProtobuf(Uint8Array.from(atob(serialized), c => c.charCodeAt(0)));
27
+ if (privateKey.type !== 'Ed25519')
28
+ throw new Error('Only Ed25519 device identities are supported');
29
+ return { privateKey, peerId: peerIdFromPublicKey(privateKey.publicKey).toString() };
30
+ }
31
+ /** Bounded bridge, not a cryptographic record layer. */
32
+ class ByteQueue {
33
+ consumed;
34
+ chunks = [];
35
+ size = 0;
36
+ ended = false;
37
+ error;
38
+ wake;
39
+ constructor(consumed = noop) {
40
+ this.consumed = consumed;
41
+ }
42
+ push(bytes) {
43
+ if (this.ended)
44
+ throw this.error ?? new Error('Byte stream closed');
45
+ if (this.size + bytes.byteLength > MAX_BUFFER_BYTES)
46
+ throw new Error('Secure stream buffer limit exceeded');
47
+ this.chunks.push(bytes.slice());
48
+ this.size += bytes.byteLength;
49
+ this.wake?.();
50
+ }
51
+ end(error) { this.ended = true; this.error ??= error; this.wake?.(); }
52
+ async *[Symbol.asyncIterator]() {
53
+ while (true) {
54
+ if (this.error)
55
+ throw this.error;
56
+ const chunk = this.chunks.shift();
57
+ if (chunk) {
58
+ this.size -= chunk.byteLength;
59
+ yield chunk;
60
+ this.consumed();
61
+ }
62
+ else if (this.ended)
63
+ return;
64
+ else
65
+ await new Promise(resolve => { this.wake = resolve; });
66
+ }
67
+ }
68
+ }
69
+ class TransportStream extends AbstractMessageStream {
70
+ duplex;
71
+ outgoing = new ByteQueue(() => this.onMuxerDrain());
72
+ finished;
73
+ constructor(duplex, initiator) {
74
+ super({ log: silentLogger, direction: initiator ? 'outbound' : 'inbound', maxReadBufferLength: MAX_BUFFER_BYTES, maxWriteBufferLength: MAX_BUFFER_BYTES });
75
+ this.duplex = duplex;
76
+ this.finished = duplex.sink(this.outgoing).catch(error => { this.abort(asError(error)); });
77
+ void this.readTransport();
78
+ }
79
+ async readTransport() {
80
+ try {
81
+ for await (const bytes of this.duplex.source)
82
+ this.onData(bytes.slice());
83
+ this.onTransportClosed();
84
+ }
85
+ catch (error) {
86
+ this.onTransportClosed(asError(error));
87
+ }
88
+ }
89
+ sendData(data) {
90
+ this.outgoing.push(data.subarray());
91
+ return { sentBytes: data.byteLength, canSendMore: false };
92
+ }
93
+ sendReset(error) { this.outgoing.end(error); this.duplex.close?.(error); }
94
+ sendPause() { }
95
+ sendResume() { }
96
+ async close() {
97
+ this.outgoing.end();
98
+ this.duplex.close?.();
99
+ this.onTransportClosed();
100
+ await this.finished;
101
+ }
102
+ }
103
+ function asError(value) { return value instanceof Error ? value : new Error('Secure transport failed'); }
104
+ export class SecureConnectionExpiredError extends Error {
105
+ code = 'E2EE_REHANDSHAKE_REQUIRED';
106
+ constructor() { super('Encrypted connection lifetime reached; establish a new handshake without replaying pending input'); }
107
+ }
108
+ function connectionLimits(limits) {
109
+ const maxAgeMs = limits?.maxAgeMs ?? MAX_SECURE_CONNECTION_AGE_MS;
110
+ const maxBytesPerDirection = limits?.maxBytesPerDirection ?? MAX_SECURE_CONNECTION_BYTES_PER_DIRECTION;
111
+ if (!Number.isSafeInteger(maxAgeMs) || maxAgeMs <= 0 || maxAgeMs > MAX_SECURE_CONNECTION_AGE_MS
112
+ || !Number.isSafeInteger(maxBytesPerDirection) || maxBytesPerDirection <= 0 || maxBytesPerDirection > MAX_SECURE_CONNECTION_BYTES_PER_DIRECTION) {
113
+ throw new Error('Encrypted connection limits cannot exceed the production maximum');
114
+ }
115
+ return { maxAgeMs, maxBytesPerDirection };
116
+ }
117
+ export async function secureConnection(options) {
118
+ const { identity, duplex, initiator, targetPinnedPeerId, signal } = options;
119
+ const limits = connectionLimits(options.limits);
120
+ if (typeof Reflect.get(Promise, 'withResolvers') !== 'function' || typeof globalThis.crypto?.getRandomValues !== 'function') {
121
+ throw new Error('End-to-end encryption requires Node.js 22+ or a modern browser with Promise.withResolvers and secure random support');
122
+ }
123
+ if (initiator && !targetPinnedPeerId)
124
+ throw new Error('A pinned target identity is required');
125
+ const remotePeer = targetPinnedPeerId ? peerIdFromString(targetPinnedPeerId) : undefined;
126
+ if (remotePeer && remotePeer.type !== 'Ed25519')
127
+ throw new Error('Only Ed25519 target identities are supported');
128
+ if (identity.peerId !== peerIdFromPublicKey(identity.privateKey.publicKey).toString())
129
+ throw new Error('Local identity mismatch');
130
+ if (signal?.aborted)
131
+ throw signal.reason ?? new Error('Connection aborted');
132
+ const transport = new TransportStream(duplex, initiator);
133
+ const handshake = new AbortController();
134
+ const timeout = setTimeout(() => {
135
+ const error = new Error('Encrypted handshake timed out');
136
+ handshake.abort(error);
137
+ transport.abort(error);
138
+ }, 15_000);
139
+ const abort = () => { handshake.abort(signal?.reason); transport.abort(asError(signal?.reason)); };
140
+ signal?.addEventListener('abort', abort, { once: true });
141
+ transport.addEventListener('close', () => signal?.removeEventListener('abort', abort), { once: true });
142
+ const encrypter = noise({ crypto: pureJsCrypto, prologueBytes: new TextEncoder().encode(SECURE_PROTOCOL) })({
143
+ privateKey: identity.privateKey,
144
+ peerId: peerIdFromPublicKey(identity.privateKey.publicKey),
145
+ logger: { forComponent: () => silentLogger },
146
+ // Only getStreamMuxers is needed, and negotiation is explicitly disabled.
147
+ upgrader: { getStreamMuxers: () => new Map() },
148
+ });
149
+ try {
150
+ const secured = await (initiator ? encrypter.secureOutbound(transport, { remotePeer, signal: handshake.signal, skipStreamMuxerNegotiation: true })
151
+ : encrypter.secureInbound(transport, { remotePeer, signal: handshake.signal, skipStreamMuxerNegotiation: true }));
152
+ if (secured.remotePeer.type !== 'Ed25519')
153
+ throw new Error('Unsupported remote identity');
154
+ return { authenticatedPeerId: secured.remotePeer.toString(), duplex: plaintextDuplex(secured.connection, limits) };
155
+ }
156
+ catch (error) {
157
+ transport.abort(asError(error));
158
+ throw error;
159
+ }
160
+ finally {
161
+ clearTimeout(timeout);
162
+ signal?.removeEventListener('abort', abort);
163
+ }
164
+ }
165
+ function plaintextDuplex(stream, limits) {
166
+ const incoming = new ByteQueue();
167
+ const establishedAt = performance.now(), establishedWallTime = Date.now();
168
+ let sentBytes = 0, receivedBytes = 0, expiredError;
169
+ const expire = () => {
170
+ expiredError ??= new SecureConnectionExpiredError();
171
+ incoming.end(expiredError);
172
+ stream.abort(expiredError);
173
+ return expiredError;
174
+ };
175
+ const lifetime = setTimeout(expire, limits.maxAgeMs);
176
+ if (typeof lifetime === 'object')
177
+ lifetime.unref?.();
178
+ const checkLimit = (alreadyTransferred, nextBytes) => {
179
+ if (expiredError)
180
+ throw expiredError;
181
+ // Check on traffic as well as the timer: a suspended PWA must not resume
182
+ // using an expired session key before its delayed timer gets a turn.
183
+ const age = Math.max(performance.now() - establishedAt, Date.now() - establishedWallTime);
184
+ if (age >= limits.maxAgeMs || alreadyTransferred + nextBytes >= limits.maxBytesPerDirection)
185
+ throw expire();
186
+ };
187
+ stream.addEventListener('message', event => {
188
+ try {
189
+ checkLimit(receivedBytes, event.data.byteLength);
190
+ receivedBytes += event.data.byteLength;
191
+ incoming.push(event.data.subarray());
192
+ }
193
+ catch (error) {
194
+ stream.abort(asError(error));
195
+ }
196
+ });
197
+ stream.addEventListener('close', event => { clearTimeout(lifetime); incoming.end(event.error); }, { once: true });
198
+ let writing = false;
199
+ return {
200
+ source: incoming,
201
+ async sink(source) {
202
+ if (writing)
203
+ throw new Error('Secure sink already consumed');
204
+ writing = true;
205
+ try {
206
+ for await (const chunk of source) {
207
+ checkLimit(sentBytes, chunk.byteLength);
208
+ sentBytes += chunk.byteLength;
209
+ if (!stream.send(chunk))
210
+ await stream.onDrain();
211
+ }
212
+ }
213
+ catch (error) {
214
+ stream.abort(asError(error));
215
+ throw error;
216
+ }
217
+ },
218
+ close(error) { if (error)
219
+ stream.abort(error);
220
+ else
221
+ void stream.close(); },
222
+ };
223
+ }
@@ -0,0 +1,42 @@
1
+ import { AsyncQueue } from './packets.js';
2
+ export function socketDuplex(socket) {
3
+ const input = new AsyncQueue(64);
4
+ socket.binaryType = 'arraybuffer';
5
+ const close = (error) => { input.end(error); socket.close(1000); };
6
+ socket.addEventListener('message', event => {
7
+ try {
8
+ if (!(event.data instanceof ArrayBuffer) || event.data.byteLength > 1024 * 1024)
9
+ throw new Error('Invalid encrypted frame');
10
+ input.push(new Uint8Array(event.data));
11
+ }
12
+ catch {
13
+ close(new Error('Encrypted transport rejected frame'));
14
+ }
15
+ });
16
+ socket.addEventListener('close', () => input.end());
17
+ socket.addEventListener('error', () => input.end(new Error('Encrypted transport disconnected')));
18
+ return {
19
+ source: input, close,
20
+ async sink(source) {
21
+ try {
22
+ for await (const chunk of source) {
23
+ for (let offset = 0; offset < chunk.length; offset += 64 * 1024) {
24
+ const started = Date.now();
25
+ while (socket.bufferedAmount > 256 * 1024) {
26
+ if (socket.readyState !== 1 || Date.now() - started > 15000)
27
+ throw new Error('Encrypted transport congested');
28
+ await new Promise(resolve => setTimeout(resolve, 10));
29
+ }
30
+ if (socket.readyState !== 1)
31
+ throw new Error('Encrypted transport closed');
32
+ socket.send(chunk.subarray(offset, offset + 64 * 1024));
33
+ }
34
+ }
35
+ }
36
+ catch (error) {
37
+ close(error instanceof Error ? error : new Error('Encrypted transport failed'));
38
+ throw error;
39
+ }
40
+ },
41
+ };
42
+ }
@@ -0,0 +1,5 @@
1
+ // Long-lived terminal subscriptions have an independent budget from short HTTP
2
+ // operations. Normal browser requests queue below the server's defensive ceiling.
3
+ export const MAX_ACTIVE_HTTP_REQUESTS = 8;
4
+ export const MAX_SERVER_HTTP_REQUESTS = 32;
5
+ export const MAX_OPEN_SECURE_SOCKETS = 128;
@@ -9,6 +9,7 @@ import busboy from 'busboy';
9
9
  import { validatePreview } from '../utils/previewValidation.js';
10
10
  import { pathValidator } from '../utils/pathValidator.js';
11
11
  import { isAuthEnabled, isRequestAuthenticated } from '../utils/authProtection.js';
12
+ import { isEncryptedRequest } from '../federation/requestContext.js';
12
13
  import { getImageDimensions, parseImageDimensions } from '../utils/imageDimensions.js';
13
14
  import { writeDiffTraceLog, writeErrorLog, writeJsonLog } from '../utils/serverLogger.js';
14
15
  import { clearBranchAuditRecords, clearChangeAuditRecords, listBranchAuditRecords, listChangeAuditRecords, buildChangeAuditFingerprint } from '../utils/changeAuditStore.js';
@@ -3656,7 +3657,7 @@ router.get('/preview/*path', async (req, res) => {
3656
3657
  // previewed file's directory, so the sandboxed iframe's subresources can
3657
3658
  // load without cookies. The token segment in the URL is inherited by every
3658
3659
  // relative reference the document makes.
3659
- if (authEnabled && !maybeToken) {
3660
+ if ((authEnabled || isEncryptedRequest(req)) && !maybeToken) {
3660
3661
  const root = stat.isDirectory() ? validatedPath : path.dirname(validatedPath);
3661
3662
  const tokenized = tokenizePreviewUrl(previewBaseUrl, mintPreviewToken(root, req.cookies?.[AUTH_COOKIE]));
3662
3663
  redirectUrl = stat.isDirectory() && !previewBaseUrl.endsWith('/') ? `${tokenized}/` : tokenized;
@@ -33,6 +33,8 @@ import { AgentResumeHistoryStore } from '../agent/resumeHistory.js';
33
33
  import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
34
34
  import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
35
35
  import { buildBracketedSubmitBytes, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
36
+ import { collaborationRoutes } from '../agent/collaborationRoutes.js';
37
+ import { COLLAB_LIMITS, extrasFromBody } from '../agent/collaborationProtocol.js';
36
38
  import { CollaborationStore } from '../agent/collaborationStore.js';
37
39
  import { formatCollaborationDelivery } from '../agent/collaborationPrompt.js';
38
40
  import { resolveCollaborationSpawnMode } from '../agent/collaborationSpawn.js';
@@ -1266,6 +1268,7 @@ function orchestrationSessionSnapshot(record) {
1266
1268
  const agent = backend?.agent ?? (record.agentResume?.slug ? agentBySlug(record.agentResume.slug) : null);
1267
1269
  const latestPrompt = backend?.autoTitlePromptPayloads.at(-1)?.trim() ?? '';
1268
1270
  return {
1271
+ ...collaborationStore.sessionFacts(record.sessionId, Boolean(backend), backend?.agentSession?.status),
1269
1272
  sessionId: record.sessionId,
1270
1273
  agentNativeSessionId: backend?.agentSession?.sessionId ?? record.agentResume?.sessionId ?? null,
1271
1274
  backendSessionId: record.backendSessionId ?? null,
@@ -1367,13 +1370,13 @@ function resolveFrontendSessionId(input) {
1367
1370
  }
1368
1371
  function collaborationRemoteSessions() {
1369
1372
  return Array.from(new Map(collaborationStore.list().flatMap((group) => group.remoteSessions ?? [])
1370
- .map((session) => [session.sessionId, { ...session, status: session.serviceConnected !== true || Date.now() - (session.serviceCheckedAt ?? 0) > 15_000 ? 'service-unreachable' : session.status, name: `${session.name} · ${session.serviceLabel}` }])).values());
1373
+ .map((session) => [session.sessionId, { ...session, ...collaborationStore.sessionFacts(session.sessionId, session.serviceConnected === true && Date.now() - (session.serviceCheckedAt ?? 0) <= 15_000, session.status), status: session.serviceConnected !== true || Date.now() - (session.serviceCheckedAt ?? 0) > 15_000 ? 'service-unreachable' : session.status, name: `${session.name} · ${session.serviceLabel}` }])).values());
1371
1374
  }
1372
1375
  function tryDeliverCollaborationInbox(frontendSessionId) {
1373
1376
  const remote = collaborationRemoteSessions().find((session) => session.sessionId === frontendSessionId);
1374
1377
  if (remote) {
1375
1378
  const unavailable = remote.serviceConnected !== true || Date.now() - (remote.serviceCheckedAt ?? 0) > 15_000;
1376
- return { delivered: [], pending: collaborationStore.inbox(frontendSessionId, { pendingOnly: true }).length,
1379
+ return { delivered: [], pending: collaborationStore.pendingCount(frontendSessionId),
1377
1380
  serviceUnavailable: unavailable, reason: unavailable
1378
1381
  ? `服务 ${remote.serviceLabel} 不可达:消息尚未送达,仅保存在待发送队列;请勿等待对方已收到的回复,服务重连且 Mac 客户端运行后重试投递。`
1379
1382
  : '跨服务消息尚未确认送达,正在等待 Mac 客户端转发。' };
@@ -1400,9 +1403,23 @@ function tryDeliverCollaborationInbox(frontendSessionId) {
1400
1403
  };
1401
1404
  })],
1402
1405
  });
1403
- session.ptyProcess.write(buildBracketedSubmitBytes(prompt));
1406
+ try {
1407
+ session.ptyProcess.write(buildBracketedSubmitBytes(prompt));
1408
+ }
1409
+ catch (error) {
1410
+ for (const message of pending)
1411
+ collaborationStore.recordTransport(message.id, {
1412
+ relay_online: null, peer_reachable: true, attempt_count: (collaborationStore.diagnostic(message.id)?.attempt_count ?? 0) + 1,
1413
+ next_retry_at: Date.now() + 2_000, last_error: `PTY_WRITE_FAILED: ${getErrorMessage(error)}`, checked_at: Date.now(),
1414
+ });
1415
+ setTimeout(() => tryDeliverCollaborationInbox(frontendSessionId), 2_000).unref?.();
1416
+ return { delivered: [], pending: collaborationStore.pendingCount(frontendSessionId), reason: '终端写入失败,消息已保留并等待重试' };
1417
+ }
1404
1418
  collaborationStore.markDelivered(pending.map((message) => message.id));
1405
- return { delivered: pending.map((message) => message.id), pending: 0 };
1419
+ const remaining = collaborationStore.pendingCount(frontendSessionId);
1420
+ if (remaining)
1421
+ setTimeout(() => tryDeliverCollaborationInbox(frontendSessionId), 300).unref?.();
1422
+ return { delivered: pending.map((message) => message.id), pending: remaining };
1406
1423
  }
1407
1424
  async function refreshCollaborationAgentIdentity(backendSessionId, session) {
1408
1425
  let activeProgram = null;
@@ -5203,7 +5220,7 @@ router.delete('/operations/automations/:automationId', (req, res) => {
5203
5220
  // Authenticated desktop connections exchange only collaboration data; no peer credentials
5204
5221
  // or arbitrary remote URLs are accepted by the server.
5205
5222
  router.get('/operations/collaboration-federation', (_req, res) => {
5206
- res.json({ ...collaborationStore.federationSnapshot(),
5223
+ res.json({ protocolVersion: 2, limits: COLLAB_LIMITS, ...collaborationStore.federationSnapshot(),
5207
5224
  sessions: globalSessionState.sessions.map(orchestrationSessionSnapshot) });
5208
5225
  });
5209
5226
  router.post('/operations/collaboration-federation', (req, res) => {
@@ -5218,10 +5235,21 @@ router.post('/operations/collaboration-federation', (req, res) => {
5218
5235
  }
5219
5236
  collaborationStore.mergeFederatedGroup(group);
5220
5237
  collaborationStore.mergeFederatedMessages(Array.isArray(req.body.messages) ? req.body.messages : []);
5238
+ const fragments = Array.isArray(req.body.fragments) ? req.body.fragments : [];
5239
+ if (fragments.length > 25 || fragments.some((fragment) => fragment.group_id !== group.id))
5240
+ throw new Error('无效消息分片');
5241
+ const fragmentReceipts = fragments.map((fragment) => collaborationStore.acceptFragment(fragment));
5242
+ for (const entry of Array.isArray(req.body.transport) ? req.body.transport : []) {
5243
+ if (collaborationStore.getMessage(entry.message_id)?.groupId !== group.id || !entry.diagnostic || !Number.isFinite(entry.diagnostic.checked_at) || !Number.isInteger(entry.diagnostic.attempt_count) || entry.diagnostic.attempt_count < 0)
5244
+ continue;
5245
+ collaborationStore.recordTransport(entry.message_id, entry.diagnostic);
5246
+ if (entry.failure_reason)
5247
+ collaborationStore.fail(entry.message_id, entry.failure_reason);
5248
+ }
5221
5249
  for (const id of group.sessionIds)
5222
5250
  if (localIds.has(id))
5223
5251
  tryDeliverCollaborationInbox(id);
5224
- res.json(collaborationStore.federationSnapshot());
5252
+ res.json({ protocolVersion: 2, ...collaborationStore.federationSnapshot(), fragmentReceipts });
5225
5253
  }
5226
5254
  catch (error) {
5227
5255
  res.status(400).json({ error: getErrorMessage(error) });
@@ -5283,7 +5311,7 @@ router.post('/operations/collaboration-groups/:groupId/messages', (req, res) =>
5283
5311
  return res.status(404).json({ error: '协作组不存在' });
5284
5312
  const fromSessionId = resolveFrontendSessionId(req.body ?? {});
5285
5313
  const kind = typeof req.body?.kind === 'string' ? req.body.kind : 'message';
5286
- const content = typeof req.body?.content === 'string' ? req.body.content.slice(0, 20_000) : '';
5314
+ const content = typeof req.body?.content === 'string' ? req.body.content : '';
5287
5315
  const requestedTargets = Array.isArray(req.body?.toSessionIds)
5288
5316
  ? req.body.toSessionIds.filter((id) => typeof id === 'string')
5289
5317
  : [];
@@ -5291,6 +5319,7 @@ router.post('/operations/collaboration-groups/:groupId/messages', (req, res) =>
5291
5319
  ? requestedTargets
5292
5320
  : group.sessionIds.filter((id) => id !== fromSessionId);
5293
5321
  const messages = collaborationStore.send({
5322
+ ...extrasFromBody(req.body),
5294
5323
  groupId: group.id,
5295
5324
  fromSessionId,
5296
5325
  toSessionIds,
@@ -5303,7 +5332,7 @@ router.post('/operations/collaboration-groups/:groupId/messages', (req, res) =>
5303
5332
  sessionId,
5304
5333
  ...tryDeliverCollaborationInbox(sessionId),
5305
5334
  }));
5306
- res.json({ messages, deliveries });
5335
+ res.json({ messages: messages.map((message) => collaborationStore.getMessage(message.id)), deliveries });
5307
5336
  }
5308
5337
  catch (error) {
5309
5338
  res.status(400).json({ error: getErrorMessage(error) });
@@ -5364,70 +5393,7 @@ router.post('/operations/orchestration/spawn', async (req, res) => {
5364
5393
  res.status(400).json({ error: getErrorMessage(error) });
5365
5394
  }
5366
5395
  });
5367
- router.post('/operations/orchestration/send', (req, res) => {
5368
- const sourceSessionId = resolveFrontendSessionId(req.body ?? {});
5369
- const targetSessionId = typeof req.body?.targetSessionId === 'string' ? req.body.targetSessionId.trim() : '';
5370
- const content = typeof req.body?.message === 'string' ? req.body.message.trim().slice(0, 20_000) : '';
5371
- if (!sourceSessionId)
5372
- return res.status(400).json({ error: '无法识别发送会话;请从 Termdock 会话内运行 td collab' });
5373
- const group = collaborationStore.groupsForSession(sourceSessionId).find((candidate) => candidate.sessionIds.includes(targetSessionId));
5374
- if (!group)
5375
- return res.status(400).json({ error: '发送方和接收方不在同一协作组' });
5376
- try {
5377
- const messages = collaborationStore.send({
5378
- groupId: group.id, fromSessionId: sourceSessionId, toSessionIds: [targetSessionId],
5379
- kind: typeof req.body?.kind === 'string' ? req.body.kind : 'message',
5380
- content,
5381
- });
5382
- res.json({ ok: true, messages, delivery: tryDeliverCollaborationInbox(targetSessionId) });
5383
- }
5384
- catch (error) {
5385
- res.status(400).json({ error: getErrorMessage(error) });
5386
- }
5387
- });
5388
- router.get('/operations/orchestration/inbox', (req, res) => {
5389
- const sessionId = resolveFrontendSessionId(req.query);
5390
- if (!sessionId)
5391
- return res.status(404).json({ error: '会话不存在' });
5392
- const messages = collaborationStore.inbox(sessionId, { limit: Number(req.query.limit) || 50 });
5393
- if (req.query.markRead === 'true')
5394
- collaborationStore.markRead(messages.map((message) => message.id));
5395
- const groups = collaborationStore.groupsForSession(sessionId);
5396
- const peerIds = new Set(groups.flatMap((group) => group.sessionIds).filter((id) => id !== sessionId));
5397
- res.json({
5398
- session: orchestrationSessionSnapshot(globalSessionState.sessions.find((record) => record.sessionId === sessionId)),
5399
- groups,
5400
- peers: [...globalSessionState.sessions.filter((record) => peerIds.has(record.sessionId)).map(orchestrationSessionSnapshot), ...collaborationRemoteSessions().filter((record) => peerIds.has(record.sessionId))],
5401
- messages,
5402
- });
5403
- });
5404
- router.post('/operations/orchestration/reply', (req, res) => {
5405
- const sourceSessionId = resolveFrontendSessionId(req.body ?? {});
5406
- const messageId = typeof req.body?.messageId === 'string' ? req.body.messageId.trim() : '';
5407
- const content = typeof req.body?.content === 'string' ? req.body.content.trim().slice(0, 20_000) : '';
5408
- const original = collaborationStore.getMessage(messageId);
5409
- if (!sourceSessionId || !original || original.toSessionId !== sourceSessionId) {
5410
- return res.status(404).json({ error: '协作消息不存在或不属于当前会话' });
5411
- }
5412
- if (!original.fromSessionId)
5413
- return res.status(400).json({ error: '这条用户消息无需回复到其他会话' });
5414
- try {
5415
- collaborationStore.markRead([original.id]);
5416
- const messages = collaborationStore.send({
5417
- groupId: original.groupId,
5418
- fromSessionId: sourceSessionId,
5419
- toSessionIds: [original.fromSessionId],
5420
- kind: 'reply',
5421
- content,
5422
- threadId: original.threadId,
5423
- replyTo: original.id,
5424
- });
5425
- res.json({ ok: true, messages, delivery: tryDeliverCollaborationInbox(original.fromSessionId) });
5426
- }
5427
- catch (error) {
5428
- res.status(400).json({ error: getErrorMessage(error) });
5429
- }
5430
- });
5396
+ router.use('/operations/orchestration', collaborationRoutes({ store: collaborationStore, resolveSession: resolveFrontendSessionId, deliver: tryDeliverCollaborationInbox }));
5431
5397
  router.get('/operations/session-search', (req, res) => {
5432
5398
  const query = typeof req.query.q === 'string' ? req.query.q : '';
5433
5399
  const results = sessionSearchStore.search(query, Number(req.query.limit) || 30).map((result) => {
@@ -7200,6 +7166,8 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
7200
7166
  type: 'connected',
7201
7167
  streamEpoch: TERMINAL_STREAM_EPOCH,
7202
7168
  outputProtocol: options.flowControl ? 2 : undefined,
7169
+ cols: session.cols,
7170
+ rows: session.rows,
7203
7171
  runtime,
7204
7172
  ptyBackend: session.ptyBackend || 'unknown',
7205
7173
  mode: session.mode,
@@ -1,4 +1,5 @@
1
1
  import crypto from 'crypto';
2
+ import { isEncryptedRequest } from '../federation/requestContext.js';
2
3
  import { EventEmitter } from 'events';
3
4
  import fs from 'fs';
4
5
  import os from 'os';
@@ -123,6 +124,14 @@ function credentialFingerprint() {
123
124
  export function isEnvPasswordSet() {
124
125
  return getEnvPassword() !== null;
125
126
  }
127
+ /** Server-only input for password-authenticated encrypted bootstrap. Never serialize this value. */
128
+ export function getPasswordVerifier() {
129
+ return getEnvPasswordHash() ?? readAuthFile()?.passwordHash ?? null;
130
+ }
131
+ export function getPasswordCredentialFingerprint() {
132
+ const verifier = getPasswordVerifier();
133
+ return verifier ? crypto.createHash('sha256').update(verifier).digest('hex') : null;
134
+ }
126
135
  export function isAuthEnabled() {
127
136
  if (getEnvPassword())
128
137
  return true;
@@ -317,6 +326,8 @@ export function recordLoginSuccess(ip) {
317
326
  // ── Express middleware ──
318
327
  // Returns true when the incoming request bears a valid session cookie.
319
328
  export function isRequestAuthenticated(req) {
329
+ if (isEncryptedRequest(req))
330
+ return true;
320
331
  pruneExpiredSessions();
321
332
  const token = req.cookies?.[AUTH_COOKIE];
322
333
  return isSessionValid(typeof token === 'string' ? token : undefined);
@@ -338,6 +349,8 @@ export function renewSessionMiddleware(req, res, next) {
338
349
  // Bypass paths are public (login/status/health/static).
339
350
  export function requireAuth(options) {
340
351
  return (req, res, next) => {
352
+ if (isEncryptedRequest(req))
353
+ return next();
341
354
  if (!isAuthEnabled())
342
355
  return next();
343
356
  if (options?.bypass?.(req))
@@ -1,4 +1,5 @@
1
1
  import crypto from 'crypto';
2
+ import { isEncryptedRequest } from '../federation/requestContext.js';
2
3
  import { getCookieSecurityOptions } from './cookieSecurity.js';
3
4
  /**
4
5
  * CSRF令牌管理器
@@ -65,6 +66,8 @@ export class CsrfProtection {
65
66
  */
66
67
  verifyMiddleware(options) {
67
68
  return (req, res, next) => {
69
+ if (isEncryptedRequest(req))
70
+ return next();
68
71
  if (options?.bypass?.(req)) {
69
72
  return next();
70
73
  }
@@ -30,9 +30,14 @@ export const securityHeaders = (req, res, next) => {
30
30
  // Enforce sandbox even for top-level navigation to user-controlled HTML/SVG.
31
31
  // allow-same-origin must NEVER be added: that would expose the terminal API.
32
32
  const preview = /^\/api\/terminal\/fs(?:\/|$)/i.test(req.path);
33
- res.setHeader('Content-Security-Policy', preview
34
- ? "sandbox allow-scripts; frame-ancestors 'self'; object-src 'none'; base-uri 'self'"
35
- : "script-src 'self' 'wasm-unsafe-eval'; script-src-attr 'none'; worker-src 'self' blob:; frame-ancestors 'self'; object-src 'none'; base-uri 'self'");
33
+ const host = req.get('host') ?? '';
34
+ const shellSource = /^[a-z0-9.\-:\[\]]+$/i.test(host) ? `http://${host}/preview-shell.html https://${host}/preview-shell.html` : "'none'";
35
+ const shell = req.path === '/preview-shell.html';
36
+ res.setHeader('Content-Security-Policy', shell
37
+ ? "sandbox allow-scripts; default-src 'none'; script-src 'unsafe-inline' blob: https: http:; style-src 'unsafe-inline' blob: https:; img-src blob: data: https:; font-src blob: data: https:; media-src blob: data: https:; connect-src https:; frame-src 'none'; frame-ancestors 'self'; object-src 'none'; base-uri https://termdock-preview.invalid; form-action 'none'"
38
+ : preview
39
+ ? "sandbox allow-scripts; frame-ancestors 'self'; object-src 'none'; base-uri 'self'"
40
+ : `script-src 'self' 'wasm-unsafe-eval'; script-src-attr 'none'; worker-src 'self' blob:; frame-src ${shellSource}; frame-ancestors 'self'; object-src 'none'; base-uri 'self'`);
36
41
  if (getPublicOrigin()) {
37
42
  res.setHeader('Strict-Transport-Security', 'max-age=31536000');
38
43
  if (!isAuthEnabled()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.174",
3
+ "version": "1.4.175",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -24,7 +24,7 @@
24
24
  "dev:client": "vite",
25
25
  "dev:server": "cross-env PORT=9835 tsx watch src/server/entry.ts",
26
26
  "build": "npm run clean && npm run build:client && npm run build:server && npm run build:runtime-manifest",
27
- "build:desktop": "node scripts/prepare-desktop-tokens.mjs && tsc -p tsconfig.desktop.json && esbuild desktop/preload.cts --bundle --platform=node --format=cjs --external:electron --outfile=.desktop-dist/preload.cjs",
27
+ "build:desktop": "node scripts/prepare-desktop-tokens.mjs && tsc -p tsconfig.desktop.json && esbuild desktop/preload.cts --bundle --platform=node --format=cjs --external:electron --outfile=.desktop-dist/preload.cjs && esbuild desktop/renderer/services.tsx --bundle --platform=browser --format=iife --minify --outfile=desktop/renderer/services.js",
28
28
  "desktop:dev": "npm run build && npm run build:desktop && electron-forge start",
29
29
  "desktop:prepare": "npm run build && npm run build:desktop && node scripts/prepare-desktop-runtime.mjs",
30
30
  "desktop:make": "node scripts/ensure-macos-appdmg.mjs && npm run desktop:prepare && electron-forge make",
@@ -44,10 +44,17 @@
44
44
  "postinstall": "node scripts/postinstall.mjs"
45
45
  },
46
46
  "dependencies": {
47
+ "@chainsafe/libp2p-noise": "17.0.0",
47
48
  "@dnd-kit/core": "^6.3.1",
48
49
  "@dnd-kit/sortable": "^10.0.0",
49
50
  "@dnd-kit/utilities": "^3.2.2",
50
51
  "@hello-pangea/dnd": "^18.0.1",
52
+ "@libp2p/crypto": "5.1.9",
53
+ "@libp2p/interface": "3.1.0",
54
+ "@libp2p/peer-id": "6.0.0",
55
+ "@libp2p/utils": "7.0.7",
56
+ "@noble/hashes": "2.4.0",
57
+ "@serenity-kit/opaque": "1.1.0",
51
58
  "@types/cookie-parser": "^1.4.10",
52
59
  "@types/csurf": "^1.11.5",
53
60
  "@types/refractor": "^2.8.0",
@@ -125,7 +132,7 @@
125
132
  "vitest": "^4.0.17"
126
133
  },
127
134
  "engines": {
128
- "node": ">=18.0.0"
135
+ "node": ">=22.0.0"
129
136
  },
130
137
  "keywords": [
131
138
  "terminal",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.174",
4
+ "version": "1.4.175",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
- "dependencyHash": "sha256-/c1QpL8I/K1/8wYVjqa7fYdeLyBTU/rKXAewGrOlv5A=",
9
- "serverBundleHash": "sha256-o3Ox04RTctpLtrl/Ju26M1EbnuLNZEMLJygf6jXN2Mw=",
10
- "clientBundleHash": "sha256-Ow17qaVsrs3zp8W6ZxYahdTzZQglcr0Mgj1MBry/oTE=",
8
+ "dependencyHash": "sha256-kSujny2SLOFnZ1ffxm1FYtli7g1vEN8d3vj1oQeLLdc=",
9
+ "serverBundleHash": "sha256-fr1FQxYSw6qb2o5QN42fGPJgN9pA3G6ZfQ5PscJ3b6E=",
10
+ "clientBundleHash": "sha256-f9Xk5CnTO9En7oL7HC2IwM4TdFST+XT+XalrxV1Xors=",
11
11
  "entrypoint": "dist/server/cli.js",
12
12
  "clientEntrypoint": "dist/client/index.html"
13
13
  }