termdock 1.4.194 → 1.4.196

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 (318) hide show
  1. package/dist/client/assets/{App-BbIl0DAa.js → App-DHPY_Qw6.js} +10 -10
  2. package/dist/client/assets/App-DHPY_Qw6.js.br +0 -0
  3. package/dist/client/assets/App-DHPY_Qw6.js.gz +0 -0
  4. package/dist/client/assets/{ChangeWalkthroughPanel-CT7mLy_e.js → ChangeWalkthroughPanel-Dl6vEiEH.js} +1 -1
  5. package/dist/client/assets/ChangeWalkthroughPanel-Dl6vEiEH.js.br +0 -0
  6. package/dist/client/assets/ChangeWalkthroughPanel-Dl6vEiEH.js.gz +0 -0
  7. package/dist/client/assets/{DagPlayground-Bsf4bv7e.js → DagPlayground-Dush1TIN.js} +1 -1
  8. package/dist/client/assets/DagPlayground-Dush1TIN.js.br +0 -0
  9. package/dist/client/assets/DagPlayground-Dush1TIN.js.gz +0 -0
  10. package/dist/client/assets/{DiffLab-BjiZcUSn.js → DiffLab-T8DSZ9CZ.js} +1 -1
  11. package/dist/client/assets/DiffLab-T8DSZ9CZ.js.br +0 -0
  12. package/dist/client/assets/DiffLab-T8DSZ9CZ.js.gz +0 -0
  13. package/dist/client/assets/{DiffReview-DmkAyOh4.js → DiffReview-CWqBYEQi.js} +1 -1
  14. package/dist/client/assets/DiffReview-CWqBYEQi.js.br +0 -0
  15. package/dist/client/assets/DiffReview-CWqBYEQi.js.gz +0 -0
  16. package/dist/client/assets/{DiffReviewLab-wXYUmdna.js → DiffReviewLab-HiliQgzS.js} +1 -1
  17. package/dist/client/assets/DiffReviewLab-HiliQgzS.js.br +0 -0
  18. package/dist/client/assets/DiffReviewLab-HiliQgzS.js.gz +0 -0
  19. package/dist/client/assets/{DiffViewer-BlwwMnsB.js → DiffViewer-BOzmZ9Vg.js} +1 -1
  20. package/dist/client/assets/DiffViewer-BOzmZ9Vg.js.br +0 -0
  21. package/dist/client/assets/DiffViewer-BOzmZ9Vg.js.gz +0 -0
  22. package/dist/client/assets/{ModelPreview-DGIaQAcq.js → ModelPreview-BScN6pYp.js} +1 -1
  23. package/dist/client/assets/ModelPreview-BScN6pYp.js.br +0 -0
  24. package/dist/client/assets/ModelPreview-BScN6pYp.js.gz +0 -0
  25. package/dist/client/assets/{RightSidebar-PgJ0XzEh.js → RightSidebar-Cwwgb4aF.js} +4 -4
  26. package/dist/client/assets/RightSidebar-Cwwgb4aF.js.br +0 -0
  27. package/dist/client/assets/RightSidebar-Cwwgb4aF.js.gz +0 -0
  28. package/dist/client/assets/{abnfDiagram-VCTEODGH-B_sCIKms.js → abnfDiagram-VCTEODGH-_Jotrwh5.js} +1 -1
  29. package/dist/client/assets/abnfDiagram-VCTEODGH-_Jotrwh5.js.br +0 -0
  30. package/dist/client/assets/abnfDiagram-VCTEODGH-_Jotrwh5.js.gz +0 -0
  31. package/dist/client/assets/{app-5zC_J9mq.js → app-D3EW-RfP.js} +3 -3
  32. package/dist/client/assets/app-D3EW-RfP.js.br +0 -0
  33. package/dist/client/assets/app-D3EW-RfP.js.gz +0 -0
  34. package/dist/client/assets/{arc-Ps2GTfJ3.js → arc--QK4vqUb.js} +1 -1
  35. package/dist/client/assets/arc--QK4vqUb.js.br +0 -0
  36. package/dist/client/assets/arc--QK4vqUb.js.gz +0 -0
  37. package/dist/client/assets/{architectureDiagram-5GKGNRK7-DxKfqPAR.js → architectureDiagram-5GKGNRK7-BwHR__6X.js} +1 -1
  38. package/dist/client/assets/architectureDiagram-5GKGNRK7-BwHR__6X.js.br +0 -0
  39. package/dist/client/assets/architectureDiagram-5GKGNRK7-BwHR__6X.js.gz +0 -0
  40. package/dist/client/assets/{blockDiagram-I7D4REHJ-BNL8tkC0.js → blockDiagram-I7D4REHJ-DZEMZMfx.js} +1 -1
  41. package/dist/client/assets/blockDiagram-I7D4REHJ-DZEMZMfx.js.br +0 -0
  42. package/dist/client/assets/blockDiagram-I7D4REHJ-DZEMZMfx.js.gz +0 -0
  43. package/dist/client/assets/{c4Diagram-7LVT6UL2-hyEavwo6.js → c4Diagram-7LVT6UL2-CWWPwhkP.js} +1 -1
  44. package/dist/client/assets/c4Diagram-7LVT6UL2-CWWPwhkP.js.br +0 -0
  45. package/dist/client/assets/c4Diagram-7LVT6UL2-CWWPwhkP.js.gz +0 -0
  46. package/dist/client/assets/channel-DXepE6hM.js +1 -0
  47. package/dist/client/assets/{chunk-2Q5K7J3B-DN_HrxPz.js → chunk-2Q5K7J3B-Ciwe6Jpr.js} +1 -1
  48. package/dist/client/assets/{chunk-5VM5RSS4-BofAFEcC.js → chunk-5VM5RSS4-C1uXRBQl.js} +1 -1
  49. package/dist/client/assets/{chunk-F27PBJKO-CLNw1JDM.js → chunk-F27PBJKO-BBroEsMn.js} +1 -1
  50. package/dist/client/assets/chunk-F27PBJKO-BBroEsMn.js.br +0 -0
  51. package/dist/client/assets/chunk-F27PBJKO-BBroEsMn.js.gz +0 -0
  52. package/dist/client/assets/{chunk-IMKFNOWR-DsVDl8p7.js → chunk-IMKFNOWR-DulvBTQW.js} +1 -1
  53. package/dist/client/assets/chunk-IMKFNOWR-DulvBTQW.js.br +0 -0
  54. package/dist/client/assets/chunk-IMKFNOWR-DulvBTQW.js.gz +0 -0
  55. package/dist/client/assets/{chunk-JWPE2WC7-CdfzOrPC.js → chunk-JWPE2WC7-C1iD62gS.js} +1 -1
  56. package/dist/client/assets/{chunk-POPQ4Y6H-MXmTC-sG.js → chunk-POPQ4Y6H-1XZwzFea.js} +1 -1
  57. package/dist/client/assets/{chunk-SVP7TREG-DfwfQAY6.js → chunk-SVP7TREG-DPeh3BNp.js} +1 -1
  58. package/dist/client/assets/chunk-SVP7TREG-DPeh3BNp.js.br +0 -0
  59. package/dist/client/assets/chunk-SVP7TREG-DPeh3BNp.js.gz +0 -0
  60. package/dist/client/assets/{chunk-TICWLB2K-N3OPIvmU.js → chunk-TICWLB2K-DeFRSdCH.js} +1 -1
  61. package/dist/client/assets/chunk-TICWLB2K-DeFRSdCH.js.br +0 -0
  62. package/dist/client/assets/chunk-TICWLB2K-DeFRSdCH.js.gz +0 -0
  63. package/dist/client/assets/{chunk-XXDRQBXY-IurIojt5.js → chunk-XXDRQBXY-DxUnOflr.js} +1 -1
  64. package/dist/client/assets/classDiagram-ZZMXUADV-IgYlwyDS.js +1 -0
  65. package/dist/client/assets/classDiagram-v2-VYDZK3BY-IgYlwyDS.js +1 -0
  66. package/dist/client/assets/{cose-bilkent-JH36ORCC-DHbDHTvp.js → cose-bilkent-JH36ORCC-RFbthyXT.js} +1 -1
  67. package/dist/client/assets/cose-bilkent-JH36ORCC-RFbthyXT.js.br +0 -0
  68. package/dist/client/assets/cose-bilkent-JH36ORCC-RFbthyXT.js.gz +0 -0
  69. package/dist/client/assets/{cynefin-OW5HDTMX-DyTW2Iyi.js → cynefin-OW5HDTMX-BynwJL-i.js} +1 -1
  70. package/dist/client/assets/cynefin-OW5HDTMX-BynwJL-i.js.br +0 -0
  71. package/dist/client/assets/cynefin-OW5HDTMX-BynwJL-i.js.gz +0 -0
  72. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-DEan3pcN.js → cynefinDiagram-5FMLGOSQ-DuOeJl1-.js} +1 -1
  73. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DuOeJl1-.js.br +0 -0
  74. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DuOeJl1-.js.gz +0 -0
  75. package/dist/client/assets/{dagre-GXQ25YYZ-Rnw2v1uV.js → dagre-GXQ25YYZ-B5OYEUlw.js} +1 -1
  76. package/dist/client/assets/dagre-GXQ25YYZ-B5OYEUlw.js.br +0 -0
  77. package/dist/client/assets/dagre-GXQ25YYZ-B5OYEUlw.js.gz +0 -0
  78. package/dist/client/assets/{diagram-S7CK7UJ4-CmBa29S9.js → diagram-S7CK7UJ4-KI8T0yjS.js} +1 -1
  79. package/dist/client/assets/diagram-S7CK7UJ4-KI8T0yjS.js.br +0 -0
  80. package/dist/client/assets/diagram-S7CK7UJ4-KI8T0yjS.js.gz +0 -0
  81. package/dist/client/assets/{diagram-UQ7AKVKN-Cqzmpane.js → diagram-UQ7AKVKN-Cj2J871X.js} +1 -1
  82. package/dist/client/assets/diagram-UQ7AKVKN-Cj2J871X.js.br +0 -0
  83. package/dist/client/assets/diagram-UQ7AKVKN-Cj2J871X.js.gz +0 -0
  84. package/dist/client/assets/{diagram-VSXAHHWV-CrHTQozH.js → diagram-VSXAHHWV-CCBeqUWu.js} +1 -1
  85. package/dist/client/assets/diagram-VSXAHHWV-CCBeqUWu.js.br +0 -0
  86. package/dist/client/assets/diagram-VSXAHHWV-CCBeqUWu.js.gz +0 -0
  87. package/dist/client/assets/{diagram-VX7I27RA-C7nQgan9.js → diagram-VX7I27RA-BsYs3AWZ.js} +1 -1
  88. package/dist/client/assets/diagram-VX7I27RA-BsYs3AWZ.js.br +0 -0
  89. package/dist/client/assets/diagram-VX7I27RA-BsYs3AWZ.js.gz +0 -0
  90. package/dist/client/assets/{diagram-Z3DM3KII-93X66n3v.js → diagram-Z3DM3KII-mOM3kQo5.js} +1 -1
  91. package/dist/client/assets/diagram-Z3DM3KII-mOM3kQo5.js.br +0 -0
  92. package/dist/client/assets/diagram-Z3DM3KII-mOM3kQo5.js.gz +0 -0
  93. package/dist/client/assets/{ebnfDiagram-PWID7BFC-LfScrrH8.js → ebnfDiagram-PWID7BFC-fu_iYLIF.js} +1 -1
  94. package/dist/client/assets/ebnfDiagram-PWID7BFC-fu_iYLIF.js.br +0 -0
  95. package/dist/client/assets/ebnfDiagram-PWID7BFC-fu_iYLIF.js.gz +0 -0
  96. package/dist/client/assets/{erDiagram-RLTQ6QDP-DAWKsrIB.js → erDiagram-RLTQ6QDP-BJ8uQuv-.js} +1 -1
  97. package/dist/client/assets/erDiagram-RLTQ6QDP-BJ8uQuv-.js.br +0 -0
  98. package/dist/client/assets/erDiagram-RLTQ6QDP-BJ8uQuv-.js.gz +0 -0
  99. package/dist/client/assets/{flowDiagram-HODETNUW-CcdXfpU7.js → flowDiagram-HODETNUW-BZyUxfJS.js} +1 -1
  100. package/dist/client/assets/flowDiagram-HODETNUW-BZyUxfJS.js.br +0 -0
  101. package/dist/client/assets/flowDiagram-HODETNUW-BZyUxfJS.js.gz +0 -0
  102. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DPLNbHSY.js → ganttDiagram-EL5Y4UJY-z5KFkNWU.js} +1 -1
  103. package/dist/client/assets/ganttDiagram-EL5Y4UJY-z5KFkNWU.js.br +0 -0
  104. package/dist/client/assets/ganttDiagram-EL5Y4UJY-z5KFkNWU.js.gz +0 -0
  105. package/dist/client/assets/{gestureArbiter-B5PxTluh.js → gestureArbiter-C9YKpiBS.js} +1 -1
  106. package/dist/client/assets/gestureArbiter-C9YKpiBS.js.br +0 -0
  107. package/dist/client/assets/gestureArbiter-C9YKpiBS.js.gz +0 -0
  108. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-P741cwUf.js → gitGraphDiagram-WWUBYQGX-BrJHb2xD.js} +1 -1
  109. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BrJHb2xD.js.br +0 -0
  110. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BrJHb2xD.js.gz +0 -0
  111. package/dist/client/assets/{infoDiagram-27XIBGKW-xrl-VW74.js → infoDiagram-27XIBGKW-CSL9Nne-.js} +1 -1
  112. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BJmiVWrB.js → ishikawaDiagram-5VMMS53U-DRcYfZrL.js} +1 -1
  113. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BJmiVWrB.js.br → ishikawaDiagram-5VMMS53U-DRcYfZrL.js.br} +0 -0
  114. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DRcYfZrL.js.gz +0 -0
  115. package/dist/client/assets/{journeyDiagram-3NMN7TZE-DZX8uYK2.js → journeyDiagram-3NMN7TZE-B1Ihp7iG.js} +1 -1
  116. package/dist/client/assets/journeyDiagram-3NMN7TZE-B1Ihp7iG.js.br +0 -0
  117. package/dist/client/assets/journeyDiagram-3NMN7TZE-B1Ihp7iG.js.gz +0 -0
  118. package/dist/client/assets/{kanban-definition-UXKFOSKX-1SmdXf0S.js → kanban-definition-UXKFOSKX-B4B0y8d-.js} +1 -1
  119. package/dist/client/assets/kanban-definition-UXKFOSKX-B4B0y8d-.js.br +0 -0
  120. package/dist/client/assets/kanban-definition-UXKFOSKX-B4B0y8d-.js.gz +0 -0
  121. package/dist/client/assets/{layout-De4QxmMN.js → layout-BlVpm00F.js} +1 -1
  122. package/dist/client/assets/layout-BlVpm00F.js.br +0 -0
  123. package/dist/client/assets/layout-BlVpm00F.js.gz +0 -0
  124. package/dist/client/assets/{linear-Dc93ZnhP.js → linear-6hHPwm_d.js} +1 -1
  125. package/dist/client/assets/linear-6hHPwm_d.js.br +0 -0
  126. package/dist/client/assets/linear-6hHPwm_d.js.gz +0 -0
  127. package/dist/client/assets/{mermaid.core-Ny4ifEul.js → mermaid.core-DPcnsfOi.js} +5 -5
  128. package/dist/client/assets/mermaid.core-DPcnsfOi.js.br +0 -0
  129. package/dist/client/assets/mermaid.core-DPcnsfOi.js.gz +0 -0
  130. package/dist/client/assets/{mindmap-definition-YA3MSWOX-CE75rUrK.js → mindmap-definition-YA3MSWOX-BJKiRn8E.js} +1 -1
  131. package/dist/client/assets/mindmap-definition-YA3MSWOX-BJKiRn8E.js.br +0 -0
  132. package/dist/client/assets/mindmap-definition-YA3MSWOX-BJKiRn8E.js.gz +0 -0
  133. package/dist/client/assets/{passwordBootstrap-BuXV9qsA.js → passwordBootstrap-DOeA8hBZ.js} +1 -1
  134. package/dist/client/assets/passwordBootstrap-DOeA8hBZ.js.br +0 -0
  135. package/dist/client/assets/passwordBootstrap-DOeA8hBZ.js.gz +0 -0
  136. package/dist/client/assets/{pegDiagram-XKGWAZYB-CR8E9wWF.js → pegDiagram-XKGWAZYB-DED8CspT.js} +1 -1
  137. package/dist/client/assets/pegDiagram-XKGWAZYB-DED8CspT.js.br +0 -0
  138. package/dist/client/assets/pegDiagram-XKGWAZYB-DED8CspT.js.gz +0 -0
  139. package/dist/client/assets/{pieDiagram-E7YTZNPT-CKZz2-Iz.js → pieDiagram-E7YTZNPT-9IcWqNZq.js} +1 -1
  140. package/dist/client/assets/pieDiagram-E7YTZNPT-9IcWqNZq.js.br +0 -0
  141. package/dist/client/assets/pieDiagram-E7YTZNPT-9IcWqNZq.js.gz +0 -0
  142. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-w0wqPGg1.js → quadrantDiagram-AXDQQJYC-CrmjzpEv.js} +1 -1
  143. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CrmjzpEv.js.br +0 -0
  144. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CrmjzpEv.js.gz +0 -0
  145. package/dist/client/assets/{railroadDiagram-O6MQD6OU-CWYxj4Iu.js → railroadDiagram-O6MQD6OU-BRbKdDeO.js} +1 -1
  146. package/dist/client/assets/railroadDiagram-O6MQD6OU-BRbKdDeO.js.br +0 -0
  147. package/dist/client/assets/railroadDiagram-O6MQD6OU-BRbKdDeO.js.gz +0 -0
  148. package/dist/client/assets/{referenceLongPress-xQTJmyUv.js → referenceLongPress-DFDR-igt.js} +1 -1
  149. package/dist/client/assets/referenceLongPress-DFDR-igt.js.br +0 -0
  150. package/dist/client/assets/referenceLongPress-DFDR-igt.js.gz +0 -0
  151. package/dist/client/assets/{requirementDiagram-BXWQKSXE-DzcUlIZo.js → requirementDiagram-BXWQKSXE-CKnTGXKk.js} +1 -1
  152. package/dist/client/assets/requirementDiagram-BXWQKSXE-CKnTGXKk.js.br +0 -0
  153. package/dist/client/assets/requirementDiagram-BXWQKSXE-CKnTGXKk.js.gz +0 -0
  154. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-B1KFzqqb.js → sankeyDiagram-P5KCCOFB-DCg3-qjH.js} +1 -1
  155. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DCg3-qjH.js.br +0 -0
  156. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DCg3-qjH.js.gz +0 -0
  157. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Bph5Zy95.js → sequenceDiagram-WJ2MYXX4-BdKp72oL.js} +1 -1
  158. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BdKp72oL.js.br +0 -0
  159. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BdKp72oL.js.gz +0 -0
  160. package/dist/client/assets/{sizeCapture-INFHLROL-B22qdSe2.js → sizeCapture-INFHLROL-bClrPVvk.js} +1 -1
  161. package/dist/client/assets/sizeCapture-INFHLROL-bClrPVvk.js.br +0 -0
  162. package/dist/client/assets/sizeCapture-INFHLROL-bClrPVvk.js.gz +0 -0
  163. package/dist/client/assets/{sparkles-iFGazcNw.js → sparkles-CD2zRzzp.js} +1 -1
  164. package/dist/client/assets/{stateDiagram-D77RDMKH-qt4ZIeIU.js → stateDiagram-D77RDMKH-IW4ojktz.js} +1 -1
  165. package/dist/client/assets/stateDiagram-D77RDMKH-IW4ojktz.js.br +0 -0
  166. package/dist/client/assets/stateDiagram-D77RDMKH-IW4ojktz.js.gz +0 -0
  167. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-UzQ4VZ52.js +1 -0
  168. package/dist/client/assets/{swimlanes-42K2YHIH-BLCfdR2d.js → swimlanes-42K2YHIH-DPEqSZHZ.js} +1 -1
  169. package/dist/client/assets/swimlanes-42K2YHIH-DPEqSZHZ.js.br +0 -0
  170. package/dist/client/assets/swimlanes-42K2YHIH-DPEqSZHZ.js.gz +0 -0
  171. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-wnRqK4Za.js +8 -0
  172. package/dist/client/assets/{timeline-definition-24CTP7MA-B1KrZ6Jd.js → timeline-definition-24CTP7MA-DyWBGHcQ.js} +1 -1
  173. package/dist/client/assets/timeline-definition-24CTP7MA-DyWBGHcQ.js.br +0 -0
  174. package/dist/client/assets/timeline-definition-24CTP7MA-DyWBGHcQ.js.gz +0 -0
  175. package/dist/client/assets/{triangle-alert-BNMREFNU.js → triangle-alert-Cm8GVelT.js} +1 -1
  176. package/dist/client/assets/{vennDiagram-4TSXK5OY-DWNDoCmv.js → vennDiagram-4TSXK5OY-D96Q8vI8.js} +1 -1
  177. package/dist/client/assets/vennDiagram-4TSXK5OY-D96Q8vI8.js.br +0 -0
  178. package/dist/client/assets/vennDiagram-4TSXK5OY-D96Q8vI8.js.gz +0 -0
  179. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdVZqb5Z.js → wardleyDiagram-VM6X3IG4-jMfmwhTE.js} +1 -1
  180. package/dist/client/assets/wardleyDiagram-VM6X3IG4-jMfmwhTE.js.br +0 -0
  181. package/dist/client/assets/wardleyDiagram-VM6X3IG4-jMfmwhTE.js.gz +0 -0
  182. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-C1U9Cr8F.js → xychartDiagram-S5SC5T6Z-DjbvL4uH.js} +1 -1
  183. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DjbvL4uH.js.br +0 -0
  184. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DjbvL4uH.js.gz +0 -0
  185. package/dist/client/index.html +1 -1
  186. package/dist/client/index.html.br +0 -0
  187. package/dist/client/index.html.gz +0 -0
  188. package/dist/client/sw.js +1 -1
  189. package/dist/client/sw.js.br +0 -0
  190. package/dist/client/sw.js.gz +0 -0
  191. package/dist/server/agent/collaborationCli.js +7 -4
  192. package/dist/server/agent/collaborationDeliveryWorker.js +35 -21
  193. package/dist/server/agent/collaborationPrompt.js +46 -6
  194. package/dist/server/agent/collaborationProtocol.js +37 -0
  195. package/dist/server/agent/collaborationRoutes.js +42 -5
  196. package/dist/server/agent/collaborationStore.js +18 -1
  197. package/dist/server/agent/collaborationTmuxDelivery.js +31 -11
  198. package/dist/server/routes/terminal.js +54 -7
  199. package/package.json +1 -1
  200. package/runtime-manifest.json +3 -3
  201. package/dist/client/assets/App-BbIl0DAa.js.br +0 -0
  202. package/dist/client/assets/App-BbIl0DAa.js.gz +0 -0
  203. package/dist/client/assets/ChangeWalkthroughPanel-CT7mLy_e.js.br +0 -0
  204. package/dist/client/assets/ChangeWalkthroughPanel-CT7mLy_e.js.gz +0 -0
  205. package/dist/client/assets/DagPlayground-Bsf4bv7e.js.br +0 -0
  206. package/dist/client/assets/DagPlayground-Bsf4bv7e.js.gz +0 -0
  207. package/dist/client/assets/DiffLab-BjiZcUSn.js.br +0 -0
  208. package/dist/client/assets/DiffLab-BjiZcUSn.js.gz +0 -0
  209. package/dist/client/assets/DiffReview-DmkAyOh4.js.br +0 -0
  210. package/dist/client/assets/DiffReview-DmkAyOh4.js.gz +0 -0
  211. package/dist/client/assets/DiffReviewLab-wXYUmdna.js.br +0 -0
  212. package/dist/client/assets/DiffReviewLab-wXYUmdna.js.gz +0 -0
  213. package/dist/client/assets/DiffViewer-BlwwMnsB.js.br +0 -0
  214. package/dist/client/assets/DiffViewer-BlwwMnsB.js.gz +0 -0
  215. package/dist/client/assets/ModelPreview-DGIaQAcq.js.br +0 -0
  216. package/dist/client/assets/ModelPreview-DGIaQAcq.js.gz +0 -0
  217. package/dist/client/assets/RightSidebar-PgJ0XzEh.js.br +0 -0
  218. package/dist/client/assets/RightSidebar-PgJ0XzEh.js.gz +0 -0
  219. package/dist/client/assets/abnfDiagram-VCTEODGH-B_sCIKms.js.br +0 -0
  220. package/dist/client/assets/abnfDiagram-VCTEODGH-B_sCIKms.js.gz +0 -0
  221. package/dist/client/assets/app-5zC_J9mq.js.br +0 -0
  222. package/dist/client/assets/app-5zC_J9mq.js.gz +0 -0
  223. package/dist/client/assets/arc-Ps2GTfJ3.js.br +0 -0
  224. package/dist/client/assets/arc-Ps2GTfJ3.js.gz +0 -0
  225. package/dist/client/assets/architectureDiagram-5GKGNRK7-DxKfqPAR.js.br +0 -0
  226. package/dist/client/assets/architectureDiagram-5GKGNRK7-DxKfqPAR.js.gz +0 -0
  227. package/dist/client/assets/blockDiagram-I7D4REHJ-BNL8tkC0.js.br +0 -0
  228. package/dist/client/assets/blockDiagram-I7D4REHJ-BNL8tkC0.js.gz +0 -0
  229. package/dist/client/assets/c4Diagram-7LVT6UL2-hyEavwo6.js.br +0 -0
  230. package/dist/client/assets/c4Diagram-7LVT6UL2-hyEavwo6.js.gz +0 -0
  231. package/dist/client/assets/channel-Bkfq4dnz.js +0 -1
  232. package/dist/client/assets/chunk-F27PBJKO-CLNw1JDM.js.br +0 -0
  233. package/dist/client/assets/chunk-F27PBJKO-CLNw1JDM.js.gz +0 -0
  234. package/dist/client/assets/chunk-IMKFNOWR-DsVDl8p7.js.br +0 -0
  235. package/dist/client/assets/chunk-IMKFNOWR-DsVDl8p7.js.gz +0 -0
  236. package/dist/client/assets/chunk-SVP7TREG-DfwfQAY6.js.br +0 -0
  237. package/dist/client/assets/chunk-SVP7TREG-DfwfQAY6.js.gz +0 -0
  238. package/dist/client/assets/chunk-TICWLB2K-N3OPIvmU.js.br +0 -0
  239. package/dist/client/assets/chunk-TICWLB2K-N3OPIvmU.js.gz +0 -0
  240. package/dist/client/assets/classDiagram-ZZMXUADV-Dahb2o7K.js +0 -1
  241. package/dist/client/assets/classDiagram-v2-VYDZK3BY-Dahb2o7K.js +0 -1
  242. package/dist/client/assets/cose-bilkent-JH36ORCC-DHbDHTvp.js.br +0 -0
  243. package/dist/client/assets/cose-bilkent-JH36ORCC-DHbDHTvp.js.gz +0 -0
  244. package/dist/client/assets/cynefin-OW5HDTMX-DyTW2Iyi.js.br +0 -0
  245. package/dist/client/assets/cynefin-OW5HDTMX-DyTW2Iyi.js.gz +0 -0
  246. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DEan3pcN.js.br +0 -0
  247. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DEan3pcN.js.gz +0 -0
  248. package/dist/client/assets/dagre-GXQ25YYZ-Rnw2v1uV.js.br +0 -0
  249. package/dist/client/assets/dagre-GXQ25YYZ-Rnw2v1uV.js.gz +0 -0
  250. package/dist/client/assets/diagram-S7CK7UJ4-CmBa29S9.js.br +0 -0
  251. package/dist/client/assets/diagram-S7CK7UJ4-CmBa29S9.js.gz +0 -0
  252. package/dist/client/assets/diagram-UQ7AKVKN-Cqzmpane.js.br +0 -0
  253. package/dist/client/assets/diagram-UQ7AKVKN-Cqzmpane.js.gz +0 -0
  254. package/dist/client/assets/diagram-VSXAHHWV-CrHTQozH.js.br +0 -0
  255. package/dist/client/assets/diagram-VSXAHHWV-CrHTQozH.js.gz +0 -0
  256. package/dist/client/assets/diagram-VX7I27RA-C7nQgan9.js.br +0 -0
  257. package/dist/client/assets/diagram-VX7I27RA-C7nQgan9.js.gz +0 -0
  258. package/dist/client/assets/diagram-Z3DM3KII-93X66n3v.js.br +0 -0
  259. package/dist/client/assets/diagram-Z3DM3KII-93X66n3v.js.gz +0 -0
  260. package/dist/client/assets/ebnfDiagram-PWID7BFC-LfScrrH8.js.br +0 -0
  261. package/dist/client/assets/ebnfDiagram-PWID7BFC-LfScrrH8.js.gz +0 -0
  262. package/dist/client/assets/erDiagram-RLTQ6QDP-DAWKsrIB.js.br +0 -0
  263. package/dist/client/assets/erDiagram-RLTQ6QDP-DAWKsrIB.js.gz +0 -0
  264. package/dist/client/assets/flowDiagram-HODETNUW-CcdXfpU7.js.br +0 -0
  265. package/dist/client/assets/flowDiagram-HODETNUW-CcdXfpU7.js.gz +0 -0
  266. package/dist/client/assets/ganttDiagram-EL5Y4UJY-DPLNbHSY.js.br +0 -0
  267. package/dist/client/assets/ganttDiagram-EL5Y4UJY-DPLNbHSY.js.gz +0 -0
  268. package/dist/client/assets/gestureArbiter-B5PxTluh.js.br +0 -0
  269. package/dist/client/assets/gestureArbiter-B5PxTluh.js.gz +0 -0
  270. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-P741cwUf.js.br +0 -0
  271. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-P741cwUf.js.gz +0 -0
  272. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BJmiVWrB.js.gz +0 -0
  273. package/dist/client/assets/journeyDiagram-3NMN7TZE-DZX8uYK2.js.br +0 -0
  274. package/dist/client/assets/journeyDiagram-3NMN7TZE-DZX8uYK2.js.gz +0 -0
  275. package/dist/client/assets/kanban-definition-UXKFOSKX-1SmdXf0S.js.br +0 -0
  276. package/dist/client/assets/kanban-definition-UXKFOSKX-1SmdXf0S.js.gz +0 -0
  277. package/dist/client/assets/layout-De4QxmMN.js.br +0 -0
  278. package/dist/client/assets/layout-De4QxmMN.js.gz +0 -0
  279. package/dist/client/assets/linear-Dc93ZnhP.js.br +0 -0
  280. package/dist/client/assets/linear-Dc93ZnhP.js.gz +0 -0
  281. package/dist/client/assets/mermaid.core-Ny4ifEul.js.br +0 -0
  282. package/dist/client/assets/mermaid.core-Ny4ifEul.js.gz +0 -0
  283. package/dist/client/assets/mindmap-definition-YA3MSWOX-CE75rUrK.js.br +0 -0
  284. package/dist/client/assets/mindmap-definition-YA3MSWOX-CE75rUrK.js.gz +0 -0
  285. package/dist/client/assets/passwordBootstrap-BuXV9qsA.js.br +0 -0
  286. package/dist/client/assets/passwordBootstrap-BuXV9qsA.js.gz +0 -0
  287. package/dist/client/assets/pegDiagram-XKGWAZYB-CR8E9wWF.js.br +0 -0
  288. package/dist/client/assets/pegDiagram-XKGWAZYB-CR8E9wWF.js.gz +0 -0
  289. package/dist/client/assets/pieDiagram-E7YTZNPT-CKZz2-Iz.js.br +0 -0
  290. package/dist/client/assets/pieDiagram-E7YTZNPT-CKZz2-Iz.js.gz +0 -0
  291. package/dist/client/assets/quadrantDiagram-AXDQQJYC-w0wqPGg1.js.br +0 -0
  292. package/dist/client/assets/quadrantDiagram-AXDQQJYC-w0wqPGg1.js.gz +0 -0
  293. package/dist/client/assets/railroadDiagram-O6MQD6OU-CWYxj4Iu.js.br +0 -0
  294. package/dist/client/assets/railroadDiagram-O6MQD6OU-CWYxj4Iu.js.gz +0 -0
  295. package/dist/client/assets/referenceLongPress-xQTJmyUv.js.br +0 -0
  296. package/dist/client/assets/referenceLongPress-xQTJmyUv.js.gz +0 -0
  297. package/dist/client/assets/requirementDiagram-BXWQKSXE-DzcUlIZo.js.br +0 -0
  298. package/dist/client/assets/requirementDiagram-BXWQKSXE-DzcUlIZo.js.gz +0 -0
  299. package/dist/client/assets/sankeyDiagram-P5KCCOFB-B1KFzqqb.js.br +0 -0
  300. package/dist/client/assets/sankeyDiagram-P5KCCOFB-B1KFzqqb.js.gz +0 -0
  301. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Bph5Zy95.js.br +0 -0
  302. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Bph5Zy95.js.gz +0 -0
  303. package/dist/client/assets/sizeCapture-INFHLROL-B22qdSe2.js.br +0 -0
  304. package/dist/client/assets/sizeCapture-INFHLROL-B22qdSe2.js.gz +0 -0
  305. package/dist/client/assets/stateDiagram-D77RDMKH-qt4ZIeIU.js.br +0 -0
  306. package/dist/client/assets/stateDiagram-D77RDMKH-qt4ZIeIU.js.gz +0 -0
  307. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-xKezo5Hj.js +0 -1
  308. package/dist/client/assets/swimlanes-42K2YHIH-BLCfdR2d.js.br +0 -0
  309. package/dist/client/assets/swimlanes-42K2YHIH-BLCfdR2d.js.gz +0 -0
  310. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CNA032xr.js +0 -8
  311. package/dist/client/assets/timeline-definition-24CTP7MA-B1KrZ6Jd.js.br +0 -0
  312. package/dist/client/assets/timeline-definition-24CTP7MA-B1KrZ6Jd.js.gz +0 -0
  313. package/dist/client/assets/vennDiagram-4TSXK5OY-DWNDoCmv.js.br +0 -0
  314. package/dist/client/assets/vennDiagram-4TSXK5OY-DWNDoCmv.js.gz +0 -0
  315. package/dist/client/assets/wardleyDiagram-VM6X3IG4-kdVZqb5Z.js.br +0 -0
  316. package/dist/client/assets/wardleyDiagram-VM6X3IG4-kdVZqb5Z.js.gz +0 -0
  317. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C1U9Cr8F.js.br +0 -0
  318. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C1U9Cr8F.js.gz +0 -0
@@ -1,3 +1,4 @@
1
+ import { canonicalShortId } from './collaborationProtocol.js';
1
2
  import { sanitizeCollaborationRole } from './collaborationStore.js';
2
3
  const SHELL_RULE = '─'.repeat(30);
3
4
  /** Body larger than this (in UTF-8 bytes) is replaced by a retrieval pointer
@@ -25,39 +26,78 @@ export function sanitizeCollaborationName(name, max = 40) {
25
26
  .trim();
26
27
  return cleaned.length > max ? `${cleaned.slice(0, max - 1)}…` : cleaned;
27
28
  }
29
+ /** The id form a delivery shows and the confirm gate searches for, per message.
30
+ * Canonical UUIDs shorten to their 8-character prefix (a 36-character id wraps
31
+ * in a narrow pane and has to be retyped by whoever answers it); ids that are
32
+ * not canonical UUIDs pass through untouched. A prefix shared by two messages
33
+ * in the same delivery would make a `includes` search match the wrong block —
34
+ * including against the other one's line still sitting in terminal history —
35
+ * so every colliding message falls back to its full id. The batch is the unit
36
+ * because one delivery is what a confirm search scans against.
37
+ *
38
+ * Delivered text and the confirm gate must both derive the token here: if the
39
+ * text carried a short id while the gate searched the full one, the gate could
40
+ * never match a delivery again and would re-write it until the attempt bound
41
+ * (the "one message arrived three times" regression). */
42
+ export function collaborationMessageAnchorTokens(messages) {
43
+ const counts = new Map();
44
+ for (const message of messages) {
45
+ const short = canonicalShortId(message.id);
46
+ counts.set(short, (counts.get(short) ?? 0) + 1);
47
+ }
48
+ return new Map(messages.map((message) => {
49
+ const short = canonicalShortId(message.id);
50
+ return [message.id, counts.get(short) === 1 ? short : message.id];
51
+ }));
52
+ }
53
+ /** The one line of a delivered block that carries the message's id, chosen by
54
+ * what the recipient can actually do with it: an agent-sourced message gets the
55
+ * reply command, a user message gets the read-back command (`td collab reply`
56
+ * refuses user messages — NO_REPLY_TARGET — so naming it there would be a dead
57
+ * command). Both routes accept the short form (the CLI resolves id prefixes),
58
+ * so whichever token collaborationMessageAnchorTokens picks for this delivery is what
59
+ * the recipient can paste back. Every message must carry its token regardless
60
+ * of source: the invariant is pinned by the "carries its id" test in
61
+ * collaborationPrompt.test.ts. */
62
+ export function collaborationMessageAnchorLine(message, token = canonicalShortId(message.id)) {
63
+ return message.fromSessionId
64
+ ? `回复:td collab reply ${token} "回复内容" --text`
65
+ : `详情:td collab message get ${token} --json`;
66
+ }
28
67
  /** A single delivered message: `来自:X · kind` over a fenced body, with the
29
- * reply route for agent-sourced messages kept outside the fence. A fan-out
68
+ * anchor line (reply route / read-back route) kept outside the fence. A fan-out
30
69
  * dispatch (message.fanOutIds present) is flagged `· 群发` and names the
31
70
  * sibling recipients on their own line, so a broadcast is never mistaken for
32
71
  * a one-to-one assignment — raw ids fall back to the sanitized id itself. */
33
- function formatCollaborationMessage(message, source, fannedNames, fence) {
72
+ function formatCollaborationMessage(message, source, fannedNames, fence, token) {
34
73
  const lines = [`来自:${source} · ${message.kind}${fannedNames.length ? ' · 群发' : ''}`];
35
74
  if (fannedNames.length)
36
75
  lines.push(`同时发给了:${fannedNames.join('、')}`);
37
76
  lines.push('', fence, message.content, fence);
38
77
  if (message.task)
39
78
  lines.push('', `任务上报:${JSON.stringify(message.task)}`);
40
- if (message.fromSessionId)
41
- lines.push('', `回复:td collab reply ${message.id} "回复内容" --text`);
79
+ lines.push('', collaborationMessageAnchorLine(message, token));
42
80
  return lines.join('\n');
43
81
  }
44
82
  export function formatCollaborationDelivery(input) {
45
83
  const groupsById = new Map(input.groups.map((group) => [group.id, group]));
46
84
  const sessionsById = new Map(input.sessions.map((session) => [session.sessionId, session]));
85
+ const tokens = collaborationMessageAnchorTokens(input.messages);
47
86
  const blocks = [];
48
87
  for (const message of input.messages) {
49
88
  const sourceSession = message.fromSessionId ? sessionsById.get(message.fromSessionId) : null;
50
89
  const source = message.fromSessionId
51
90
  ? sanitizeCollaborationName(sourceSession?.name ?? message.fromSessionId)
52
91
  : '用户';
92
+ const token = tokens.get(message.id) ?? message.id;
53
93
  const bytes = Buffer.byteLength(message.content);
54
94
  const body = bytes > MAX_INLINE_BODY_BYTES
55
- ? `大消息已完整保存(${bytes} 字节)。使用 td collab message get ${message.id} --json 获取正文;不要把这条提示当作消息正文。`
95
+ ? `大消息已完整保存(${bytes} 字节)。使用 td collab message get ${token} --json 获取正文;不要把这条提示当作消息正文。`
56
96
  : message.content;
57
97
  const fence = '`'.repeat(Math.max(3, ...Array.from(body.matchAll(/`+/g), (match) => match[0].length + 1)));
58
98
  const fannedNames = (message.fanOutIds ?? [])
59
99
  .map((sessionId) => sanitizeCollaborationName(sessionsById.get(sessionId)?.name ?? sessionId));
60
- blocks.push(formatCollaborationMessage({ ...message, content: body }, source, fannedNames, fence));
100
+ blocks.push(formatCollaborationMessage({ ...message, content: body }, source, fannedNames, fence, token));
61
101
  }
62
102
  // The shell header names the group only when every block belongs to one;
63
103
  // a mixed batch drops the header entirely (no single-group claim to make).
@@ -18,6 +18,43 @@ export class CollaborationError extends Error {
18
18
  this.httpStatus = httpStatus;
19
19
  }
20
20
  }
21
+ /** Canonical message and group ids are UUIDs; a delivered terminal shows only
22
+ * the first 8 characters, because a 36-character id wraps in a narrow pane
23
+ * and has to be retyped by whoever answers it. Shortening is display-only and
24
+ * one-way: storage, wire format, receipts and federation always carry the
25
+ * full id, and every lookup resolves a prefix back to it. Ids that are not
26
+ * canonical UUIDs pass through untouched — a hand-written session id
27
+ * (`40bc89py`), a `remote:<origin>:<id>` address or a `cross-<uuid>` federated
28
+ * group are either already short or decoded by their own structural rules
29
+ * (`split(':')`), so truncating them would corrupt the parse. */
30
+ export const SHORT_ID_LENGTH = 8;
31
+ /** Shortest input accepted as a prefix; below this a lookup is exact-match
32
+ * only, so a one-character typo never turns into an ambiguity error. */
33
+ export const MIN_ID_PREFIX_LENGTH = 4;
34
+ const CANONICAL_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
35
+ export function canonicalShortId(id) {
36
+ return CANONICAL_ID.test(id) ? id.slice(0, SHORT_ID_LENGTH) : id;
37
+ }
38
+ /** Resolve what a user typed against the ids that exist, git-style: an exact
39
+ * match always wins, otherwise a prefix of at least MIN_ID_PREFIX_LENGTH
40
+ * characters resolves when it is unique. Callers turn 'ambiguous' into an
41
+ * error built by ambiguousIdMessage. */
42
+ export function resolveIdPrefix(ids, input) {
43
+ if (ids.includes(input))
44
+ return { status: 'ok', id: input };
45
+ if (input.length < MIN_ID_PREFIX_LENGTH)
46
+ return { status: 'not-found' };
47
+ const matches = ids.filter((id) => id.startsWith(input));
48
+ if (matches.length === 1)
49
+ return { status: 'ok', id: matches[0] };
50
+ return matches.length ? { status: 'ambiguous', matches } : { status: 'not-found' };
51
+ }
52
+ /** Both message and group lookups answer an ambiguous prefix the same way: say
53
+ * how many matched, never which ones (a prefix search can reach another
54
+ * session's ids), and name the way out. */
55
+ export function ambiguousIdMessage(kind, count) {
56
+ return `${kind} id 前缀匹配到 ${count} 个对象,请提供更长的前缀或完整 id`;
57
+ }
21
58
  export function validateExtras(input) {
22
59
  if (input.idempotencyKey !== undefined && (typeof input.idempotencyKey !== 'string' || !input.idempotencyKey.trim() || input.idempotencyKey.length > 256)) {
23
60
  throw new CollaborationError('INVALID_IDEMPOTENCY_KEY', 'idempotency key must contain 1–256 characters');
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { COLLAB_LIMITS, CollaborationError, extrasFromBody } from './collaborationProtocol.js';
2
+ import { COLLAB_LIMITS, CollaborationError, ambiguousIdMessage, extrasFromBody } from './collaborationProtocol.js';
3
3
  /** Member names arrive agent-authored over a CLI; control characters would
4
4
  * corrupt terminal shells, tmux options and persisted records. Fold them to
5
5
  * spaces, collapse runs, and cap the length (display sanitization for the
@@ -30,8 +30,17 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
30
30
  }
31
31
  res.json({ ok: true, route: await rebind(sessionId, pane ?? null) });
32
32
  }));
33
+ /** Accepts the 8-character id a terminal shows as well as the full one; an
34
+ * ambiguous prefix is refused rather than guessed, so a reply can never
35
+ * land on the wrong thread. */
36
+ const resolveMessage = (id) => {
37
+ const resolved = store.resolveMessageId(id);
38
+ if (resolved.status === 'ambiguous')
39
+ throw new CollaborationError('MESSAGE_ID_AMBIGUOUS', ambiguousIdMessage('消息', resolved.matches.length));
40
+ return resolved.status === 'ok' ? store.getMessage(resolved.id) : null;
41
+ };
33
42
  const ownMessage = (id, sessionId, recipientOnly = false) => {
34
- const message = store.getMessage(id);
43
+ const message = resolveMessage(id);
35
44
  if (!message || (message.toSessionId !== sessionId && (recipientOnly || message.fromSessionId !== sessionId)))
36
45
  throw new CollaborationError('MESSAGE_NOT_FOUND', 'Message does not belong to this session', 404);
37
46
  return message;
@@ -83,8 +92,18 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
83
92
  const targets = requestedTargets.length > 0 ? requestedTargets : (target ? [target] : []);
84
93
  if (!targets.length)
85
94
  throw new CollaborationError('NO_TARGET', 'send requires a targetSessionId (or toSessionIds for a fan-out)', 400);
95
+ // `--group` may be the 8-character id; an unresolvable one must stay a
96
+ // GROUP_NOT_FOUND below instead of silently falling back to the only
97
+ // shared group, which would send to a set the sender did not name.
98
+ let requestedGroupId = typeof req.body.group_id === 'string' ? req.body.group_id : '';
99
+ if (requestedGroupId) {
100
+ const resolved = store.resolveGroupId(requestedGroupId);
101
+ if (resolved.status === 'ambiguous')
102
+ throw new CollaborationError('GROUP_ID_AMBIGUOUS', ambiguousIdMessage('协作组', resolved.matches.length));
103
+ requestedGroupId = resolved.status === 'ok' ? resolved.id : requestedGroupId;
104
+ }
86
105
  const groups = store.groupsForSession(sessionId)
87
- .filter((group) => targets.every((candidate) => group.sessionIds.includes(candidate)) && (!req.body.group_id || group.id === req.body.group_id));
106
+ .filter((group) => targets.every((candidate) => group.sessionIds.includes(candidate)) && (!requestedGroupId || group.id === requestedGroupId));
88
107
  if (!groups.length)
89
108
  throw new CollaborationError('GROUP_NOT_FOUND', 'Sender and recipients must share the specified group');
90
109
  if (groups.length > 1 && !req.body.group_id)
@@ -129,9 +148,24 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
129
148
  const since = sinceText === undefined ? undefined : /^\d+$/.test(sinceText) ? Number(sinceText) : Date.parse(sinceText);
130
149
  if (since !== undefined && !Number.isFinite(since))
131
150
  throw new CollaborationError('INVALID_SINCE', 'since must be an ISO timestamp or epoch milliseconds');
151
+ // `--group` accepts the 8-character id; an unresolvable or ambiguous one
152
+ // keeps the caller's text, which matches no group and yields an empty page
153
+ // (the pre-existing behavior for an unknown group filter).
154
+ let groupFilter = string('group');
155
+ if (groupFilter) {
156
+ const resolved = store.resolveGroupId(groupFilter);
157
+ if (resolved.status === 'ok')
158
+ groupFilter = resolved.id;
159
+ }
160
+ let threadFilter = string('thread');
161
+ if (threadFilter) {
162
+ const resolved = store.resolveThreadId(threadFilter);
163
+ if (resolved.status === 'ok')
164
+ threadFilter = resolved.id;
165
+ }
132
166
  const page = store.page(sessionId, { unread: string('unread') === 'true', since, afterId: string('after_id'), cursor: string('cursor'),
133
167
  consumer: string('consumer'), limit: string('limit') ? Number(string('limit')) : undefined,
134
- from: string('from'), group: string('group'), thread: string('thread'), kind: string('kind'), responseKind: string('response_kind'), order: string('order') });
168
+ from: string('from'), group: groupFilter, thread: threadFilter, kind: string('kind'), responseKind: string('response_kind'), order: string('order') });
135
169
  // Fan-out edges carry sibling recipients; the names map lets the CLI text
136
170
  // renderer show 同时发给了:… as people instead of bare session ids. The
137
171
  // fallback to the raw id stays server-side agnostic (federated/offline).
@@ -143,7 +177,10 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
143
177
  res.json({ ok: true, consumer: req.body.consumer, cursor: req.body.cursor });
144
178
  }));
145
179
  const groupOf = (id, sessionId) => {
146
- const group = store.getGroup(id);
180
+ const resolved = store.resolveGroupId(id);
181
+ if (resolved.status === 'ambiguous')
182
+ throw new CollaborationError('GROUP_ID_AMBIGUOUS', ambiguousIdMessage('协作组', resolved.matches.length));
183
+ const group = resolved.status === 'ok' ? store.getGroup(resolved.id) : null;
147
184
  if (!group || group.deleted)
148
185
  throw new CollaborationError('GROUP_NOT_FOUND', 'Collaboration group not found', 404);
149
186
  if (!group.sessionIds.includes(sessionId))
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import crypto from 'node:crypto';
4
- import { COLLAB_LIMITS, CollaborationError, STATUS_RANK, validateExtras } from './collaborationProtocol.js';
4
+ import { COLLAB_LIMITS, CollaborationError, STATUS_RANK, resolveIdPrefix, validateExtras } from './collaborationProtocol.js';
5
5
  /** Characters that would corrupt a role line injected into the delivery shell
6
6
  * (`你的定位:...`) or smuggle terminal output. Unlike names, roles are plain
7
7
  * prose — 「」 and · are harmless there — so only control sequences are barred. */
@@ -57,6 +57,13 @@ export class CollaborationStore {
57
57
  getGroup(id) {
58
58
  return this.document.groups.find((group) => group.id === id) ?? null;
59
59
  }
60
+ /** Typed lookups accept the 8-character id a terminal shows as well as the
61
+ * full one: exact match first, then a unique prefix. Ambiguity is reported,
62
+ * never guessed at, and resolution happens before any send so the
63
+ * idempotency payload hash still sees the full id. */
64
+ resolveGroupId(id) {
65
+ return resolveIdPrefix(this.document.groups.map((group) => group.id), id);
66
+ }
60
67
  save(input) {
61
68
  const now = Date.now();
62
69
  const existing = input.id ? this.document.groups.find((group) => group.id === input.id) : null;
@@ -222,6 +229,16 @@ export class CollaborationStore {
222
229
  this.expire();
223
230
  return this.document.messages.find((message) => message.id === id) ?? null;
224
231
  }
232
+ resolveMessageId(id) {
233
+ this.expire();
234
+ return resolveIdPrefix(this.document.messages.map((message) => message.id), id);
235
+ }
236
+ /** Thread ids are shown shortened alongside message ids, so the `--thread`
237
+ * filter has to take one back the same way. */
238
+ resolveThreadId(id) {
239
+ this.expire();
240
+ return resolveIdPrefix([...new Set(this.document.messages.map((message) => message.threadId).filter((threadId) => Boolean(threadId)))], id);
241
+ }
225
242
  inbox(sessionId, options = {}) {
226
243
  this.expire();
227
244
  const matches = this.document.messages.filter((message) => message.toSessionId === sessionId && (!options.pendingOnly || message.status === 'pending'));
@@ -47,7 +47,16 @@ async function assertSamePane(run, pane) {
47
47
  /** Unique-per-process buffer name so concurrent deliveries to different panes
48
48
  * never share (or clobber) a buffer. */
49
49
  let bufferSequence = 0;
50
- export async function writeCollaborationTmuxPane(run, pane, prompt) {
50
+ export async function writeCollaborationTmuxPane(run, pane, prompt,
51
+ /** Sends `input` to the tmux client's stdin. The steps below are one `\;`
52
+ * chain (see the comment inside), and a chain is argv, so the body must not
53
+ * ride in argv: tmux treats an element that is exactly `;` as a separator
54
+ * even after `--`, and its backslash unescaping is version-dependent
55
+ * (`\\` survives verbatim while `\;` collapses to `;`). Reading the body
56
+ * from stdin sidesteps both — every byte round-trips unchanged. Required,
57
+ * not optional: a run() that ignored the payload would load an empty buffer
58
+ * and fail the delivery rather than deliver the wrong thing. */
59
+ stdin) {
51
60
  await assertSamePane(run, pane);
52
61
  // A fixed pane target is independent of the current window, keyboard focus
53
62
  // and browser presence. Delivery goes through a named tmux buffer rather
@@ -67,16 +76,27 @@ export async function writeCollaborationTmuxPane(run, pane, prompt) {
67
76
  // every tmux version.
68
77
  const buffer = `termdock-collab-${process.pid}-${bufferSequence++}`;
69
78
  try {
70
- await run(['set-buffer', '-b', buffer, '--', normalizePromptForPaste(prompt)]);
71
- // -r keeps LF as LF rather than the separator default of CR. The
72
- // normalizer already folded every line break to CR, so no LF is left for
73
- // it to rewrite the flag is insurance, not the mechanism.
74
- await run(['paste-buffer', '-p', '-r', '-d', '-b', buffer, '-t', pane.paneId]);
75
- // The submit key rides outside the paste block: inside it, an editor
76
- // inserts a pasted CR as text instead of acting on it. Pasting the bare
77
- // CR (no -p) keeps the key in the same mode-proof channel as the text.
78
- await run(['set-buffer', '-b', buffer, '--', '\r']);
79
- await run(['paste-buffer', '-d', '-b', buffer, '-t', pane.paneId]);
79
+ // The four steps ride one client invocation joined by tmux's `\;`: the
80
+ // server runs them back to back in a single queue item, so no other
81
+ // client's paste can interleave between our text and our submit CR
82
+ // (measured: one contiguous block, 0ms apart, versus two invocations
83
+ // ~14ms apart). A failing step stops the rest — verified on 3.4 and 3.7 —
84
+ // which is the safe direction: a failed text paste is never followed by a
85
+ // bare CR into whatever the input box already held.
86
+ await stdin([
87
+ // The body arrives on stdin, not argv: it is user content, and in a
88
+ // `\;` chain argv is a language where `;` and `\` mean something.
89
+ 'load-buffer', '-b', buffer, '-', ';',
90
+ // -r keeps LF as LF rather than the separator default of CR. The
91
+ // normalizer already folded every line break to CR, so no LF is left
92
+ // for it to rewrite — the flag is insurance, not the mechanism.
93
+ 'paste-buffer', '-p', '-r', '-d', '-b', buffer, '-t', pane.paneId, ';',
94
+ // The submit key rides outside the paste block: inside it, an editor
95
+ // inserts a pasted CR as text instead of acting on it. Pasting the bare
96
+ // CR (no -p) keeps the key in the same mode-proof channel as the text.
97
+ 'set-buffer', '-b', buffer, '--', '\r', ';',
98
+ 'paste-buffer', '-d', '-b', buffer, '-t', pane.paneId,
99
+ ], normalizePromptForPaste(prompt));
80
100
  }
81
101
  finally {
82
102
  // -d consumed the buffer on the happy path; this sweeps up after a failed
@@ -40,6 +40,7 @@ import { collaborationRoutes } from '../agent/collaborationRoutes.js';
40
40
  import { COLLAB_LIMITS, extrasFromBody } from '../agent/collaborationProtocol.js';
41
41
  import { CollaborationStore } from '../agent/collaborationStore.js';
42
42
  import { COLLAB_NAME_FORBIDDEN, formatCollaborationDelivery } from '../agent/collaborationPrompt.js';
43
+ import { ambiguousIdMessage } from '../agent/collaborationProtocol.js';
43
44
  import { buildCollaborationSpawnCommand, resolveCollaborationSpawnMode } from '../agent/collaborationSpawn.js';
44
45
  import { SessionSearchStore } from '../agent/sessionSearchStore.js';
45
46
  import { resolveCollaborationBackend, resolveCollaborationSessionId } from '../agent/sessionBindingRecovery.js';
@@ -1610,7 +1611,7 @@ async function resolveCollaborationRoute(frontendSessionId) {
1610
1611
  return { state: 'ready', capture: async () => (await captureTmuxPane(pinned.paneId)).content, write: async (messages) => {
1611
1612
  if (!globalSessionState.sessions.some((candidate) => candidate.sessionId === frontendSessionId))
1612
1613
  throw new Error('SESSION_REMOVED');
1613
- await writeCollaborationTmuxPane(runTmux, pinned, formatLocalCollaborationMessages(frontendSessionId, messages));
1614
+ await writeCollaborationTmuxPane(runTmux, pinned, formatLocalCollaborationMessages(frontendSessionId, messages), runTmuxStdin);
1614
1615
  backend.lastActivity = Date.now();
1615
1616
  // First-delivery confirm: history proves the agent rendered our
1616
1617
  // message (boot sequences clear only the screen, never the history a
@@ -1735,6 +1736,32 @@ async function runTmux(args) {
1735
1736
  });
1736
1737
  return stdout;
1737
1738
  }
1739
+ /** runTmux with a payload on the client's stdin — how delivery hands user
1740
+ * content to `load-buffer -`. Kept separate from runTmux so the many callers
1741
+ * that never pipe anything are untouched. */
1742
+ async function runTmuxStdin(args, input) {
1743
+ const child = execFile(getTmuxBinary(), args, {
1744
+ timeout: 5000,
1745
+ maxBuffer: 2 * 1024 * 1024,
1746
+ env: buildInteractiveColorEnvironment(process.env),
1747
+ });
1748
+ // Write then end: tmux reads stdin to EOF for `load-buffer -`.
1749
+ child.stdin?.end(input);
1750
+ const { stdout } = await new Promise((resolve, reject) => {
1751
+ let stdout = '';
1752
+ let stderr = '';
1753
+ child.stdout?.on('data', (chunk) => { stdout += chunk; });
1754
+ child.stderr?.on('data', (chunk) => { stderr += chunk; });
1755
+ child.on('error', reject);
1756
+ child.on('close', (code) => (code === 0
1757
+ ? resolve({ stdout })
1758
+ // Carry tmux's own message: it names the failing step ("no buffer X",
1759
+ // "target pane has exited"), which is what makes a delivery failure
1760
+ // diagnosable from the transport diagnostic alone.
1761
+ : reject(new Error(`tmux exited with ${code}${stderr.trim() ? `: ${stderr.trim()}` : ''}`))));
1762
+ });
1763
+ return stdout;
1764
+ }
1738
1765
  // ---- Persistent tmux control-mode connection ----
1739
1766
  // Instead of spawning a new `tmux` process per command (execFile overhead),
1740
1767
  // maintain a single `tmux -C attach` child process per session. Commands
@@ -5493,8 +5520,20 @@ router.post('/operations/collaboration-federation', (req, res) => {
5493
5520
  });
5494
5521
  router.use('/operations', collaborationGroupRoutes({ store: collaborationStore,
5495
5522
  sessions: () => globalSessionState.sessions.map(orchestrationSessionSnapshot) }));
5523
+ /** Group id from a URL param: the 8-character id a terminal shows resolves to
5524
+ * its full id, an ambiguous prefix is refused with 409, and anything else is
5525
+ * simply "no such group" — the same 404 each route already answers. */
5526
+ function resolveGroupParam(id) {
5527
+ const resolved = collaborationStore.resolveGroupId(id);
5528
+ if (resolved.status === 'ambiguous')
5529
+ return { group: null, ambiguous: resolved.matches.length };
5530
+ return { group: resolved.status === 'ok' ? collaborationStore.getGroup(resolved.id) : null, ambiguous: 0 };
5531
+ }
5532
+ const ambiguousGroupResponse = (res, count) => res.status(409).json({ error: ambiguousIdMessage('协作组', count), code: 'GROUP_ID_AMBIGUOUS' });
5496
5533
  router.post('/operations/collaboration-groups/:groupId/spawn', async (req, res) => {
5497
- const group = collaborationStore.getGroup(req.params.groupId);
5534
+ const { group, ambiguous } = resolveGroupParam(req.params.groupId);
5535
+ if (ambiguous)
5536
+ return ambiguousGroupResponse(res, ambiguous);
5498
5537
  if (!group)
5499
5538
  return res.status(404).json({ error: '协作组不存在' });
5500
5539
  try {
@@ -5507,14 +5546,18 @@ router.post('/operations/collaboration-groups/:groupId/spawn', async (req, res)
5507
5546
  }
5508
5547
  });
5509
5548
  router.get('/operations/collaboration-groups/:groupId/messages', (req, res) => {
5510
- const group = collaborationStore.getGroup(req.params.groupId);
5549
+ const { group, ambiguous } = resolveGroupParam(req.params.groupId);
5550
+ if (ambiguous)
5551
+ return ambiguousGroupResponse(res, ambiguous);
5511
5552
  if (!group)
5512
5553
  return res.status(404).json({ error: '协作组不存在' });
5513
5554
  res.json({ messages: collaborationStore.listMessages(group.id, Number(req.query.limit) || 200) });
5514
5555
  });
5515
5556
  router.post('/operations/collaboration-groups/:groupId/messages', (req, res) => {
5516
5557
  try {
5517
- const group = collaborationStore.getGroup(req.params.groupId);
5558
+ const { group, ambiguous } = resolveGroupParam(req.params.groupId);
5559
+ if (ambiguous)
5560
+ return ambiguousGroupResponse(res, ambiguous);
5518
5561
  if (!group)
5519
5562
  return res.status(404).json({ error: '协作组不存在' });
5520
5563
  const fromSessionId = resolveFrontendSessionId(req.body ?? {});
@@ -5566,7 +5609,9 @@ router.post('/operations/orchestration/members', (req, res) => {
5566
5609
  const groupId = typeof req.body?.groupId === 'string' ? req.body.groupId.trim() : '';
5567
5610
  const targetSessionId = typeof req.body?.targetSessionId === 'string' ? req.body.targetSessionId.trim() : '';
5568
5611
  const action = req.body?.action === 'remove' ? 'remove' : req.body?.action === 'add' ? 'add' : null;
5569
- const group = collaborationStore.getGroup(groupId);
5612
+ const { group, ambiguous } = resolveGroupParam(groupId);
5613
+ if (ambiguous)
5614
+ return ambiguousGroupResponse(res, ambiguous);
5570
5615
  if (!sourceSessionId)
5571
5616
  return res.status(400).json({ error: '无法识别当前会话;请从 Termdock 会话内运行 td collab' });
5572
5617
  if (!group || !group.sessionIds.includes(sourceSessionId))
@@ -5587,7 +5632,9 @@ router.post('/operations/orchestration/members', (req, res) => {
5587
5632
  router.post('/operations/orchestration/spawn', async (req, res) => {
5588
5633
  const sourceSessionId = resolveFrontendSessionId(req.body ?? {});
5589
5634
  const groupId = typeof req.body?.groupId === 'string' ? req.body.groupId.trim() : '';
5590
- const group = collaborationStore.getGroup(groupId);
5635
+ const { group, ambiguous } = resolveGroupParam(groupId);
5636
+ if (ambiguous)
5637
+ return ambiguousGroupResponse(res, ambiguous);
5591
5638
  if (!sourceSessionId)
5592
5639
  return res.status(400).json({ error: '无法识别当前会话;请从 Termdock 会话内运行 td collab' });
5593
5640
  if (!group || !group.sessionIds.includes(sourceSessionId))
@@ -5781,7 +5828,7 @@ router.post('/operations/orchestration/drive', async (req, res) => {
5781
5828
  return res.status(400).json({ error: 'run 文本过长(上限 10000 字符);需要更多内容请走 td collab send 投递' });
5782
5829
  // Same bracketed-paste write path deliveries use: one line, one submit,
5783
5830
  // embedded newlines stay inside the recipient's editor.
5784
- await writeCollaborationTmuxPane(runTmux, pane, text);
5831
+ await writeCollaborationTmuxPane(runTmux, pane, text, runTmuxStdin);
5785
5832
  const snapshot = await captureTmuxPaneText(runTmux, pane);
5786
5833
  return res.json({ ok: true, action, sessionId: target, text, snapshot });
5787
5834
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.194",
3
+ "version": "1.4.196",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.194",
4
+ "version": "1.4.196",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
8
  "dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
9
- "serverBundleHash": "sha256-2Y3XSbsDOzYXhEe57Szt3L16aZzGBDb1ZA/6TsYIiOQ=",
10
- "clientBundleHash": "sha256-wpGsT/oJup/G4MyJSKqpHBJlzc2Ha3wFIWmtp4vc/Wc=",
9
+ "serverBundleHash": "sha256-T/KLnvRkLhdOmsag6ksQv7ZoSL8RTw328UNIFTUC3/4=",
10
+ "clientBundleHash": "sha256-EQPT/w33vRGcZlyZoRHKmtgmEPWiRSGjRGHBx2SAwOw=",
11
11
  "entrypoint": "dist/server/cli.js",
12
12
  "clientEntrypoint": "dist/client/index.html"
13
13
  }
@@ -1 +0,0 @@
1
- import{c as a,C as n}from"./mermaid.core-Ny4ifEul.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as t,C as e}from"./chunk-TICWLB2K-N3OPIvmU.js";import{d as i}from"./mermaid.core-Ny4ifEul.js";import"./chunk-5VM5RSS4-BofAFEcC.js";import"./chunk-XXDRQBXY-IurIojt5.js";import"./chunk-POPQ4Y6H-MXmTC-sG.js";import"./chunk-F27PBJKO-CLNw1JDM.js";import"./purify.es-4eNOHKSq.js";import"./app-5zC_J9mq.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as t,C as e}from"./chunk-TICWLB2K-N3OPIvmU.js";import{d as i}from"./mermaid.core-Ny4ifEul.js";import"./chunk-5VM5RSS4-BofAFEcC.js";import"./chunk-XXDRQBXY-IurIojt5.js";import"./chunk-POPQ4Y6H-MXmTC-sG.js";import"./chunk-F27PBJKO-CLNw1JDM.js";import"./purify.es-4eNOHKSq.js";import"./app-5zC_J9mq.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};