termdock 1.4.173 → 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 (357) hide show
  1. package/.desktop-dist/main.js +204 -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-xuS6rtpv.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-BQGXUr8t.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-BfZzS1_d.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-Dn_lmPcC.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-DUybtKGZ.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-CLEmOHBp.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-O_XM5b9_.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-DlUEslcV.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-DCrP6W79.js → chunk-2Q5K7J3B-BsVAXGLa.js} +1 -1
  49. package/dist/client/assets/{chunk-5VM5RSS4-Zm6_pYQv.js → chunk-5VM5RSS4-BKtILsst.js} +1 -1
  50. package/dist/client/assets/{chunk-F27PBJKO-DkyD-X9z.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-UvWxXAkh.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-MVtVQeTr.js.gz +0 -0
  56. package/dist/client/assets/{chunk-JWPE2WC7-BjeBAFYM.js → chunk-JWPE2WC7-DliIIMe7.js} +1 -1
  57. package/dist/client/assets/{chunk-POPQ4Y6H-CnqrQdZC.js → chunk-POPQ4Y6H-XBSus3IC.js} +1 -1
  58. package/dist/client/assets/{chunk-SVP7TREG-C4a1s0v4.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-hnmjYAl_.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-xR4LOz28.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-CqY84fFp.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-Bd14zuaD.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-DSHcNXDs.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-CIGWQYeP.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-C9Fg7OLN.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-DoRhl7Fd.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-CI83g3iM.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-Dp2kP4PB.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-KtLMCM-V.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-D_zseu1m.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-DaWUl_Kz.js → erDiagram-RLTQ6QDP-DbjtZnJx.js} +1 -1
  98. package/dist/client/assets/{erDiagram-RLTQ6QDP-DaWUl_Kz.js.br → 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-BMoJ46zJ.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-lV_iVmoW.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-BVCT9Btd.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-CnKSUg74.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-BVhXOx1S.js → infoDiagram-27XIBGKW-BH4AynkM.js} +1 -1
  119. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-Cyzfuoys.js → ishikawaDiagram-5VMMS53U-BQw90AKR.js} +1 -1
  120. package/dist/client/assets/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-CEIPDhQF.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-DISkQocf.js.gz +0 -0
  125. package/dist/client/assets/{kanban-definition-UXKFOSKX-C8OulEOF.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-YN93qRzb.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-D9T4dYh7.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-BdCvvCGV.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-CSpES3Jh.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-6f4vAA1Q.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-BC4Jd-I8.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-B0pnPaEN.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-B-oOamZT.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-DBSyxt0k.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-CcohzEZE.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-D7KS6rq_.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-CaRXtn4g.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-Dz836LqY.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-BK4KAY00.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-DWgxTDhO.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-BV1TIfOp.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-GYClC5F0.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-D1oKV5W0.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 +12 -3
  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 +311 -20
  210. package/dist/server/cli.js +28 -163
  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 +89 -79
  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-DKj7F0ex.js +0 -2
  240. package/dist/client/assets/ChangeWalkthroughPanel-DKj7F0ex.js.br +0 -0
  241. package/dist/client/assets/ChangeWalkthroughPanel-DKj7F0ex.js.gz +0 -0
  242. package/dist/client/assets/DagPlayground-D2Wui4jd.js +0 -1
  243. package/dist/client/assets/DagPlayground-D2Wui4jd.js.br +0 -0
  244. package/dist/client/assets/DagPlayground-D2Wui4jd.js.gz +0 -0
  245. package/dist/client/assets/DiffLab-xuS6rtpv.js.br +0 -0
  246. package/dist/client/assets/DiffLab-xuS6rtpv.js.gz +0 -0
  247. package/dist/client/assets/DiffReview-CAwpqM_w.js +0 -1
  248. package/dist/client/assets/DiffReview-CAwpqM_w.js.br +0 -0
  249. package/dist/client/assets/DiffReview-CAwpqM_w.js.gz +0 -0
  250. package/dist/client/assets/DiffReviewLab-BM_uGdyI.js +0 -2
  251. package/dist/client/assets/DiffReviewLab-BM_uGdyI.js.br +0 -0
  252. package/dist/client/assets/DiffReviewLab-BM_uGdyI.js.gz +0 -0
  253. package/dist/client/assets/DiffViewer-BQGXUr8t.js.br +0 -0
  254. package/dist/client/assets/DiffViewer-BQGXUr8t.js.gz +0 -0
  255. package/dist/client/assets/ModelPreview-BfZzS1_d.js.br +0 -0
  256. package/dist/client/assets/ModelPreview-BfZzS1_d.js.gz +0 -0
  257. package/dist/client/assets/RightSidebar-Cdqt3C7V.js +0 -55
  258. package/dist/client/assets/RightSidebar-Cdqt3C7V.js.br +0 -0
  259. package/dist/client/assets/RightSidebar-Cdqt3C7V.js.gz +0 -0
  260. package/dist/client/assets/abnfDiagram-VCTEODGH-Dn_lmPcC.js.br +0 -0
  261. package/dist/client/assets/abnfDiagram-VCTEODGH-Dn_lmPcC.js.gz +0 -0
  262. package/dist/client/assets/app-DDCkFsNe.js +0 -175
  263. package/dist/client/assets/app-DDCkFsNe.js.br +0 -0
  264. package/dist/client/assets/app-DDCkFsNe.js.gz +0 -0
  265. package/dist/client/assets/arc-DUybtKGZ.js.br +0 -0
  266. package/dist/client/assets/arc-DUybtKGZ.js.gz +0 -0
  267. package/dist/client/assets/architectureDiagram-5GKGNRK7-CLEmOHBp.js.br +0 -0
  268. package/dist/client/assets/architectureDiagram-5GKGNRK7-CLEmOHBp.js.gz +0 -0
  269. package/dist/client/assets/blockDiagram-I7D4REHJ-O_XM5b9_.js.br +0 -0
  270. package/dist/client/assets/blockDiagram-I7D4REHJ-O_XM5b9_.js.gz +0 -0
  271. package/dist/client/assets/c4Diagram-7LVT6UL2-DlUEslcV.js.br +0 -0
  272. package/dist/client/assets/c4Diagram-7LVT6UL2-DlUEslcV.js.gz +0 -0
  273. package/dist/client/assets/channel-Bk1VkYvd.js +0 -1
  274. package/dist/client/assets/chunk-F27PBJKO-DkyD-X9z.js.br +0 -0
  275. package/dist/client/assets/chunk-F27PBJKO-DkyD-X9z.js.gz +0 -0
  276. package/dist/client/assets/chunk-IMKFNOWR-UvWxXAkh.js.br +0 -0
  277. package/dist/client/assets/chunk-IMKFNOWR-UvWxXAkh.js.gz +0 -0
  278. package/dist/client/assets/chunk-SVP7TREG-C4a1s0v4.js.br +0 -0
  279. package/dist/client/assets/chunk-SVP7TREG-C4a1s0v4.js.gz +0 -0
  280. package/dist/client/assets/chunk-TICWLB2K-hnmjYAl_.js.br +0 -0
  281. package/dist/client/assets/chunk-TICWLB2K-hnmjYAl_.js.gz +0 -0
  282. package/dist/client/assets/classDiagram-ZZMXUADV-_tUz3Cxt.js +0 -1
  283. package/dist/client/assets/classDiagram-v2-VYDZK3BY-_tUz3Cxt.js +0 -1
  284. package/dist/client/assets/cose-bilkent-JH36ORCC-CqY84fFp.js.br +0 -0
  285. package/dist/client/assets/cose-bilkent-JH36ORCC-CqY84fFp.js.gz +0 -0
  286. package/dist/client/assets/cynefin-OW5HDTMX-Bd14zuaD.js.br +0 -0
  287. package/dist/client/assets/cynefin-OW5HDTMX-Bd14zuaD.js.gz +0 -0
  288. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DSHcNXDs.js.br +0 -0
  289. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DSHcNXDs.js.gz +0 -0
  290. package/dist/client/assets/dagre-GXQ25YYZ-CIGWQYeP.js.br +0 -0
  291. package/dist/client/assets/dagre-GXQ25YYZ-CIGWQYeP.js.gz +0 -0
  292. package/dist/client/assets/diagram-S7CK7UJ4-C9Fg7OLN.js.br +0 -0
  293. package/dist/client/assets/diagram-S7CK7UJ4-C9Fg7OLN.js.gz +0 -0
  294. package/dist/client/assets/diagram-UQ7AKVKN-DoRhl7Fd.js.br +0 -0
  295. package/dist/client/assets/diagram-UQ7AKVKN-DoRhl7Fd.js.gz +0 -0
  296. package/dist/client/assets/diagram-VSXAHHWV-CI83g3iM.js.br +0 -0
  297. package/dist/client/assets/diagram-VSXAHHWV-CI83g3iM.js.gz +0 -0
  298. package/dist/client/assets/diagram-VX7I27RA-Dp2kP4PB.js.br +0 -0
  299. package/dist/client/assets/diagram-VX7I27RA-Dp2kP4PB.js.gz +0 -0
  300. package/dist/client/assets/diagram-Z3DM3KII-KtLMCM-V.js.br +0 -0
  301. package/dist/client/assets/diagram-Z3DM3KII-KtLMCM-V.js.gz +0 -0
  302. package/dist/client/assets/ebnfDiagram-PWID7BFC-D_zseu1m.js.br +0 -0
  303. package/dist/client/assets/ebnfDiagram-PWID7BFC-D_zseu1m.js.gz +0 -0
  304. package/dist/client/assets/erDiagram-RLTQ6QDP-DaWUl_Kz.js.gz +0 -0
  305. package/dist/client/assets/flowDiagram-HODETNUW-BMoJ46zJ.js.br +0 -0
  306. package/dist/client/assets/flowDiagram-HODETNUW-BMoJ46zJ.js.gz +0 -0
  307. package/dist/client/assets/ganttDiagram-EL5Y4UJY-lV_iVmoW.js.br +0 -0
  308. package/dist/client/assets/ganttDiagram-EL5Y4UJY-lV_iVmoW.js.gz +0 -0
  309. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVCT9Btd.js.br +0 -0
  310. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVCT9Btd.js.gz +0 -0
  311. package/dist/client/assets/index-CnKSUg74.css.br +0 -0
  312. package/dist/client/assets/index-CnKSUg74.css.gz +0 -0
  313. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cyzfuoys.js.br +0 -0
  314. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cyzfuoys.js.gz +0 -0
  315. package/dist/client/assets/journeyDiagram-3NMN7TZE-CEIPDhQF.js.br +0 -0
  316. package/dist/client/assets/journeyDiagram-3NMN7TZE-CEIPDhQF.js.gz +0 -0
  317. package/dist/client/assets/kanban-definition-UXKFOSKX-C8OulEOF.js.br +0 -0
  318. package/dist/client/assets/kanban-definition-UXKFOSKX-C8OulEOF.js.gz +0 -0
  319. package/dist/client/assets/layout-YN93qRzb.js.br +0 -0
  320. package/dist/client/assets/layout-YN93qRzb.js.gz +0 -0
  321. package/dist/client/assets/linear-D9T4dYh7.js.br +0 -0
  322. package/dist/client/assets/linear-D9T4dYh7.js.gz +0 -0
  323. package/dist/client/assets/mermaid.core-BdCvvCGV.js.br +0 -0
  324. package/dist/client/assets/mermaid.core-BdCvvCGV.js.gz +0 -0
  325. package/dist/client/assets/mindmap-definition-YA3MSWOX-CSpES3Jh.js.br +0 -0
  326. package/dist/client/assets/mindmap-definition-YA3MSWOX-CSpES3Jh.js.gz +0 -0
  327. package/dist/client/assets/pegDiagram-XKGWAZYB-6f4vAA1Q.js.br +0 -0
  328. package/dist/client/assets/pegDiagram-XKGWAZYB-6f4vAA1Q.js.gz +0 -0
  329. package/dist/client/assets/pieDiagram-E7YTZNPT-BC4Jd-I8.js.br +0 -0
  330. package/dist/client/assets/pieDiagram-E7YTZNPT-BC4Jd-I8.js.gz +0 -0
  331. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B0pnPaEN.js.br +0 -0
  332. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B0pnPaEN.js.gz +0 -0
  333. package/dist/client/assets/railroadDiagram-O6MQD6OU-B-oOamZT.js.br +0 -0
  334. package/dist/client/assets/railroadDiagram-O6MQD6OU-B-oOamZT.js.gz +0 -0
  335. package/dist/client/assets/requirementDiagram-BXWQKSXE-DBSyxt0k.js.br +0 -0
  336. package/dist/client/assets/requirementDiagram-BXWQKSXE-DBSyxt0k.js.gz +0 -0
  337. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CcohzEZE.js.br +0 -0
  338. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CcohzEZE.js.gz +0 -0
  339. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D7KS6rq_.js.br +0 -0
  340. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D7KS6rq_.js.gz +0 -0
  341. package/dist/client/assets/sizeCapture-INFHLROL-CaRXtn4g.js.br +0 -0
  342. package/dist/client/assets/sizeCapture-INFHLROL-CaRXtn4g.js.gz +0 -0
  343. package/dist/client/assets/sparkles-CUdUt4qy.js +0 -1
  344. package/dist/client/assets/stateDiagram-D77RDMKH-Dz836LqY.js.br +0 -0
  345. package/dist/client/assets/stateDiagram-D77RDMKH-Dz836LqY.js.gz +0 -0
  346. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-5V5Y3wwn.js +0 -1
  347. package/dist/client/assets/swimlanes-42K2YHIH-BK4KAY00.js.br +0 -0
  348. package/dist/client/assets/swimlanes-42K2YHIH-BK4KAY00.js.gz +0 -0
  349. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-Sj-7YK2P.js +0 -8
  350. package/dist/client/assets/timeline-definition-24CTP7MA-DWgxTDhO.js.br +0 -0
  351. package/dist/client/assets/timeline-definition-24CTP7MA-DWgxTDhO.js.gz +0 -0
  352. package/dist/client/assets/vennDiagram-4TSXK5OY-BV1TIfOp.js.br +0 -0
  353. package/dist/client/assets/vennDiagram-4TSXK5OY-BV1TIfOp.js.gz +0 -0
  354. package/dist/client/assets/wardleyDiagram-VM6X3IG4-GYClC5F0.js.br +0 -0
  355. package/dist/client/assets/wardleyDiagram-VM6X3IG4-GYClC5F0.js.gz +0 -0
  356. package/dist/client/assets/xychartDiagram-S5SC5T6Z-D1oKV5W0.js.br +0 -0
  357. package/dist/client/assets/xychartDiagram-S5SC5T6Z-D1oKV5W0.js.gz +0 -0
@@ -1,3 +1,7 @@
1
+ import { CollaborationFederation, sessionAddress } from './collaborationFederation.js';
2
+ import { prepareBundledFrontend } from './bundledFrontend.js';
3
+ import { serviceConnection, serviceConnectionKeys, importServiceConnection, upsertServiceConnection, invitationForService } from './serviceConnections.js';
4
+ const pendingServiceInvitations = new WeakMap();
1
5
  import { app, BrowserWindow, clipboard, dialog, ipcMain, Menu, net, nativeImage, Notification, powerMonitor, screen, session, shell, Tray, } from 'electron';
2
6
  import { execFile, spawn } from 'node:child_process';
3
7
  import crypto from 'node:crypto';
@@ -16,6 +20,7 @@ import { isExternalLinkStagingUrl, isSafeExternalUrl } from './externalLinks.js'
16
20
  import { shouldThrottleDesktopRenderer } from './windowPolicy.js';
17
21
  import { checkConnectedServiceRuntime, getConnectedServiceRuntimeState, restartConnectedServiceRuntime, } from './connectedServiceRuntime.js';
18
22
  import { isOwnedDesktopRuntimeTarget } from './runtimeTarget.js';
23
+ import { canReadLocalInvite } from './localInviteGuard.js';
19
24
  import { serviceDocumentNeedsReload } from './serviceWindowRecovery.js';
20
25
  import { CertificateTrustRequests, resolveServiceCertificateTrust, canOfferCertificateTrust, downloadCertificateAuthority, isCertificateTrustError, isLocalNetworkHostname, matchManagedLocalCertificate, } from './certificateTrust.js';
21
26
  const execFileAsync = promisify(execFile);
@@ -25,6 +30,7 @@ const termdockDir = path.join(os.homedir(), '.termdock');
25
30
  const desktopConfigPath = path.join(termdockDir, 'desktop.json');
26
31
  const serverStatePath = path.join(termdockDir, 'server.json');
27
32
  const desktopRuntimeOwnerSocketPath = path.join(termdockDir, 'desktop-runtime-owner.sock');
33
+ let federationRelayProcess = null;
28
34
  const DEFAULT_LOCAL_URL = 'http://localhost:9834';
29
35
  const PROTOCOL_VERSION = 1;
30
36
  const HEALTH_TIMEOUT_MS = 3_500;
@@ -80,6 +86,30 @@ let connectedServiceRuntimePollInFlight = false;
80
86
  let isQuitting = false;
81
87
  const FLOATING_WIDGET_WIDTHS = [64, 108, 152];
82
88
  const FLOATING_WIDGET_HEIGHT = 40;
89
+ const collaborationFederation = new CollaborationFederation(() => [...serviceWindows.entries()]
90
+ .filter(([, window]) => !window.isDestroyed())
91
+ .map(([origin, window]) => ({ origin, label: serviceLabel(origin),
92
+ request: async (route, method = 'GET', body) => {
93
+ if (new URL(window.webContents.getURL()).origin !== origin)
94
+ throw new Error('服务窗口尚未就绪');
95
+ const args = JSON.stringify({ route, method, body });
96
+ return window.webContents.executeJavaScript(`(async () => {
97
+ const { route, method, body } = ${args};
98
+ const headers = { 'Content-Type': 'application/json' };
99
+ if (method !== 'GET') {
100
+ const token = await fetch('/api/csrf-token', { signal: AbortSignal.timeout(5000) }).then(r => r.json());
101
+ headers['X-XSRF-TOKEN'] = token.csrfToken;
102
+ }
103
+ const response = await fetch('/api/terminal/operations' + route, {
104
+ method, headers, body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(5000)
105
+ });
106
+ const payload = response.status === 204 ? null : await response.json();
107
+ if (!response.ok) throw new Error(payload?.error || '服务不可达或需要升级 Termdock');
108
+ return payload;
109
+ })()`, true);
110
+ },
111
+ })));
112
+ let collaborationPollTimer = null;
83
113
  function focusedWorkspaceWindow() {
84
114
  const focused = BrowserWindow.getFocusedWindow();
85
115
  if (focused && windowServiceOrigins.has(focused))
@@ -459,6 +489,8 @@ function readManagedLocalCertificateFingerprint() {
459
489
  }
460
490
  function installCertificateVerifyProcedure(targetSession = session.defaultSession, serviceOrigin) {
461
491
  targetSession.setCertificateVerifyProc((request, callback) => {
492
+ const routeOrigins = serviceOrigin ? readDesktopConfig().connections.flatMap(item => item.routes || []).map(route => route.url) : [];
493
+ const requestedOrigin = [serviceOrigin, ...routeOrigins].find(origin => origin && new URL(origin).hostname.replace(/^\[|\]$/g, '').toLowerCase() === request.hostname.replace(/^\[|\]$/g, '').toLowerCase());
462
494
  let isLocalTarget = false;
463
495
  try {
464
496
  isLocalTarget = isLocalNetworkTarget(new URL(`https://${request.hostname}`));
@@ -475,9 +507,7 @@ function installCertificateVerifyProcedure(targetSession = session.defaultSessio
475
507
  }
476
508
  const explicitlyTrustedTarget = presentedFingerprint
477
509
  ? serviceOrigin
478
- ? new URL(serviceOrigin).hostname.replace(/^\[|\]$/g, '').toLowerCase()
479
- === request.hostname.replace(/^\[|\]$/g, '').toLowerCase()
480
- && sessionTrustedLeafByOrigin.get(serviceOrigin) === presentedFingerprint
510
+ ? !!requestedOrigin && sessionTrustedLeafByOrigin.get(requestedOrigin) === presentedFingerprint
481
511
  : sessionTrustedCertificateTargets.has(certificateTrustKey(request.hostname, presentedFingerprint))
482
512
  : false;
483
513
  const managedMatch = isLocalTarget
@@ -489,11 +519,11 @@ function installCertificateVerifyProcedure(targetSession = session.defaultSessio
489
519
  callback(0);
490
520
  return;
491
521
  }
492
- if (serviceOrigin && canOfferCertificateTrust(serviceOrigin)
522
+ if (requestedOrigin && canOfferCertificateTrust(requestedOrigin)
493
523
  && isCertificateTrustError(request.verificationResult)) {
494
524
  // Resolve trust before Chromium caches a rejection. This covers fetch,
495
525
  // WebSocket and navigation requests, not only the initial Node probe.
496
- void resolveServiceCertificateTrust(serviceOrigin, request.hostname, request.certificate.data, () => requestCertificateTrust(serviceOrigin)).then((trusted) => callback(trusted ? 0 : -3), (error) => {
526
+ void resolveServiceCertificateTrust(requestedOrigin, request.hostname, request.certificate.data, () => requestCertificateTrust(requestedOrigin)).then((trusted) => callback(trusted ? 0 : -3), (error) => {
497
527
  console.warn(`[desktop-certificate] ${serviceOrigin}: ${networkErrorDetails(error)}`);
498
528
  callback(-3);
499
529
  });
@@ -663,6 +693,7 @@ function readDesktopConfig() {
663
693
  const lastConnectionUrl = typeof parsed.lastConnectionUrl === 'string' ? parsed.lastConnectionUrl : null;
664
694
  return {
665
695
  version: 1,
696
+ removedServiceKeys: Array.isArray(parsed.removedServiceKeys) ? parsed.removedServiceKeys.filter((key) => typeof key === 'string').slice(-768) : [],
666
697
  connections: parsed.connections.filter((entry) => Boolean(entry)
667
698
  && typeof entry.id === 'string'
668
699
  && typeof entry.label === 'string'
@@ -946,6 +977,41 @@ function runtimePaths() {
946
977
  source: 'development',
947
978
  };
948
979
  }
980
+ /** Explicit opt-in only; all routing and reconnect behavior lives in the shared CLI. */
981
+ function startConfiguredFederationRelay() {
982
+ const configPath = path.join(termdockDir, 'federation', 'relay.json');
983
+ if (federationRelayProcess || !fs.existsSync(configPath))
984
+ return;
985
+ let logFd;
986
+ try {
987
+ const runtime = runtimePaths();
988
+ if (!fs.existsSync(runtime.cli))
989
+ throw new Error('Runtime unavailable');
990
+ const logPath = path.join(termdockDir, 'federation', 'relay.log');
991
+ logFd = fs.openSync(logPath, 'a', 0o600);
992
+ fs.fchmodSync(logFd, 0o600);
993
+ const child = spawn(runtime.node, [runtime.cli, '--federation-relay', configPath], {
994
+ detached: false,
995
+ stdio: ['ignore', logFd, logFd],
996
+ env: desktopRuntimeEnv(runtime),
997
+ });
998
+ federationRelayProcess = child;
999
+ child.once('error', () => {
1000
+ if (federationRelayProcess === child)
1001
+ federationRelayProcess = null;
1002
+ console.error('[federation] Configured relay failed to start; inspect the private relay log.');
1003
+ });
1004
+ child.once('exit', () => { if (federationRelayProcess === child)
1005
+ federationRelayProcess = null; });
1006
+ }
1007
+ catch {
1008
+ console.error('[federation] Unable to start configured relay; verify the runtime and private configuration.');
1009
+ }
1010
+ finally {
1011
+ if (logFd !== undefined)
1012
+ fs.closeSync(logFd);
1013
+ }
1014
+ }
949
1015
  async function executableVersion(executable) {
950
1016
  try {
951
1017
  const { stdout } = await execFileAsync(executable, ['--version'], {
@@ -1369,7 +1435,8 @@ async function connectWindow(rawUrl, options = {}) {
1369
1435
  return await probeService(rawUrl);
1370
1436
  }
1371
1437
  }
1372
- let probe = await probeServiceWithLocalNetworkPermission(rawUrl, {
1438
+ const known = readDesktopConfig().connections.find(item => (item.serviceOrigin || item.url) === normalizeServiceUrl(rawUrl));
1439
+ let probe = known?.targetPeerId ? { ok: true, url: normalizeServiceUrl(rawUrl) } : await probeServiceWithLocalNetworkPermission(rawUrl, {
1373
1440
  interactive: options.focus !== false,
1374
1441
  });
1375
1442
  if (!probe.ok)
@@ -1398,7 +1465,9 @@ async function connectWindow(rawUrl, options = {}) {
1398
1465
  existing.lastConnectedAt = Date.now();
1399
1466
  writeDesktopConfig(config);
1400
1467
  }
1401
- if (await serviceDocumentNeedsReload(existingWindow.webContents, key)) {
1468
+ if (options.invitation || await serviceDocumentNeedsReload(existingWindow.webContents, key)) {
1469
+ if (options.invitation)
1470
+ pendingServiceInvitations.set(existingWindow, options.invitation);
1402
1471
  await existingWindow.loadURL(probe.url);
1403
1472
  }
1404
1473
  if (options.focus !== false) {
@@ -1411,6 +1480,9 @@ async function connectWindow(rawUrl, options = {}) {
1411
1480
  return probe;
1412
1481
  }
1413
1482
  const workspaceWindow = createDesktopWindow({ serviceOrigin: key, label: serviceLabel(probe.url) });
1483
+ await prepareBundledFrontend(workspaceWindow.webContents.session, key, path.join(runtimePaths().serverRoot, 'dist', 'client'));
1484
+ if (options.invitation)
1485
+ pendingServiceInvitations.set(workspaceWindow, options.invitation);
1414
1486
  serviceWindows.set(key, workspaceWindow);
1415
1487
  broadcastServiceActivity();
1416
1488
  while (!workspaceWindow.isDestroyed()) {
@@ -1786,7 +1858,91 @@ function installIpcHandlers() {
1786
1858
  const png = image.toPNG();
1787
1859
  return png.buffer.slice(png.byteOffset, png.byteOffset + png.byteLength);
1788
1860
  });
1861
+ const collaborationOrigin = (event) => {
1862
+ const window = BrowserWindow.fromWebContents(event.sender);
1863
+ const origin = window ? windowServiceOrigins.get(window) : undefined;
1864
+ if (!origin || event.senderFrame !== event.sender.mainFrame
1865
+ || new URL(event.sender.getURL()).origin !== origin)
1866
+ throw new Error('未授权的服务窗口');
1867
+ return origin;
1868
+ };
1869
+ ipcMain.handle('desktop:collaboration-list', (event) => collaborationFederation.list(collaborationOrigin(event)));
1870
+ ipcMain.handle('desktop:collaboration-save', (event, input) => collaborationFederation.save(collaborationOrigin(event), input));
1871
+ ipcMain.handle('desktop:collaboration-remove', (event, id) => collaborationFederation.remove(collaborationOrigin(event), id));
1872
+ ipcMain.handle('desktop:collaboration-focus', (event, id) => {
1873
+ collaborationOrigin(event);
1874
+ const address = sessionAddress(id);
1875
+ const target = address ? serviceWindows.get(address.origin) : null;
1876
+ if (!target || target.isDestroyed())
1877
+ return false;
1878
+ showAndFocusWindow(target);
1879
+ target.webContents.send('desktop:focus-session', address.id);
1880
+ return true;
1881
+ });
1882
+ collaborationPollTimer = setInterval(() => void collaborationFederation.refresh().catch(() => { }), 2000);
1883
+ collaborationPollTimer.unref();
1789
1884
  ipcMain.handle('desktop:snapshot', () => snapshot());
1885
+ const directorySender = (event) => {
1886
+ const window = BrowserWindow.fromWebContents(event.sender);
1887
+ if (!window || event.senderFrame !== event.sender.mainFrame)
1888
+ throw new Error('无法访问服务列表。');
1889
+ const origin = windowServiceOrigins.get(window);
1890
+ const url = new URL(event.senderFrame.url);
1891
+ if (origin ? url.origin !== origin || url.pathname !== '/' : window !== mainWindow || url.protocol !== 'file:')
1892
+ throw new Error('无法访问服务列表。');
1893
+ return window;
1894
+ };
1895
+ const directoryChanged = () => {
1896
+ installMenu();
1897
+ for (const window of BrowserWindow.getAllWindows())
1898
+ window.webContents.send('desktop:service-connections-changed');
1899
+ broadcastServiceActivity();
1900
+ };
1901
+ ipcMain.handle('desktop:service-connections', event => { directorySender(event); return readDesktopConfig().connections; });
1902
+ ipcMain.handle('desktop:save-service-connection', (event, input) => {
1903
+ directorySender(event);
1904
+ const config = readDesktopConfig();
1905
+ config.connections = upsertServiceConnection(config.connections, input);
1906
+ writeDesktopConfig(config);
1907
+ directoryChanged();
1908
+ return config.connections;
1909
+ });
1910
+ ipcMain.handle('desktop:import-service-connection', (event, input) => {
1911
+ directorySender(event);
1912
+ const config = readDesktopConfig();
1913
+ config.connections = importServiceConnection(config.connections, config.removedServiceKeys || [], input);
1914
+ writeDesktopConfig(config);
1915
+ directoryChanged();
1916
+ return config.connections;
1917
+ });
1918
+ ipcMain.handle('desktop:remove-service-connection', (event, id) => {
1919
+ directorySender(event);
1920
+ const config = readDesktopConfig();
1921
+ const removed = config.connections.find(item => item.id === id);
1922
+ if (removed)
1923
+ config.removedServiceKeys = [...new Set([...(config.removedServiceKeys || []), ...serviceConnectionKeys(removed)])].slice(-768);
1924
+ config.connections = config.connections.filter(item => item.id !== id);
1925
+ writeDesktopConfig(config);
1926
+ directoryChanged();
1927
+ return config.connections;
1928
+ });
1929
+ ipcMain.handle('desktop:current-service-connection', event => {
1930
+ const window = directorySender(event), origin = windowServiceOrigins.get(window);
1931
+ const connection = readDesktopConfig().connections.find(item => (item.serviceOrigin || item.url) === origin);
1932
+ const invitation = pendingServiceInvitations.get(window);
1933
+ pendingServiceInvitations.delete(window);
1934
+ return connection ? { ...connection, ...(invitation ? { invitation } : {}) } : null;
1935
+ });
1936
+ ipcMain.handle('desktop:open-service-connection', async (event, input, rawInvitation) => {
1937
+ directorySender(event);
1938
+ const connection = serviceConnection(input), invitation = invitationForService(rawInvitation, connection);
1939
+ // A bookmark pin is connection metadata, never authorization to the service.
1940
+ const config = readDesktopConfig();
1941
+ config.connections = upsertServiceConnection(config.connections, connection);
1942
+ writeDesktopConfig(config);
1943
+ directoryChanged();
1944
+ return connectWindow(connection.serviceOrigin || connection.url, { invitation });
1945
+ });
1790
1946
  ipcMain.handle('desktop:probe', (_event, url) => {
1791
1947
  try {
1792
1948
  certificateTrustRequests.retry(new URL(normalizeServiceUrl(url)).origin);
@@ -1862,6 +2018,42 @@ function installIpcHandlers() {
1862
2018
  broadcastServiceActivity();
1863
2019
  return true;
1864
2020
  });
2021
+ ipcMain.handle('desktop:local-invite', async (event) => {
2022
+ const sourceWindow = BrowserWindow.fromWebContents(event.sender);
2023
+ if (!sourceWindow || sourceWindow.isDestroyed() || event.senderFrame !== event.sender.mainFrame)
2024
+ return null;
2025
+ const registeredOrigin = windowServiceOrigins.get(sourceWindow);
2026
+ const initialUrl = event.sender.getURL();
2027
+ // First reject remote/preview callers before any asynchronous local probing.
2028
+ let callerPort;
2029
+ try {
2030
+ const url = new URL(initialUrl);
2031
+ callerPort = Number(url.port || (url.protocol === 'https:' ? 443 : 80));
2032
+ }
2033
+ catch {
2034
+ return null;
2035
+ }
2036
+ if (!canReadLocalInvite({ registeredOrigin, currentUrl: initialUrl, mainFrame: true, running: true, desktopManaged: true, servicePort: callerPort }))
2037
+ return null;
2038
+ const status = await getLocalServiceStatus().catch(() => null);
2039
+ if (!status || !status.state || sourceWindow.isDestroyed() || event.sender.isDestroyed()
2040
+ || event.senderFrame !== event.sender.mainFrame || event.sender.getURL() !== initialUrl
2041
+ || windowServiceOrigins.get(sourceWindow) !== registeredOrigin
2042
+ || !canReadLocalInvite({ registeredOrigin, currentUrl: event.sender.getURL(), mainFrame: true,
2043
+ running: status.running, desktopManaged: status.probe?.desktopManaged === true, servicePort: status.state.port })
2044
+ || !isOwnedDesktopRuntimeWindow(sourceWindow, status))
2045
+ return null;
2046
+ try {
2047
+ const data = JSON.parse(fs.readFileSync(path.join(termdockDir, 'federation', 'pairing.json'), 'utf8'));
2048
+ if (typeof data.serviceId !== 'string' || !/^12D3KooW[1-9A-HJ-NP-Za-km-z]{44}$/.test(data.serviceId)
2049
+ || typeof data.pairingCode !== 'string' || !/^[A-Za-z0-9_-]{32,128}$/.test(data.pairingCode))
2050
+ return null;
2051
+ return { url: registeredOrigin, targetPeerId: data.serviceId, pairingCode: data.pairingCode, serviceName: '本机 Termdock' };
2052
+ }
2053
+ catch {
2054
+ return null;
2055
+ }
2056
+ });
1865
2057
  ipcMain.handle('desktop:start-local', () => startLocalService());
1866
2058
  ipcMain.handle('desktop:update-preferences', async (_event, preferences) => {
1867
2059
  updateDesktopPreferences({
@@ -2199,6 +2391,7 @@ app.whenReady().then(async () => {
2199
2391
  });
2200
2392
  });
2201
2393
  startConnectedServiceRuntimePolling();
2394
+ startConfiguredFederationRelay();
2202
2395
  const startupConfig = readDesktopConfig();
2203
2396
  const restoreUrls = startupConfig.openConnectionUrls;
2204
2397
  startupRestoreActive = true;
@@ -2257,8 +2450,12 @@ app.on('window-all-closed', () => {
2257
2450
  });
2258
2451
  app.on('before-quit', () => {
2259
2452
  isQuitting = true;
2453
+ federationRelayProcess?.kill('SIGTERM');
2454
+ federationRelayProcess = null;
2260
2455
  desktopRuntimeOwnerServer?.close();
2261
2456
  desktopRuntimeOwnerServer = null;
2457
+ if (collaborationPollTimer)
2458
+ clearInterval(collaborationPollTimer);
2262
2459
  if (connectedServiceRuntimePollTimer)
2263
2460
  clearInterval(connectedServiceRuntimePollTimer);
2264
2461
  connectedServiceRuntimePollTimer = null;