termdock 1.4.299 → 1.4.301

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 (372) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +2 -1
  3. package/dist/client/assets/App-BziVLy1b.js +179 -0
  4. package/dist/client/assets/App-BziVLy1b.js.br +0 -0
  5. package/dist/client/assets/App-BziVLy1b.js.gz +0 -0
  6. package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js +12 -0
  7. package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js.br +0 -0
  8. package/dist/client/assets/ArchitecturePanel-CARNBEqQ.js.gz +0 -0
  9. package/dist/client/assets/{ChangeWalkthroughPanel-2lXfrgk4.js → ChangeWalkthroughPanel-00oa0z6w.js} +2 -2
  10. package/dist/client/assets/ChangeWalkthroughPanel-00oa0z6w.js.br +0 -0
  11. package/dist/client/assets/ChangeWalkthroughPanel-00oa0z6w.js.gz +0 -0
  12. package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js +1 -0
  13. package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js.br +0 -0
  14. package/dist/client/assets/CollaborationMainWorkspace-DuEeKQKZ.js.gz +0 -0
  15. package/dist/client/assets/CollaborationTaskContent-B_mzpNuw.js +2 -0
  16. package/dist/client/assets/ComputerControlView-C9v1Ooc9.js +5 -0
  17. package/dist/client/assets/ComputerControlView-C9v1Ooc9.js.br +0 -0
  18. package/dist/client/assets/ComputerControlView-C9v1Ooc9.js.gz +0 -0
  19. package/dist/client/assets/{DagPlayground-EFUb9S3u.js → DagPlayground-DfUpMALj.js} +1 -1
  20. package/dist/client/assets/DagPlayground-DfUpMALj.js.br +0 -0
  21. package/dist/client/assets/DagPlayground-DfUpMALj.js.gz +0 -0
  22. package/dist/client/assets/{DiffLab-CXWjSE2q.js → DiffLab-Cf_URhQt.js} +1 -1
  23. package/dist/client/assets/DiffLab-Cf_URhQt.js.br +0 -0
  24. package/dist/client/assets/DiffLab-Cf_URhQt.js.gz +0 -0
  25. package/dist/client/assets/{DiffReview-ByMkBaD9.js → DiffReview-DjG9vCpH.js} +1 -1
  26. package/dist/client/assets/DiffReview-DjG9vCpH.js.br +0 -0
  27. package/dist/client/assets/DiffReview-DjG9vCpH.js.gz +0 -0
  28. package/dist/client/assets/{DiffReviewLab-DoWaKm94.js → DiffReviewLab-BKOvHdJY.js} +2 -2
  29. package/dist/client/assets/DiffReviewLab-BKOvHdJY.js.br +0 -0
  30. package/dist/client/assets/DiffReviewLab-BKOvHdJY.js.gz +0 -0
  31. package/dist/client/assets/{DiffViewer-B4hn9z0k.js → DiffViewer-6n3tgsdc.js} +8 -8
  32. package/dist/client/assets/DiffViewer-6n3tgsdc.js.br +0 -0
  33. package/dist/client/assets/DiffViewer-6n3tgsdc.js.gz +0 -0
  34. package/dist/client/assets/{ModelPreview-C-LJZ8so.js → ModelPreview-BNs2sRct.js} +1 -1
  35. package/dist/client/assets/ModelPreview-BNs2sRct.js.br +0 -0
  36. package/dist/client/assets/ModelPreview-BNs2sRct.js.gz +0 -0
  37. package/dist/client/assets/RightSidebar-CcMSU1v8.js +1677 -0
  38. package/dist/client/assets/RightSidebar-CcMSU1v8.js.br +0 -0
  39. package/dist/client/assets/RightSidebar-CcMSU1v8.js.gz +0 -0
  40. package/dist/client/assets/{abnfDiagram-VCTEODGH-BY-pfYKk.js → abnfDiagram-VCTEODGH-DogjvRKp.js} +1 -1
  41. package/dist/client/assets/abnfDiagram-VCTEODGH-DogjvRKp.js.br +0 -0
  42. package/dist/client/assets/abnfDiagram-VCTEODGH-DogjvRKp.js.gz +0 -0
  43. package/dist/client/assets/app-D6vN8PW-.js +35 -0
  44. package/dist/client/assets/app-D6vN8PW-.js.br +0 -0
  45. package/dist/client/assets/app-D6vN8PW-.js.gz +0 -0
  46. package/dist/client/assets/{arc-DIENgCZn.js → arc-Cqel4Ted.js} +1 -1
  47. package/dist/client/assets/arc-Cqel4Ted.js.br +0 -0
  48. package/dist/client/assets/arc-Cqel4Ted.js.gz +0 -0
  49. package/dist/client/assets/{architectureDiagram-5GKGNRK7-C1h4e4az.js → architectureDiagram-5GKGNRK7-DgvPtgNb.js} +1 -1
  50. package/dist/client/assets/architectureDiagram-5GKGNRK7-DgvPtgNb.js.br +0 -0
  51. package/dist/client/assets/architectureDiagram-5GKGNRK7-DgvPtgNb.js.gz +0 -0
  52. package/dist/client/assets/{blockDiagram-I7D4REHJ-B_yOr54K.js → blockDiagram-I7D4REHJ-BxbWO4x4.js} +1 -1
  53. package/dist/client/assets/blockDiagram-I7D4REHJ-BxbWO4x4.js.br +0 -0
  54. package/dist/client/assets/blockDiagram-I7D4REHJ-BxbWO4x4.js.gz +0 -0
  55. package/dist/client/assets/{c4Diagram-7LVT6UL2-DRD4zxIo.js → c4Diagram-7LVT6UL2-gsA37gjL.js} +1 -1
  56. package/dist/client/assets/c4Diagram-7LVT6UL2-gsA37gjL.js.br +0 -0
  57. package/dist/client/assets/c4Diagram-7LVT6UL2-gsA37gjL.js.gz +0 -0
  58. package/dist/client/assets/channel-CBc8-n7y.js +1 -0
  59. package/dist/client/assets/{chunk-2Q5K7J3B-CXytnjmD.js → chunk-2Q5K7J3B-ChC9yYOd.js} +1 -1
  60. package/dist/client/assets/{chunk-5VM5RSS4-Bjmajkf7.js → chunk-5VM5RSS4-Bi4Hc8yL.js} +1 -1
  61. package/dist/client/assets/{chunk-F27PBJKO-CQCL8mJG.js → chunk-F27PBJKO-DvVWvQEk.js} +1 -1
  62. package/dist/client/assets/chunk-F27PBJKO-DvVWvQEk.js.br +0 -0
  63. package/dist/client/assets/chunk-F27PBJKO-DvVWvQEk.js.gz +0 -0
  64. package/dist/client/assets/{chunk-IMKFNOWR-ruHGCADe.js → chunk-IMKFNOWR-BnwQLR5S.js} +1 -1
  65. package/dist/client/assets/chunk-IMKFNOWR-BnwQLR5S.js.br +0 -0
  66. package/dist/client/assets/chunk-IMKFNOWR-BnwQLR5S.js.gz +0 -0
  67. package/dist/client/assets/{chunk-JWPE2WC7-U18S7rxZ.js → chunk-JWPE2WC7-BkNnaDiR.js} +1 -1
  68. package/dist/client/assets/{chunk-POPQ4Y6H-DWnwssfL.js → chunk-POPQ4Y6H-BRzm6Uzi.js} +1 -1
  69. package/dist/client/assets/{chunk-SVP7TREG-DMHj3NSq.js → chunk-SVP7TREG-CDYm-dzk.js} +1 -1
  70. package/dist/client/assets/chunk-SVP7TREG-CDYm-dzk.js.br +0 -0
  71. package/dist/client/assets/chunk-SVP7TREG-CDYm-dzk.js.gz +0 -0
  72. package/dist/client/assets/{chunk-TICWLB2K-Dh_ekvFW.js → chunk-TICWLB2K-BKaW9Z9i.js} +1 -1
  73. package/dist/client/assets/chunk-TICWLB2K-BKaW9Z9i.js.br +0 -0
  74. package/dist/client/assets/chunk-TICWLB2K-BKaW9Z9i.js.gz +0 -0
  75. package/dist/client/assets/{chunk-XXDRQBXY-Bq5wD6iJ.js → chunk-XXDRQBXY-DcHZ_FHb.js} +1 -1
  76. package/dist/client/assets/classDiagram-ZZMXUADV-CNFc2dOc.js +1 -0
  77. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CNFc2dOc.js +1 -0
  78. package/dist/client/assets/{cose-bilkent-JH36ORCC-CsySWhYg.js → cose-bilkent-JH36ORCC-DCbbTNc6.js} +1 -1
  79. package/dist/client/assets/cose-bilkent-JH36ORCC-DCbbTNc6.js.br +0 -0
  80. package/dist/client/assets/cose-bilkent-JH36ORCC-DCbbTNc6.js.gz +0 -0
  81. package/dist/client/assets/{cynefin-OW5HDTMX-9DKE5wV7.js → cynefin-OW5HDTMX-i23hD0Z2.js} +1 -1
  82. package/dist/client/assets/cynefin-OW5HDTMX-i23hD0Z2.js.br +0 -0
  83. package/dist/client/assets/cynefin-OW5HDTMX-i23hD0Z2.js.gz +0 -0
  84. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-B_8fvr9c.js → cynefinDiagram-5FMLGOSQ-CbyLYcqc.js} +1 -1
  85. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbyLYcqc.js.br +0 -0
  86. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbyLYcqc.js.gz +0 -0
  87. package/dist/client/assets/{dagre-GXQ25YYZ-BOdsFNFT.js → dagre-GXQ25YYZ-iJ4VKzZm.js} +1 -1
  88. package/dist/client/assets/dagre-GXQ25YYZ-iJ4VKzZm.js.br +0 -0
  89. package/dist/client/assets/dagre-GXQ25YYZ-iJ4VKzZm.js.gz +0 -0
  90. package/dist/client/assets/{diagram-S7CK7UJ4-6v_qvAvi.js → diagram-S7CK7UJ4-BNVZcdsO.js} +1 -1
  91. package/dist/client/assets/diagram-S7CK7UJ4-BNVZcdsO.js.br +0 -0
  92. package/dist/client/assets/diagram-S7CK7UJ4-BNVZcdsO.js.gz +0 -0
  93. package/dist/client/assets/{diagram-UQ7AKVKN-c03oOGhD.js → diagram-UQ7AKVKN-1ghTvPiu.js} +1 -1
  94. package/dist/client/assets/diagram-UQ7AKVKN-1ghTvPiu.js.br +0 -0
  95. package/dist/client/assets/diagram-UQ7AKVKN-1ghTvPiu.js.gz +0 -0
  96. package/dist/client/assets/{diagram-VSXAHHWV-MMIhRYp_.js → diagram-VSXAHHWV-Ce_0nMd3.js} +1 -1
  97. package/dist/client/assets/diagram-VSXAHHWV-Ce_0nMd3.js.br +0 -0
  98. package/dist/client/assets/diagram-VSXAHHWV-Ce_0nMd3.js.gz +0 -0
  99. package/dist/client/assets/{diagram-VX7I27RA-B_l-uebl.js → diagram-VX7I27RA-CLHEkhUt.js} +1 -1
  100. package/dist/client/assets/diagram-VX7I27RA-CLHEkhUt.js.br +0 -0
  101. package/dist/client/assets/diagram-VX7I27RA-CLHEkhUt.js.gz +0 -0
  102. package/dist/client/assets/{diagram-Z3DM3KII-DKoBC5gn.js → diagram-Z3DM3KII-iyb5DkP6.js} +1 -1
  103. package/dist/client/assets/diagram-Z3DM3KII-iyb5DkP6.js.br +0 -0
  104. package/dist/client/assets/diagram-Z3DM3KII-iyb5DkP6.js.gz +0 -0
  105. package/dist/client/assets/{ebnfDiagram-PWID7BFC-Bs3wu8Az.js → ebnfDiagram-PWID7BFC-Dxh2TzXm.js} +1 -1
  106. package/dist/client/assets/ebnfDiagram-PWID7BFC-Dxh2TzXm.js.br +0 -0
  107. package/dist/client/assets/ebnfDiagram-PWID7BFC-Dxh2TzXm.js.gz +0 -0
  108. package/dist/client/assets/{erDiagram-RLTQ6QDP-mYnHYbKl.js → erDiagram-RLTQ6QDP-Cr8IkdCC.js} +1 -1
  109. package/dist/client/assets/erDiagram-RLTQ6QDP-Cr8IkdCC.js.br +0 -0
  110. package/dist/client/assets/erDiagram-RLTQ6QDP-Cr8IkdCC.js.gz +0 -0
  111. package/dist/client/assets/{flowDiagram-HODETNUW-CwCLWbib.js → flowDiagram-HODETNUW-B8ZF1bwr.js} +1 -1
  112. package/dist/client/assets/flowDiagram-HODETNUW-B8ZF1bwr.js.br +0 -0
  113. package/dist/client/assets/flowDiagram-HODETNUW-B8ZF1bwr.js.gz +0 -0
  114. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-mse8c-ni.js → ganttDiagram-EL5Y4UJY-zhdL10eM.js} +1 -1
  115. package/dist/client/assets/ganttDiagram-EL5Y4UJY-zhdL10eM.js.br +0 -0
  116. package/dist/client/assets/ganttDiagram-EL5Y4UJY-zhdL10eM.js.gz +0 -0
  117. package/dist/client/assets/{gestureArbiter-BviL29ps.js → gestureArbiter-CXYHfU__.js} +1 -1
  118. package/dist/client/assets/gestureArbiter-CXYHfU__.js.br +0 -0
  119. package/dist/client/assets/gestureArbiter-CXYHfU__.js.gz +0 -0
  120. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BVUfLjAX.js → gitGraphDiagram-WWUBYQGX-BQf2fHBo.js} +1 -1
  121. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BQf2fHBo.js.br +0 -0
  122. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BQf2fHBo.js.gz +0 -0
  123. package/dist/client/assets/{index-C6ftfFlG.css → index-CNY7CTVa.css} +1 -1
  124. package/dist/client/assets/index-CNY7CTVa.css.br +0 -0
  125. package/dist/client/assets/index-CNY7CTVa.css.gz +0 -0
  126. package/dist/client/assets/{infoDiagram-27XIBGKW-XjoFF4BC.js → infoDiagram-27XIBGKW-BT8xey7S.js} +1 -1
  127. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-bH299bWL.js → ishikawaDiagram-5VMMS53U-DunPdwW9.js} +1 -1
  128. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DunPdwW9.js.br +0 -0
  129. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DunPdwW9.js.gz +0 -0
  130. package/dist/client/assets/{journeyDiagram-3NMN7TZE-BG0u_X1A.js → journeyDiagram-3NMN7TZE-B0y75iIg.js} +1 -1
  131. package/dist/client/assets/journeyDiagram-3NMN7TZE-B0y75iIg.js.br +0 -0
  132. package/dist/client/assets/journeyDiagram-3NMN7TZE-B0y75iIg.js.gz +0 -0
  133. package/dist/client/assets/{kanban-definition-UXKFOSKX-DRoc9N-i.js → kanban-definition-UXKFOSKX-BfgA5WLo.js} +1 -1
  134. package/dist/client/assets/kanban-definition-UXKFOSKX-BfgA5WLo.js.br +0 -0
  135. package/dist/client/assets/kanban-definition-UXKFOSKX-BfgA5WLo.js.gz +0 -0
  136. package/dist/client/assets/{layout-mh0t6JpE.js → layout-BvjABLff.js} +1 -1
  137. package/dist/client/assets/layout-BvjABLff.js.br +0 -0
  138. package/dist/client/assets/layout-BvjABLff.js.gz +0 -0
  139. package/dist/client/assets/{linear-B9KTRuUV.js → linear-DgeFRliF.js} +1 -1
  140. package/dist/client/assets/linear-DgeFRliF.js.br +0 -0
  141. package/dist/client/assets/linear-DgeFRliF.js.gz +0 -0
  142. package/dist/client/assets/{mermaid.core-Bu2G9zhK.js → mermaid.core-DM6Rlal9.js} +5 -5
  143. package/dist/client/assets/mermaid.core-DM6Rlal9.js.br +0 -0
  144. package/dist/client/assets/mermaid.core-DM6Rlal9.js.gz +0 -0
  145. package/dist/client/assets/{mindmap-definition-YA3MSWOX-Go6Bg5xm.js → mindmap-definition-YA3MSWOX-DhEiABv6.js} +1 -1
  146. package/dist/client/assets/mindmap-definition-YA3MSWOX-DhEiABv6.js.br +0 -0
  147. package/dist/client/assets/mindmap-definition-YA3MSWOX-DhEiABv6.js.gz +0 -0
  148. package/dist/client/assets/{passwordBootstrap-C7-MUAHQ.js → passwordBootstrap-Dxv0I4wM.js} +1 -1
  149. package/dist/client/assets/passwordBootstrap-Dxv0I4wM.js.br +0 -0
  150. package/dist/client/assets/passwordBootstrap-Dxv0I4wM.js.gz +0 -0
  151. package/dist/client/assets/{pegDiagram-XKGWAZYB-DKUIl_U6.js → pegDiagram-XKGWAZYB-LTlVaJfm.js} +1 -1
  152. package/dist/client/assets/pegDiagram-XKGWAZYB-LTlVaJfm.js.br +0 -0
  153. package/dist/client/assets/pegDiagram-XKGWAZYB-LTlVaJfm.js.gz +0 -0
  154. package/dist/client/assets/{pieDiagram-E7YTZNPT-aoDNlV7J.js → pieDiagram-E7YTZNPT-9bnryna3.js} +1 -1
  155. package/dist/client/assets/pieDiagram-E7YTZNPT-9bnryna3.js.br +0 -0
  156. package/dist/client/assets/pieDiagram-E7YTZNPT-9bnryna3.js.gz +0 -0
  157. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BKuuaF2s.js → quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js} +1 -1
  158. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BKuuaF2s.js.br → quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.br} +0 -0
  159. package/dist/client/assets/quadrantDiagram-AXDQQJYC-ZBmgIpsJ.js.gz +0 -0
  160. package/dist/client/assets/{railroadDiagram-O6MQD6OU-BwfCW2bp.js → railroadDiagram-O6MQD6OU-DTtXvKOu.js} +1 -1
  161. package/dist/client/assets/railroadDiagram-O6MQD6OU-DTtXvKOu.js.br +0 -0
  162. package/dist/client/assets/railroadDiagram-O6MQD6OU-DTtXvKOu.js.gz +0 -0
  163. package/dist/client/assets/rdpSession-Ggo3N5s5.js +1 -0
  164. package/dist/client/assets/rdpSession-Ggo3N5s5.js.br +0 -0
  165. package/dist/client/assets/rdpSession-Ggo3N5s5.js.gz +0 -0
  166. package/dist/client/assets/referenceLongPress-Df8W2cyP.js +1 -0
  167. package/dist/client/assets/referenceLongPress-Df8W2cyP.js.br +0 -0
  168. package/dist/client/assets/referenceLongPress-Df8W2cyP.js.gz +0 -0
  169. package/dist/client/assets/{requirementDiagram-BXWQKSXE-DbpU9Uig.js → requirementDiagram-BXWQKSXE-BNia9zI0.js} +1 -1
  170. package/dist/client/assets/requirementDiagram-BXWQKSXE-BNia9zI0.js.br +0 -0
  171. package/dist/client/assets/requirementDiagram-BXWQKSXE-BNia9zI0.js.gz +0 -0
  172. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-Bxa22XVM.js → sankeyDiagram-P5KCCOFB-uvg5npfK.js} +1 -1
  173. package/dist/client/assets/sankeyDiagram-P5KCCOFB-uvg5npfK.js.br +0 -0
  174. package/dist/client/assets/sankeyDiagram-P5KCCOFB-uvg5npfK.js.gz +0 -0
  175. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-C4GvzT9z.js → sequenceDiagram-WJ2MYXX4-DpJNf2MD.js} +1 -1
  176. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DpJNf2MD.js.br +0 -0
  177. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DpJNf2MD.js.gz +0 -0
  178. package/dist/client/assets/{sizeCapture-INFHLROL-B9zJJwQw.js → sizeCapture-INFHLROL-CkWB2AnF.js} +1 -1
  179. package/dist/client/assets/sizeCapture-INFHLROL-CkWB2AnF.js.br +0 -0
  180. package/dist/client/assets/sizeCapture-INFHLROL-CkWB2AnF.js.gz +0 -0
  181. package/dist/client/assets/{sparkles-BJbfT-v-.js → sparkles-DOuEtn62.js} +1 -1
  182. package/dist/client/assets/{stateDiagram-D77RDMKH-fqbw6LZa.js → stateDiagram-D77RDMKH-CeMzMQq-.js} +1 -1
  183. package/dist/client/assets/stateDiagram-D77RDMKH-CeMzMQq-.js.br +0 -0
  184. package/dist/client/assets/stateDiagram-D77RDMKH-CeMzMQq-.js.gz +0 -0
  185. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CNYUpLxt.js +1 -0
  186. package/dist/client/assets/{swimlanes-42K2YHIH-Hpc28YZY.js → swimlanes-42K2YHIH-Bo9GejWo.js} +1 -1
  187. package/dist/client/assets/swimlanes-42K2YHIH-Bo9GejWo.js.br +0 -0
  188. package/dist/client/assets/swimlanes-42K2YHIH-Bo9GejWo.js.gz +0 -0
  189. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-EB7zBRFR.js +8 -0
  190. package/dist/client/assets/{timeline-definition-24CTP7MA-qDieK7Re.js → timeline-definition-24CTP7MA-cvWXYEZ4.js} +1 -1
  191. package/dist/client/assets/timeline-definition-24CTP7MA-cvWXYEZ4.js.br +0 -0
  192. package/dist/client/assets/timeline-definition-24CTP7MA-cvWXYEZ4.js.gz +0 -0
  193. package/dist/client/assets/{triangle-alert-YOCAWhtT.js → triangle-alert-DzV0gQXz.js} +1 -1
  194. package/dist/client/assets/{vennDiagram-4TSXK5OY-BJpZlHao.js → vennDiagram-4TSXK5OY-CzleWcmk.js} +1 -1
  195. package/dist/client/assets/{vennDiagram-4TSXK5OY-BJpZlHao.js.br → vennDiagram-4TSXK5OY-CzleWcmk.js.br} +0 -0
  196. package/dist/client/assets/vennDiagram-4TSXK5OY-CzleWcmk.js.gz +0 -0
  197. package/dist/client/assets/{videoCompression-DI9vP0dm.js → videoCompression-DCnzjEfU.js} +1 -1
  198. package/dist/client/assets/videoCompression-DCnzjEfU.js.br +0 -0
  199. package/dist/client/assets/videoCompression-DCnzjEfU.js.gz +0 -0
  200. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-CQJfj6Ns.js → wardleyDiagram-VM6X3IG4-Cir1iutR.js} +1 -1
  201. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cir1iutR.js.br +0 -0
  202. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cir1iutR.js.gz +0 -0
  203. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-Cy-lkWBX.js → xychartDiagram-S5SC5T6Z-pNPcVJ1C.js} +1 -1
  204. package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.js.br +0 -0
  205. package/dist/client/assets/xychartDiagram-S5SC5T6Z-pNPcVJ1C.js.gz +0 -0
  206. package/dist/client/index.html +2 -2
  207. package/dist/client/index.html.br +0 -0
  208. package/dist/client/index.html.gz +0 -0
  209. package/dist/client/sw.js +1 -1
  210. package/dist/client/sw.js.br +0 -0
  211. package/dist/client/sw.js.gz +0 -0
  212. package/dist/server/agent/collaborationCli.js +56 -10
  213. package/dist/server/agent/collaborationGroupRoutes.js +10 -5
  214. package/dist/server/agent/collaborationLaunchProfiles.js +43 -0
  215. package/dist/server/agent/collaborationRoutes.js +6 -2
  216. package/dist/server/agent/collaborationService.js +8 -2
  217. package/dist/server/agent/collaborationStore.js +32 -1
  218. package/dist/server/agent/collaborationTaskCli.js +11 -3
  219. package/dist/server/agent/collaborationTaskService.js +16 -10
  220. package/dist/server/agent/collaborationTaskStore.js +70 -25
  221. package/dist/server/agent/collaborationTeam.js +3 -3
  222. package/dist/server/agent/integrationCli.js +243 -0
  223. package/dist/server/agent/integrationServer.js +331 -0
  224. package/dist/server/agent/integrationSessions.js +344 -0
  225. package/dist/server/agent/integrationStore.js +222 -0
  226. package/dist/server/cli.js +29 -0
  227. package/dist/server/entry.js +26 -7
  228. package/dist/server/routes/filesystem.js +120 -87
  229. package/dist/server/routes/terminal.js +196 -13
  230. package/dist/server/utils/localAccess.js +27 -7
  231. package/dist/server/utils/sessionDisplayName.js +53 -0
  232. package/docs/integrations.md +304 -0
  233. package/package.json +3 -2
  234. package/runtime-manifest.json +3 -3
  235. package/dist/client/assets/App-DzuUkEI_.js +0 -179
  236. package/dist/client/assets/App-DzuUkEI_.js.br +0 -0
  237. package/dist/client/assets/App-DzuUkEI_.js.gz +0 -0
  238. package/dist/client/assets/ArchitecturePanel-QodxiiCc.js +0 -7
  239. package/dist/client/assets/ArchitecturePanel-QodxiiCc.js.br +0 -0
  240. package/dist/client/assets/ArchitecturePanel-QodxiiCc.js.gz +0 -0
  241. package/dist/client/assets/ChangeWalkthroughPanel-2lXfrgk4.js.br +0 -0
  242. package/dist/client/assets/ChangeWalkthroughPanel-2lXfrgk4.js.gz +0 -0
  243. package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js +0 -1
  244. package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js.br +0 -0
  245. package/dist/client/assets/CollaborationMainWorkspace-05-Py9N8.js.gz +0 -0
  246. package/dist/client/assets/CollaborationTaskContent-BJe9TUtZ.js +0 -2
  247. package/dist/client/assets/ComputerControlView-B5vigCoW.js +0 -5
  248. package/dist/client/assets/ComputerControlView-B5vigCoW.js.br +0 -0
  249. package/dist/client/assets/ComputerControlView-B5vigCoW.js.gz +0 -0
  250. package/dist/client/assets/DagPlayground-EFUb9S3u.js.br +0 -0
  251. package/dist/client/assets/DagPlayground-EFUb9S3u.js.gz +0 -0
  252. package/dist/client/assets/DiffLab-CXWjSE2q.js.br +0 -0
  253. package/dist/client/assets/DiffLab-CXWjSE2q.js.gz +0 -0
  254. package/dist/client/assets/DiffReview-ByMkBaD9.js.br +0 -0
  255. package/dist/client/assets/DiffReview-ByMkBaD9.js.gz +0 -0
  256. package/dist/client/assets/DiffReviewLab-DoWaKm94.js.br +0 -0
  257. package/dist/client/assets/DiffReviewLab-DoWaKm94.js.gz +0 -0
  258. package/dist/client/assets/DiffViewer-B4hn9z0k.js.br +0 -0
  259. package/dist/client/assets/DiffViewer-B4hn9z0k.js.gz +0 -0
  260. package/dist/client/assets/ModelPreview-C-LJZ8so.js.br +0 -0
  261. package/dist/client/assets/ModelPreview-C-LJZ8so.js.gz +0 -0
  262. package/dist/client/assets/RightSidebar-EaMm4prW.js +0 -1678
  263. package/dist/client/assets/RightSidebar-EaMm4prW.js.br +0 -0
  264. package/dist/client/assets/RightSidebar-EaMm4prW.js.gz +0 -0
  265. package/dist/client/assets/abnfDiagram-VCTEODGH-BY-pfYKk.js.br +0 -0
  266. package/dist/client/assets/abnfDiagram-VCTEODGH-BY-pfYKk.js.gz +0 -0
  267. package/dist/client/assets/app-Ch0UDtJ-.js +0 -35
  268. package/dist/client/assets/app-Ch0UDtJ-.js.br +0 -0
  269. package/dist/client/assets/app-Ch0UDtJ-.js.gz +0 -0
  270. package/dist/client/assets/arc-DIENgCZn.js.br +0 -0
  271. package/dist/client/assets/arc-DIENgCZn.js.gz +0 -0
  272. package/dist/client/assets/architectureDiagram-5GKGNRK7-C1h4e4az.js.br +0 -0
  273. package/dist/client/assets/architectureDiagram-5GKGNRK7-C1h4e4az.js.gz +0 -0
  274. package/dist/client/assets/blockDiagram-I7D4REHJ-B_yOr54K.js.br +0 -0
  275. package/dist/client/assets/blockDiagram-I7D4REHJ-B_yOr54K.js.gz +0 -0
  276. package/dist/client/assets/c4Diagram-7LVT6UL2-DRD4zxIo.js.br +0 -0
  277. package/dist/client/assets/c4Diagram-7LVT6UL2-DRD4zxIo.js.gz +0 -0
  278. package/dist/client/assets/channel-MOXuUKM7.js +0 -1
  279. package/dist/client/assets/chunk-F27PBJKO-CQCL8mJG.js.br +0 -0
  280. package/dist/client/assets/chunk-F27PBJKO-CQCL8mJG.js.gz +0 -0
  281. package/dist/client/assets/chunk-IMKFNOWR-ruHGCADe.js.br +0 -0
  282. package/dist/client/assets/chunk-IMKFNOWR-ruHGCADe.js.gz +0 -0
  283. package/dist/client/assets/chunk-SVP7TREG-DMHj3NSq.js.br +0 -0
  284. package/dist/client/assets/chunk-SVP7TREG-DMHj3NSq.js.gz +0 -0
  285. package/dist/client/assets/chunk-TICWLB2K-Dh_ekvFW.js.br +0 -0
  286. package/dist/client/assets/chunk-TICWLB2K-Dh_ekvFW.js.gz +0 -0
  287. package/dist/client/assets/classDiagram-ZZMXUADV-CEXMdudw.js +0 -1
  288. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CEXMdudw.js +0 -1
  289. package/dist/client/assets/cose-bilkent-JH36ORCC-CsySWhYg.js.br +0 -0
  290. package/dist/client/assets/cose-bilkent-JH36ORCC-CsySWhYg.js.gz +0 -0
  291. package/dist/client/assets/cynefin-OW5HDTMX-9DKE5wV7.js.br +0 -0
  292. package/dist/client/assets/cynefin-OW5HDTMX-9DKE5wV7.js.gz +0 -0
  293. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B_8fvr9c.js.br +0 -0
  294. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B_8fvr9c.js.gz +0 -0
  295. package/dist/client/assets/dagre-GXQ25YYZ-BOdsFNFT.js.br +0 -0
  296. package/dist/client/assets/dagre-GXQ25YYZ-BOdsFNFT.js.gz +0 -0
  297. package/dist/client/assets/diagram-S7CK7UJ4-6v_qvAvi.js.br +0 -0
  298. package/dist/client/assets/diagram-S7CK7UJ4-6v_qvAvi.js.gz +0 -0
  299. package/dist/client/assets/diagram-UQ7AKVKN-c03oOGhD.js.br +0 -0
  300. package/dist/client/assets/diagram-UQ7AKVKN-c03oOGhD.js.gz +0 -0
  301. package/dist/client/assets/diagram-VSXAHHWV-MMIhRYp_.js.br +0 -0
  302. package/dist/client/assets/diagram-VSXAHHWV-MMIhRYp_.js.gz +0 -0
  303. package/dist/client/assets/diagram-VX7I27RA-B_l-uebl.js.br +0 -0
  304. package/dist/client/assets/diagram-VX7I27RA-B_l-uebl.js.gz +0 -0
  305. package/dist/client/assets/diagram-Z3DM3KII-DKoBC5gn.js.br +0 -0
  306. package/dist/client/assets/diagram-Z3DM3KII-DKoBC5gn.js.gz +0 -0
  307. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bs3wu8Az.js.br +0 -0
  308. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bs3wu8Az.js.gz +0 -0
  309. package/dist/client/assets/erDiagram-RLTQ6QDP-mYnHYbKl.js.br +0 -0
  310. package/dist/client/assets/erDiagram-RLTQ6QDP-mYnHYbKl.js.gz +0 -0
  311. package/dist/client/assets/flowDiagram-HODETNUW-CwCLWbib.js.br +0 -0
  312. package/dist/client/assets/flowDiagram-HODETNUW-CwCLWbib.js.gz +0 -0
  313. package/dist/client/assets/ganttDiagram-EL5Y4UJY-mse8c-ni.js.br +0 -0
  314. package/dist/client/assets/ganttDiagram-EL5Y4UJY-mse8c-ni.js.gz +0 -0
  315. package/dist/client/assets/gestureArbiter-BviL29ps.js.br +0 -0
  316. package/dist/client/assets/gestureArbiter-BviL29ps.js.gz +0 -0
  317. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVUfLjAX.js.br +0 -0
  318. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BVUfLjAX.js.gz +0 -0
  319. package/dist/client/assets/index-C6ftfFlG.css.br +0 -0
  320. package/dist/client/assets/index-C6ftfFlG.css.gz +0 -0
  321. package/dist/client/assets/ishikawaDiagram-5VMMS53U-bH299bWL.js.br +0 -0
  322. package/dist/client/assets/ishikawaDiagram-5VMMS53U-bH299bWL.js.gz +0 -0
  323. package/dist/client/assets/journeyDiagram-3NMN7TZE-BG0u_X1A.js.br +0 -0
  324. package/dist/client/assets/journeyDiagram-3NMN7TZE-BG0u_X1A.js.gz +0 -0
  325. package/dist/client/assets/kanban-definition-UXKFOSKX-DRoc9N-i.js.br +0 -0
  326. package/dist/client/assets/kanban-definition-UXKFOSKX-DRoc9N-i.js.gz +0 -0
  327. package/dist/client/assets/layout-mh0t6JpE.js.br +0 -0
  328. package/dist/client/assets/layout-mh0t6JpE.js.gz +0 -0
  329. package/dist/client/assets/linear-B9KTRuUV.js.br +0 -0
  330. package/dist/client/assets/linear-B9KTRuUV.js.gz +0 -0
  331. package/dist/client/assets/mermaid.core-Bu2G9zhK.js.br +0 -0
  332. package/dist/client/assets/mermaid.core-Bu2G9zhK.js.gz +0 -0
  333. package/dist/client/assets/mindmap-definition-YA3MSWOX-Go6Bg5xm.js.br +0 -0
  334. package/dist/client/assets/mindmap-definition-YA3MSWOX-Go6Bg5xm.js.gz +0 -0
  335. package/dist/client/assets/passwordBootstrap-C7-MUAHQ.js.br +0 -0
  336. package/dist/client/assets/passwordBootstrap-C7-MUAHQ.js.gz +0 -0
  337. package/dist/client/assets/pegDiagram-XKGWAZYB-DKUIl_U6.js.br +0 -0
  338. package/dist/client/assets/pegDiagram-XKGWAZYB-DKUIl_U6.js.gz +0 -0
  339. package/dist/client/assets/pieDiagram-E7YTZNPT-aoDNlV7J.js.br +0 -0
  340. package/dist/client/assets/pieDiagram-E7YTZNPT-aoDNlV7J.js.gz +0 -0
  341. package/dist/client/assets/quadrantDiagram-AXDQQJYC-BKuuaF2s.js.gz +0 -0
  342. package/dist/client/assets/railroadDiagram-O6MQD6OU-BwfCW2bp.js.br +0 -0
  343. package/dist/client/assets/railroadDiagram-O6MQD6OU-BwfCW2bp.js.gz +0 -0
  344. package/dist/client/assets/rdpSession--y6Q98uo.js +0 -1
  345. package/dist/client/assets/rdpSession--y6Q98uo.js.br +0 -0
  346. package/dist/client/assets/rdpSession--y6Q98uo.js.gz +0 -0
  347. package/dist/client/assets/referenceLongPress-BeG1PAdI.js +0 -1
  348. package/dist/client/assets/referenceLongPress-BeG1PAdI.js.br +0 -0
  349. package/dist/client/assets/referenceLongPress-BeG1PAdI.js.gz +0 -0
  350. package/dist/client/assets/requirementDiagram-BXWQKSXE-DbpU9Uig.js.br +0 -0
  351. package/dist/client/assets/requirementDiagram-BXWQKSXE-DbpU9Uig.js.gz +0 -0
  352. package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bxa22XVM.js.br +0 -0
  353. package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bxa22XVM.js.gz +0 -0
  354. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C4GvzT9z.js.br +0 -0
  355. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C4GvzT9z.js.gz +0 -0
  356. package/dist/client/assets/sizeCapture-INFHLROL-B9zJJwQw.js.br +0 -0
  357. package/dist/client/assets/sizeCapture-INFHLROL-B9zJJwQw.js.gz +0 -0
  358. package/dist/client/assets/stateDiagram-D77RDMKH-fqbw6LZa.js.br +0 -0
  359. package/dist/client/assets/stateDiagram-D77RDMKH-fqbw6LZa.js.gz +0 -0
  360. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BO23Pbrn.js +0 -1
  361. package/dist/client/assets/swimlanes-42K2YHIH-Hpc28YZY.js.br +0 -0
  362. package/dist/client/assets/swimlanes-42K2YHIH-Hpc28YZY.js.gz +0 -0
  363. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BLS7y4Di.js +0 -8
  364. package/dist/client/assets/timeline-definition-24CTP7MA-qDieK7Re.js.br +0 -0
  365. package/dist/client/assets/timeline-definition-24CTP7MA-qDieK7Re.js.gz +0 -0
  366. package/dist/client/assets/vennDiagram-4TSXK5OY-BJpZlHao.js.gz +0 -0
  367. package/dist/client/assets/videoCompression-DI9vP0dm.js.br +0 -0
  368. package/dist/client/assets/videoCompression-DI9vP0dm.js.gz +0 -0
  369. package/dist/client/assets/wardleyDiagram-VM6X3IG4-CQJfj6Ns.js.br +0 -0
  370. package/dist/client/assets/wardleyDiagram-VM6X3IG4-CQJfj6Ns.js.gz +0 -0
  371. package/dist/client/assets/xychartDiagram-S5SC5T6Z-Cy-lkWBX.js.br +0 -0
  372. package/dist/client/assets/xychartDiagram-S5SC5T6Z-Cy-lkWBX.js.gz +0 -0
@@ -83,7 +83,7 @@ function validateSnapshot(task) {
83
83
  invalid();
84
84
  if (event.deliveryId !== undefined && !validId(event.deliveryId))
85
85
  invalid();
86
- if (event.source !== undefined && !['system', 'user'].includes(event.source))
86
+ if (event.source !== undefined && !['system', 'user', 'integration'].includes(event.source))
87
87
  invalid();
88
88
  if (event.actor !== null)
89
89
  member(event.actor);
@@ -115,6 +115,9 @@ function validateSnapshot(task) {
115
115
  /** Atomic document writes keep decisions and their outgoing messages in one transaction. */
116
116
  export class CollaborationTaskStore {
117
117
  file;
118
+ listeners = new Set();
119
+ subscribe(listener) { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; }
120
+ snapshot() { return structuredClone(this.document.tasks); }
118
121
  document = { version: 1, tasks: [], outbox: [], requests: {} };
119
122
  constructor(file) {
120
123
  this.file = file;
@@ -129,9 +132,18 @@ export class CollaborationTaskStore {
129
132
  throw error;
130
133
  }
131
134
  }
132
- transaction(mutate) {
135
+ transaction(mutate, origin) {
133
136
  const next = structuredClone(this.document);
134
137
  const result = mutate(next);
138
+ if (origin) {
139
+ const previous = new Set(this.document.tasks.flatMap(t => t.events.map(e => e.id)));
140
+ for (const task of next.tasks)
141
+ for (const event of task.events)
142
+ if (!previous.has(event.id) && event.actor === null && event.source !== 'system') {
143
+ event.source = 'integration';
144
+ event.origin = structuredClone(origin);
145
+ }
146
+ }
135
147
  if (next.tasks.some(task => Buffer.byteLength(JSON.stringify(task)) > 512_000))
136
148
  throw new CollaborationError('TASK_HISTORY_LIMIT', '此任务记录达到 500 KiB,请建立后续任务并保留本任务为历史', 409);
137
149
  const serialized = JSON.stringify(next);
@@ -142,8 +154,18 @@ export class CollaborationTaskStore {
142
154
  writeFileSync(temporary, serialized, { mode: 0o600 });
143
155
  renameSync(temporary, this.file);
144
156
  this.document = next;
157
+ for (const listener of this.listeners) {
158
+ try {
159
+ listener();
160
+ }
161
+ catch { /* Durable sources allow the integration journal to retry. */ }
162
+ }
145
163
  return structuredClone(result);
146
164
  }
165
+ integrationRequestEvent(principalId, key, taskId) {
166
+ const request = this.document.requests[`integration:${principalId}:${key}`];
167
+ return request?.taskId === taskId ? structuredClone(this.document.tasks.find(t => t.id === taskId)?.events.find(e => e.id === request.eventId)) : undefined;
168
+ }
147
169
  get(taskId) { return structuredClone(this.document.tasks.find(t => t.id === taskId) ?? null); }
148
170
  owned(owner) { return structuredClone(this.document.tasks.filter(t => t.ownerServiceId === owner)); }
149
171
  children(taskId) {
@@ -166,7 +188,7 @@ export class CollaborationTaskStore {
166
188
  attempts: current ? [{ ...current, report: current.report ? { ...current.report, summary: reportSummary, content: '', evidence: undefined } : undefined }] : [],
167
189
  artifacts: [plan, result, ...task.artifacts.filter(a => a.kind === 'review' && a.reviewsArtifactId === result?.id)].filter((a) => !!a).map(a => ({ ...a, content: '', summary: (a.summary || (a.kind === 'result' && collaborationResultPresentation(a.content).condensed ? collaborationResultPresentation(a.content).summary : undefined))?.slice(0, 800), evidence: undefined })),
168
190
  decisions: task.decisions.filter(d => d.status === 'pending').map(d => ({ ...d, question: d.question.slice(0, 512), options: [] })),
169
- events: task.events.filter(e => ['revise', 'request-review'].includes(e.kind) && e.attemptId === task.activeAttemptId).slice(-4).map(e => ({ ...e, content: e.source === 'user' && e.kind === 'revise' ? e.content.slice(0, 512) : '' })) };
191
+ events: task.events.filter(e => ['revise', 'request-review'].includes(e.kind) && e.attemptId === task.activeAttemptId).slice(-4).map(e => ({ ...e, content: ['user', 'integration'].includes(e.source ?? '') && e.kind === 'revise' ? e.content.slice(0, 512) : '' })) };
170
192
  }));
171
193
  }
172
194
  heads(groupIds, owner) { return this.document.tasks.filter(t => groupIds.includes(t.groupId) && t.ownerServiceId === owner).map(t => ({ id: t.id, revision: t.revision })); }
@@ -179,11 +201,11 @@ export class CollaborationTaskStore {
179
201
  task.events.push(event);
180
202
  return event;
181
203
  }
182
- request(doc, actor, key, payload) {
204
+ request(doc, actor, key, payload, origin) {
183
205
  if (typeof key !== 'string' || !key.trim() || key.length > 256)
184
206
  throw new CollaborationError('INVALID_IDEMPOTENCY_KEY', '需要有效的请求幂等键');
185
- const scoped = `${actor ? taskMemberKey(actor) : 'user'}:${key}`;
186
- const hash = createHash('sha256').update(stable(payload)).digest('hex');
207
+ const scoped = `${origin ? `integration:${origin.integrationId}` : actor ? taskMemberKey(actor) : 'user'}:${key}`;
208
+ const hash = createHash('sha256').update(stable(origin ? [payload, origin] : payload)).digest('hex');
187
209
  const previous = doc.requests[scoped];
188
210
  if (previous && previous.hash !== hash)
189
211
  throw new CollaborationError('IDEMPOTENCY_CONFLICT', '该请求已用于不同内容;请保留原请求或重新开始', 409);
@@ -202,6 +224,9 @@ export class CollaborationTaskStore {
202
224
  content: `本次执行身份:${assignee.sessionId}。所有 td collab 命令显式带 --session ${assignee.sessionId};这是服务核对的实际身份,正文中的模板身份和 tmux 标识不能替代它。\n任务:${task.title}\n${task.spec}${task.constraints ? `\n约束:${task.constraints}` : ''}${task.acceptance ? `\n完成标准:${task.acceptance}` : ''}\n${content}\n任务 ID:${task.id}\n尝试 ID:${attemptId}\n用 td collab task get ${task.id} --text 查询完整上下文;用 td collab task report ${task.id} --attempt ${attemptId} --status ack --content '接手说明' 显式回复;遇必要问题用 task ask,提交结果用 report --status complete --summary '简短结论、关键交付和限制'。摘要先回答用户问题,不放任务 ID、版本、分支或流程日志;完整证据保留在 --content/--file 正文中。如果同一尝试已经交付或任务已归档,不要重复实施。${task.workspace ? `\n代码只能在独立目录 ${task.workspace.cwd} 修改。分支 ${task.workspace.branch}。交付前提交代码,结果说明提交、变更、验证与限制。不能修改原仓库、合并到用户分支或发布。` : ''}${task.workflow?.workType === 'read-only' ? '\n这是只读查询或分析任务:在本机会话中采集并交付报告,不修改代码或系统,不创建提交、构建、部署或终止进程。结果需说明采样时间、证据和限制。' : ''}${task.workflow?.kind === 'step' ? '\n完成报告会自动请求独立评审;评审要求修改时继续完成,重新提交 complete。只按用户授权运行测试。' : ''}` });
203
225
  }
204
226
  goalInstructions(task) {
227
+ return `${this.baseGoalInstructions(task)}\n启动 Agent 前,读取 task get 返回的 launchProfiles、defaultLaunchProfileId 和 roster.launchProfile。根据用户填写的 notes 判断适用任务;这些是选用建议,不是能力或性能保证。需要另一种模型或参数时,用 td collab spawn ${task.groupId} <agentSlug> --launch-profile <方案id> --cwd <项目目录> --session ${task.coordinator?.sessionId} 创建对应执行成员,再把子任务分派给它。已有成员及其代码执行会话保留创建时的启动方案,不因默认方案变更而更换模型。`;
228
+ }
229
+ baseGoalInstructions(task) {
205
230
  return `你是此目标的协调者,负责把目标推进到可验收交付,不亲自实施子任务。\n目标:${task.spec}\n约束:${task.constraints || '未补充'}\n完成标准:${task.acceptance || '满足用户目标,说明交付与限制'}\n任务 ID:${task.id}\n当前协调身份:${task.coordinator?.sessionId};所有命令显式带 --session ${task.coordinator?.sessionId},不使用 tmux 标识。\n用 td collab task get ${task.id} --json 读取 roster、子任务、完整记录和 revision。\n先报告 ack;拆分为可交付子任务,用 td collab task create --group ${task.groupId} --parent ${task.id} --title '标题' --content '完整要求' --assignee <roster里的成员sessionId> --acceptance '明确标准' --work-type read-only|code。先按目标明确分类:查询、检查、研究、分析用 read-only,复用现有执行成员会话,不创建 Git 目录;修改代码用 code,才创建独立目录。简单问题只建一个必要任务,不为了形式拆成采集、复述、汇总多份任务。子任务继承自动评审与协调者。依赖任务用 --depends-on id,id,服务在依赖评审通过后自动分派。保持分工合理,不根据终端输出推断谁有空。\n每次收到明确更新后读取最新记录,处理失败与交接。服务自动安排独立评审、返工和依赖接续;不要重复请求评审或催促正在等待回复的成员。必要的人类决策用 task ask --attempt <本轮id>;方案需要用户确认时提交 task plan,不把普通回复当授权。\n只有已交付代码任务实际包含相对 base 的提交变化时,才需创建 --work-type code --integration 的最终集成子任务,--depends-on 依赖全部代码实施任务;独立目录会包含依赖的提交。不得在原仓库自动合并或发布。\n结束本次协调用 td collab task coordinate ${task.id} --revision <最新版本> --content '已安排的工作和下一步';有新事件服务会再次唤起你。所有子任务评审通过后报告 complete --summary '直接回答用户的简短结果和限制';只读目标直接汇总已核对结果,不创建集成或重复汇总任务。正文保留证据、评审结论和限制,仅代码目标补充目录、分支和提交,等待用户最终验收。任何异常都要留下明确说明,不伪造完成或进度。`;
206
231
  }
207
232
  notifyCoordinator(doc, task, update) {
@@ -222,7 +247,7 @@ export class CollaborationTaskStore {
222
247
  doc.outbox.push({ id: id(), taskId: task.id, attemptId: attempt?.id ?? null, target: task.coordinator, kind: 'message', threadId: attempt?.threadId ?? task.id,
223
248
  content: `你被指定为任务「${task.title}」的协调者。\n目标:${task.spec}\n约束:${task.constraints || '未补充'}\n验收标准:${task.acceptance || '由用户决定'}\n任务 ID:${task.id}\n用 td collab task get ${task.id} --text 查看原始记录;用 task list --group ${task.groupId} 查看工作组。需要拆分时用 task create --group ${task.groupId} --parent ${task.id} --title '子任务标题' --content '任务内容'。分派前查询 revision,再用 task assign --revision;把必要的人类决策交给 task ask,不推断成员忙闲,不停止其他成员终端。` });
224
249
  }
225
- create(owner, input, actor) {
250
+ create(owner, input, actor, origin) {
226
251
  const title = text(input.title, '标题', 640, true), spec = text(input.spec, '任务内容', 32_000, true);
227
252
  const constraints = text(input.constraints, '约束'), acceptance = text(input.acceptance, '完成标准');
228
253
  if (input.dependsOn !== undefined && (!Array.isArray(input.dependsOn) || input.dependsOn.length > 32 || input.dependsOn.some(v => typeof v !== 'string')))
@@ -242,7 +267,7 @@ export class CollaborationTaskStore {
242
267
  throw new CollaborationError('INVALID_REVIEWERS', '评审成员列表无效');
243
268
  input.reviewers?.forEach(member);
244
269
  return this.transaction(doc => {
245
- const request = this.request(doc, actor, input.idempotencyKey, input);
270
+ const request = this.request(doc, actor, input.idempotencyKey, input, origin);
246
271
  if (request.previous)
247
272
  return request.previous;
248
273
  if (doc.tasks.length >= 2000)
@@ -285,7 +310,7 @@ export class CollaborationTaskStore {
285
310
  const task = { id: id(), ownerServiceId: owner, groupId: input.groupId, title, spec, constraints, acceptance,
286
311
  coordinator: parent?.workflow ? parent.coordinator : input.coordinator !== undefined ? input.coordinator : input.parentTaskId ? doc.tasks.find(t => t.id === input.parentTaskId)?.coordinator ?? actor : null,
287
312
  parentTaskId: input.parentTaskId ?? null, dependsOn, createdAt: now, updatedAt: now, revision: 1,
288
- status: 'open', activeAttemptId: null, attempts: [], decisions: [], artifacts: [], events: [], deliveries: [], ...(workflow ? { workflow } : {}) };
313
+ ...(origin ? { origin: structuredClone(origin) } : {}), status: 'open', activeAttemptId: null, attempts: [], decisions: [], artifacts: [], events: [], deliveries: [], ...(workflow ? { workflow } : {}) };
289
314
  this.event(task, 'created', actor, spec);
290
315
  if (parent?.constraints)
291
316
  task.constraints = text([parent.constraints, constraints].filter(Boolean).join('\n'), '继承约束');
@@ -307,9 +332,9 @@ export class CollaborationTaskStore {
307
332
  this.touchParent(doc, task, '新子任务已创建');
308
333
  doc.requests[request.key] = { hash: request.hash, taskId: task.id };
309
334
  return task;
310
- });
335
+ }, origin);
311
336
  }
312
- apply(taskId, input, actor) {
337
+ apply(taskId, input, actor, origin) {
313
338
  const content = text(input.content, '内容');
314
339
  const summary = text(input.summary, '结果摘要', 2400);
315
340
  if (summary && (input.kind !== 'report' || input.status !== 'complete'))
@@ -322,23 +347,25 @@ export class CollaborationTaskStore {
322
347
  const task = doc.tasks.find(t => t.id === taskId);
323
348
  if (!task)
324
349
  throw new CollaborationError('TASK_NOT_FOUND', '任务不存在或无权查看', 404);
325
- const request = this.request(doc, actor, input.idempotencyKey, [taskId, input]);
350
+ const request = this.request(doc, actor, input.idempotencyKey, [taskId, input], origin);
326
351
  if (request.previous)
327
352
  return request.previous;
353
+ if (origin && ['accept', 'approve-plan', 'report', 'ask', 'submit-plan', 'review', 'respond'].includes(input.kind))
354
+ throw new CollaborationError('INTEGRATION_OPERATION_DENIED', '此操作需要用户或原执行成员身份', 403);
328
355
  const coordination = actor === null || sameMember(actor, task.coordinator);
329
356
  if (['assign', 'coordinator', 'close', 'reopen', 'revise', 'request-review', 'coordinate', 'pause', 'resume', 'retry'].includes(input.kind) && !coordination)
330
357
  throw new CollaborationError('TASK_PERMISSION_DENIED', '此操作需要用户或当前协调者', 403);
331
358
  if (['answer', 'accept', 'approve-plan'].includes(input.kind) && actor !== null)
332
359
  throw new CollaborationError('USER_DECISION_REQUIRED', '回答、方案确认与验收需要用户操作', 403);
333
- if (!['report', 'ask', 'submit-plan', 'review', 'comment', 'answer'].includes(input.kind) && input.expectedRevision !== task.revision)
360
+ if (!['report', 'ask', 'submit-plan', 'review', 'comment', 'respond', 'answer'].includes(input.kind) && input.expectedRevision !== task.revision)
334
361
  throw new CollaborationError('TASK_CHANGED', '任务已更新,请查看最新记录后重试', 409);
335
362
  const userFollowup = actor === null && input.kind === 'revise' && !!content;
336
- if (task.status !== 'open' && !['reopen', 'report'].includes(input.kind) && !(task.status === 'accepted' && userFollowup))
363
+ if (task.status !== 'open' && !['reopen', 'report'].includes(input.kind) && !(task.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
337
364
  throw new CollaborationError('TASK_ARCHIVED', '任务已归档;需要继续时请重新打开', 409);
338
- if (task.workflow && task.status !== 'open' && input.kind !== 'reopen' && !(task.status === 'accepted' && userFollowup))
365
+ if (task.workflow && task.status !== 'open' && input.kind !== 'reopen' && !(task.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
339
366
  throw new CollaborationError('TASK_ARCHIVED', '自动协作的已完成版本不能追加执行报告,请先重新打开', 409);
340
367
  const root = task.workflow?.rootTaskId ? doc.tasks.find(t => t.id === task.workflow.rootTaskId) : undefined;
341
- if (root && root.status !== 'open' && !(root.status === 'accepted' && userFollowup))
368
+ if (root && root.status !== 'open' && !(root.status === 'accepted' && (userFollowup || ['comment', 'respond'].includes(input.kind))))
342
369
  throw new CollaborationError('GOAL_ARCHIVED', '请先重新打开所属目标,再继续子任务', 409);
343
370
  if (userFollowup && task.status === 'accepted') {
344
371
  task.status = 'open';
@@ -418,8 +445,26 @@ export class CollaborationTaskStore {
418
445
  const event = this.event(task, 'report', actor, content, attempt.id);
419
446
  event.reportStatus = input.status;
420
447
  event.evidence = input.evidence;
421
- if (input.status === 'complete')
422
- task.artifacts.push({ id: id(), attemptId: attempt.id, kind: 'result', content, ...(summary ? { summary } : {}), evidence: input.evidence, actor: actor, createdAt: event.createdAt });
448
+ if (input.status === 'complete' && attempt.id === task.activeAttemptId && task.status === 'accepted') {
449
+ task.status = 'open';
450
+ delete task.acceptedArtifactId;
451
+ delete task.completionMode;
452
+ }
453
+ if (input.status === 'complete') {
454
+ event.artifactId = id();
455
+ task.artifacts.push({ id: event.artifactId, attemptId: attempt.id, kind: 'result', content, ...(summary ? { summary } : {}), evidence: input.evidence, actor: actor, createdAt: event.createdAt });
456
+ }
457
+ }
458
+ else if (input.kind === 'respond') {
459
+ const original = task.events.find(e => e.id === input.replyToEventId && e.kind === 'comment');
460
+ const originalAttempt = original && task.attempts.find(a => a.id === original.attemptId);
461
+ if (!original || !originalAttempt || originalAttempt.id !== input.attemptId || !sameMember(actor, originalAttempt.assignee))
462
+ throw new CollaborationError('RESPONSE_PERMISSION_DENIED', '请由原追问对应的执行成员回复,并指定原事件和分派', 403);
463
+ if (!content)
464
+ throw new CollaborationError('INVALID_RESPONSE', '答复不能为空');
465
+ const response = this.event(task, 'respond', actor, content, originalAttempt.id);
466
+ response.replyToEventId = original.id;
467
+ response.evidence = input.evidence;
423
468
  }
424
469
  else if (input.kind === 'ask') {
425
470
  if (!content || input.options !== undefined && (!Array.isArray(input.options) || input.options.length > 8 || input.options.some(v => typeof v !== 'string' || !v.trim() || v.length > 500)))
@@ -439,7 +484,7 @@ export class CollaborationTaskStore {
439
484
  this.event(task, 'answer', null, content, decision.attemptId);
440
485
  const recipient = task.attempts.find(a => a.id === decision.attemptId);
441
486
  doc.outbox.push({ id: id(), taskId: task.id, attemptId: recipient.id, target: recipient.assignee, kind: 'message', threadId: recipient.threadId,
442
- content: `任务「${task.title}」问题已回答\n问题:${decision.question}\n用户回答:${content}\n任务 ID:${task.id}\n尝试 ID:${recipient.id}` });
487
+ content: `任务「${task.title}」问题已回答\n问题:${decision.question}\n${origin ? '外部接入回答' : '用户回答'}:${content}\n任务 ID:${task.id}\n尝试 ID:${recipient.id}` });
443
488
  }
444
489
  else if (input.kind === 'submit-plan' || input.kind === 'review') {
445
490
  if (!content || !actor)
@@ -519,7 +564,7 @@ export class CollaborationTaskStore {
519
564
  event.target = recipient.assignee;
520
565
  event.deliveryId = id();
521
566
  doc.outbox.push({ id: event.deliveryId, taskId: task.id, attemptId: recipient.id, target: recipient.assignee,
522
- kind: 'message', threadId: recipient.threadId, content: `任务「${task.title}」${input.kind === 'revise' ? actor === null ? '用户要求继续跟进' : '修改要求' : '补充反馈'}:\n${content}\n任务 ID:${task.id}\n尝试 ID:${recipient.id}${task.workflow?.kind === 'goal' ? `\n本轮继续沿用此目标和已交付证据,只推进新增要求。\n${this.goalInstructions(task)}` : '\n按这次要求继续当前分派,重新提交 complete 和摘要;新版本会重新独立评审。'}` });
567
+ kind: 'message', threadId: recipient.threadId, replyToEventId: event.id, content: `任务「${task.title}」${input.kind === 'revise' ? actor === null ? origin ? '外部接入要求继续跟进' : '用户要求继续跟进' : '修改要求' : '补充反馈'}:\n${content}\n任务 ID:${task.id}\n尝试 ID:${recipient.id}${input.kind === 'comment' ? `\n这是纯咨询,保留当前结果与验收。请用 td collab --session ${recipient.assignee.sessionId} task respond ${task.id} --attempt ${recipient.id} --to-event ${event.id} --content '答复' 关联回复;只有明确提交新的交付物才用 complete。` : task.workflow?.kind === 'goal' ? `\n本轮继续沿用此目标和已交付证据,只推进新增要求。\n${this.goalInstructions(task)}` : '\n按这次要求继续当前分派,重新提交 complete 和摘要;新版本会重新独立评审。'}` });
523
568
  if (task.workflow?.kind === 'goal' && task.coordination) {
524
569
  task.coordination.notifiedSequence = event.sequence;
525
570
  task.coordination.notifiedAt = Date.now();
@@ -584,21 +629,21 @@ export class CollaborationTaskStore {
584
629
  }
585
630
  else
586
631
  throw new CollaborationError('INVALID_TASK_OPERATION', '不支持的任务操作');
587
- if (['report', 'ask', 'answer', 'submit-plan', 'review', 'accept', 'revise', 'close', 'reopen'].includes(input.kind))
632
+ if (['report', 'respond', 'ask', 'answer', 'submit-plan', 'review', 'accept', 'revise', 'close', 'reopen'].includes(input.kind))
588
633
  this.notifyCoordinator(doc, task, task.events.at(-1));
589
634
  if (task.events.length > 1000 || task.artifacts.length > 200 || task.attempts.length > 100)
590
635
  throw new CollaborationError('TASK_HISTORY_LIMIT', '此任务历史达到上限,请建立后续任务并保留本任务为历史', 409);
591
636
  task.revision++;
592
637
  task.updatedAt = Math.max(Date.now(), task.updatedAt + 1);
593
- if (task.workflow && input.kind !== 'coordinate')
638
+ if (task.workflow && !['coordinate', 'comment', 'respond'].includes(input.kind))
594
639
  this.touchParent(doc, task, `${input.kind}${input.status ? ` / ${input.status}` : ''}:${content.slice(0, 1500)}`);
595
640
  if (task.workflow && ['blocked', 'failed'].includes(input.status ?? ''))
596
641
  task.automationIssue = content.slice(0, 1000);
597
642
  if (task.workflow && input.kind === 'report' && ['ack', 'working', 'complete'].includes(input.status ?? ''))
598
643
  delete task.automationIssue;
599
- doc.requests[request.key] = { hash: request.hash, taskId };
644
+ doc.requests[request.key] = { hash: request.hash, taskId, eventId: task.events.at(-1)?.id };
600
645
  return task;
601
- });
646
+ }, origin);
602
647
  }
603
648
  touchParent(doc, task, content) {
604
649
  const root = task.workflow?.rootTaskId ? doc.tasks.find(t => t.id === task.workflow.rootTaskId) : undefined;
@@ -717,7 +762,7 @@ export class CollaborationTaskStore {
717
762
  this.touchParent(doc, task, '独立评审通过,后续依赖可以接续');
718
763
  }
719
764
  else if (action === 'review-feedback') {
720
- const boundary = task.events.filter(e => e.kind === 'revise' && e.source === 'user' && e.attemptId === task.activeAttemptId).at(-1)?.sequence ?? 0;
765
+ const boundary = task.events.filter(e => e.kind === 'revise' && ['user', 'integration'].includes(e.source ?? '') && e.attemptId === task.activeAttemptId).at(-1)?.sequence ?? 0;
721
766
  const rounds = task.events.filter(e => e.kind === 'revise' && e.actor === null && e.artifactId && e.attemptId === task.activeAttemptId && e.sequence > boundary).length;
722
767
  const blocked = review.verdict === 'blocked' || rounds >= task.workflow.maxRevisions;
723
768
  const event = this.event(task, blocked ? 'review-blocked' : 'revise', null, review.content);
@@ -6,10 +6,10 @@ export async function ensureTeam(options) {
6
6
  for (const role of labels) {
7
7
  const members = options.members();
8
8
  const reserved = members.find(member => member.role?.startsWith(role.split(' (')[0]));
9
- if (reserved && (reserved.role !== role || reserved.cwd !== options.cwd)) {
10
- throw new Error('本组已有自动配置的成员,请使用原 Agent 和目录,或在成员设置中移出后重新配置');
9
+ if (reserved && (reserved.role !== role || reserved.cwd !== options.cwd || (reserved.launchProfileKey ?? '') !== (options.launchProfileKey ?? ''))) {
10
+ throw new Error('本组已有自动配置的成员,请使用原 Agent、启动方案和目录,或在成员设置中移出后重新配置');
11
11
  }
12
- const existing = reserved ?? members.find(member => !ids.includes(member.id) && member.agentSlug === options.agentSlug && member.cwd === options.cwd);
12
+ const existing = reserved ?? members.find(member => !ids.includes(member.id) && member.agentSlug === options.agentSlug && member.cwd === options.cwd && (member.launchProfileKey ?? '') === (options.launchProfileKey ?? ''));
13
13
  ids.push(existing?.id ?? await options.spawn(role));
14
14
  }
15
15
  return { coordinatorSessionId: ids[0], reviewerSessionIds: [ids[1]] };
@@ -0,0 +1,243 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import http from 'node:http';
4
+ import { INTEGRATION_PROTOCOL } from './integrationStore.js';
5
+ import { integrationSocketPath } from './integrationServer.js';
6
+ import { CollaborationError } from './collaborationProtocol.js';
7
+ import { executeCollaborationCommand, duration } from './collaborationCli.js';
8
+ import { getTermdockVersion } from '../utils/version.js';
9
+ export const INTEGRATION_HELP = `td integration — local scoped integration administration
10
+ groups | list
11
+ create --file <policy.json> --credential-file <private-output.json>
12
+ update --file <policy.json> (same identity/group; preserves the credential)
13
+ revoke <principal-id>
14
+ Credentials are saved as a private file and never printed. Workers set
15
+ TERMDOCK_INTEGRATION_CREDENTIAL_FILE, then use td collab --principal <id> …
16
+ Only the local administrator can provision/revoke grants. See docs/integrations.md.`;
17
+ export function readIntegrationCredential(file, principalId) {
18
+ const info = fs.lstatSync(file);
19
+ if (!info.isFile() || info.size > 4096 || (info.mode & 0o077) || process.getuid && info.uid !== process.getuid())
20
+ throw new CollaborationError('INTEGRATION_CREDENTIAL_FILE_DENIED', 'Credential file must be owned by this user and private (0600)', 403);
21
+ const credential = JSON.parse(fs.readFileSync(file, 'utf8'));
22
+ if (credential.id !== principalId || !credential.token || credential.protocol !== INTEGRATION_PROTOCOL)
23
+ throw new CollaborationError('INTEGRATION_CREDENTIAL_MISMATCH', 'Credential identity/protocol does not match the requested principal', 403);
24
+ return credential;
25
+ }
26
+ function headers(credential, adminToken) {
27
+ return { 'Content-Type': 'application/json', 'x-termdock-integration-protocol': String(INTEGRATION_PROTOCOL),
28
+ 'x-termdock-cli-version': getTermdockVersion(),
29
+ ...(credential ? { 'x-termdock-integration-id': credential.id, authorization: `Bearer ${credential.token}` } : {}),
30
+ ...(adminToken ? { 'x-termdock-local-token': adminToken } : {}) };
31
+ }
32
+ function request(socketPath, method, route, body, requestHeaders, timeout = 30000) {
33
+ return new Promise((resolve, reject) => {
34
+ const req = http.request({ socketPath, method, path: route, headers: requestHeaders }, res => {
35
+ let raw = '';
36
+ res.setEncoding('utf8');
37
+ res.on('data', chunk => { raw += chunk; if (raw.length > 4 * 1024 * 1024)
38
+ req.destroy(new Error('Integration response exceeds limit')); });
39
+ res.once('end', () => resolve({ statusCode: res.statusCode ?? 500, body: raw }));
40
+ res.once('error', reject);
41
+ });
42
+ req.setTimeout(timeout, () => req.destroy(new Error('Integration request timed out')));
43
+ req.once('error', reject);
44
+ req.end(body === undefined ? undefined : JSON.stringify(body));
45
+ });
46
+ }
47
+ function parsed(response) {
48
+ const result = JSON.parse(response.body);
49
+ if (response.statusCode >= 300)
50
+ throw new CollaborationError(result.code ?? 'INTEGRATION_REQUEST_FAILED', result.error ?? 'Integration request failed', response.statusCode);
51
+ return result;
52
+ }
53
+ export async function runIntegrationAdmin(argv, port, adminToken, write) {
54
+ let reserved;
55
+ try {
56
+ const action = argv[0] ?? 'help', options = {};
57
+ if (action === 'help' || action === '--help') {
58
+ write(INTEGRATION_HELP);
59
+ return 0;
60
+ }
61
+ for (let index = 1; index < argv.length; index += 2) {
62
+ const flag = argv[index];
63
+ if (!['--file', '--credential-file'].includes(flag) || !argv[index + 1] || options[flag])
64
+ throw new Error('Invalid integration arguments');
65
+ options[flag] = argv[index + 1];
66
+ }
67
+ const socketPath = integrationSocketPath(port);
68
+ if (action === 'groups' || action === 'list') {
69
+ if (argv.length !== 1)
70
+ throw new Error('Unexpected arguments');
71
+ write(JSON.stringify(parsed(await request(socketPath, 'GET', action === 'groups' ? '/admin/groups' : '/admin/principals', undefined, headers(undefined, adminToken)))));
72
+ return 0;
73
+ }
74
+ if (action === 'update') {
75
+ if (!options['--file'] || Object.keys(options).length !== 1)
76
+ throw new Error('update requires only --file');
77
+ const policy = JSON.parse(fs.readFileSync(options['--file'], 'utf8'));
78
+ const capabilities = parsed(await request(socketPath, 'GET', '/admin/capabilities', undefined, headers(undefined, adminToken)));
79
+ if (capabilities.integration_policy_update !== true || policy.launchProfiles?.some((profile) => profile.startupInput !== undefined) && capabilities.startup_input_conditions !== true)
80
+ throw new CollaborationError('STARTUP_INPUT_CONDITION_UNSUPPORTED', 'Running service does not support this policy update', 409);
81
+ write(JSON.stringify(parsed(await request(socketPath, 'POST', `/admin/principals/${encodeURIComponent(policy.id)}/policy`, policy, headers(undefined, adminToken)))));
82
+ return 0;
83
+ }
84
+ if (action === 'create') {
85
+ if (!options['--file'] || !options['--credential-file'] || Object.keys(options).length !== 2)
86
+ throw new Error('create requires --file and --credential-file');
87
+ const policy = JSON.parse(fs.readFileSync(options['--file'], 'utf8'));
88
+ if (policy.launchProfiles?.some((profile) => profile.startupInput !== undefined)) {
89
+ const capabilities = parsed(await request(socketPath, 'GET', '/admin/capabilities', undefined, headers(undefined, adminToken)));
90
+ if (capabilities.startup_input_conditions !== true)
91
+ throw new CollaborationError('STARTUP_INPUT_CONDITION_UNSUPPORTED', 'Running service does not support startup input conditions', 409);
92
+ }
93
+ const destination = path.resolve(options['--credential-file']);
94
+ fs.mkdirSync(path.dirname(destination), { recursive: true, mode: 0o700 });
95
+ fs.closeSync(fs.openSync(destination, 'wx', 0o600));
96
+ reserved = destination;
97
+ const credential = parsed(await request(socketPath, 'POST', '/admin/principals', policy, headers(undefined, adminToken)));
98
+ fs.writeFileSync(reserved, JSON.stringify(credential), { mode: 0o600 });
99
+ write(JSON.stringify({ ok: true, id: credential.id, credential_file: reserved }));
100
+ reserved = undefined;
101
+ return 0;
102
+ }
103
+ throw new Error('Unknown integration operation');
104
+ }
105
+ catch (error) {
106
+ if (reserved)
107
+ fs.unlinkSync(reserved);
108
+ write(JSON.stringify({ ok: false, code: error instanceof CollaborationError ? error.code : 'INTEGRATION_ADMIN_ERROR', error: error instanceof CollaborationError ? error.message : 'Integration administration failed; inspect arguments and private file paths' }));
109
+ return 1;
110
+ }
111
+ }
112
+ export async function revokeIntegration(id, port, adminToken, write) {
113
+ try {
114
+ write(JSON.stringify(parsed(await request(integrationSocketPath(port), 'POST', `/admin/principals/${encodeURIComponent(id)}/revoke`, {}, headers(undefined, adminToken)))));
115
+ return 0;
116
+ }
117
+ catch (error) {
118
+ write(JSON.stringify({ ok: false, code: error instanceof CollaborationError ? error.code : 'INTEGRATION_ADMIN_ERROR', error: error instanceof CollaborationError ? error.message : 'Integration revocation failed' }));
119
+ return 1;
120
+ }
121
+ }
122
+ export async function runIntegrationCollab(command, port, io) {
123
+ try {
124
+ const principalId = String(command.options.principal), file = process.env.TERMDOCK_INTEGRATION_CREDENTIAL_FILE;
125
+ if (!file)
126
+ throw new CollaborationError('INTEGRATION_CREDENTIAL_REQUIRED', 'Set TERMDOCK_INTEGRATION_CREDENTIAL_FILE to a private credential file', 401);
127
+ const credential = readIntegrationCredential(file, principalId), socketPath = integrationSocketPath(port);
128
+ const capability = parsed(await request(socketPath, 'GET', '/capabilities', undefined, headers(credential)));
129
+ if (capability.integration_protocol !== INTEGRATION_PROTOCOL)
130
+ throw new CollaborationError('INCOMPATIBLE_INTEGRATION_PROTOCOL', 'CLI/service protocols are incompatible', 409);
131
+ if (command.action === 'capabilities') {
132
+ io.write(JSON.stringify({ ...capability, cli_version: getTermdockVersion() }));
133
+ return 0;
134
+ }
135
+ if (command.action === 'events') {
136
+ const consumer = String(command.options.consumer ?? 'default');
137
+ if (command.operation === 'ack') {
138
+ io.write(JSON.stringify(parsed(await request(socketPath, 'POST', '/events/ack', { consumer, cursor: command.target }, headers(credential)))));
139
+ return 0;
140
+ }
141
+ const params = new URLSearchParams({ consumer });
142
+ if (command.options.group)
143
+ params.set('group', String(command.options.group));
144
+ return subscribe(socketPath, `/events?${params}`, credential, command.options.timeout ? duration(String(command.options.timeout)) : undefined, io.write);
145
+ }
146
+ if (command.action === 'session') {
147
+ const route = command.operation === 'create' ? '/sessions' : `/sessions/${encodeURIComponent(command.target)}${command.operation === 'restore' ? '/restore' : ''}`;
148
+ const body = command.operation === 'create' ? { group_id: command.options.group, launch_profile: command.options['launch-profile'], cwd: command.options.cwd, idempotency_key: command.options['idempotency-key'] }
149
+ : command.operation === 'restore' ? { idempotency_key: command.options['idempotency-key'] } : undefined;
150
+ io.write(JSON.stringify(parsed(await request(socketPath, command.operation === 'get' ? 'GET' : 'POST', route, body, headers(credential)))));
151
+ return 0;
152
+ }
153
+ if (!['task', 'message', 'help'].includes(command.action) || command.action === 'message' && command.operation !== 'get')
154
+ throw new CollaborationError('INTEGRATION_OPERATION_DENIED', 'Command is not exposed to integration identities', 403);
155
+ return executeCollaborationCommand(command, {}, { ...io, request: async (method, endpoint, body, timeout) => {
156
+ const origin = { source: command.options.source, externalActor: command.options['external-actor'] ? JSON.parse(String(command.options['external-actor'])) : undefined,
157
+ externalMessageId: command.options['external-message-id'], metadata: command.options.metadata ? JSON.parse(String(command.options.metadata)) : undefined };
158
+ return request(socketPath, method, endpoint.replace('/api/terminal/operations/orchestration', ''), body === undefined ? undefined : { ...body, origin }, headers(credential), timeout);
159
+ } });
160
+ }
161
+ catch (error) {
162
+ io.write(JSON.stringify({ ok: false, code: error instanceof CollaborationError ? error.code : 'INTEGRATION_CONNECTION_FAILED', error: error instanceof CollaborationError ? error.message : 'Local integration connection failed; credentials were not sent to a public service' }));
163
+ return 1;
164
+ }
165
+ }
166
+ async function subscribe(socketPath, route, credential, timeout, write) {
167
+ const deadline = timeout ? Date.now() + timeout : Infinity;
168
+ let backoff = 1000;
169
+ while (Date.now() < deadline) {
170
+ const outcome = await new Promise(resolve => {
171
+ let timer;
172
+ const req = http.request({ socketPath, method: 'GET', path: route, headers: headers(credential) }, res => {
173
+ res.setEncoding('utf8');
174
+ let pending = '', ended = false;
175
+ res.on('data', chunk => {
176
+ pending += chunk;
177
+ if (pending.length > 2 * 1024 * 1024) {
178
+ ended = true;
179
+ req.destroy();
180
+ resolve('stop');
181
+ return;
182
+ }
183
+ for (;;) {
184
+ const newline = pending.indexOf('\n');
185
+ if (newline < 0)
186
+ break;
187
+ const line = pending.slice(0, newline);
188
+ pending = pending.slice(newline + 1);
189
+ if (!line.trim())
190
+ continue;
191
+ let event;
192
+ try {
193
+ event = JSON.parse(line);
194
+ }
195
+ catch {
196
+ write(JSON.stringify({ type: 'error', code: 'INVALID_EVENT_RESPONSE', retryable: false }));
197
+ ended = true;
198
+ req.destroy();
199
+ resolve('stop');
200
+ return;
201
+ }
202
+ write(line);
203
+ if (event.type === 'error' && !event.retryable) {
204
+ ended = true;
205
+ req.destroy();
206
+ resolve('stop');
207
+ }
208
+ }
209
+ });
210
+ res.once('end', () => {
211
+ if ((res.statusCode ?? 500) >= 300 && pending) {
212
+ try {
213
+ const error = JSON.parse(pending);
214
+ write(JSON.stringify(error));
215
+ }
216
+ catch {
217
+ write(JSON.stringify({ type: 'error', code: 'INVALID_EVENT_RESPONSE', retryable: false }));
218
+ }
219
+ resolve((res.statusCode ?? 500) >= 500 ? 'retry' : 'stop');
220
+ }
221
+ else if (!ended)
222
+ resolve('retry');
223
+ });
224
+ res.once('close', () => { if (!ended)
225
+ resolve('retry'); });
226
+ });
227
+ req.once('error', () => resolve('retry'));
228
+ req.once('close', () => { if (timer)
229
+ clearTimeout(timer); });
230
+ if (Number.isFinite(deadline))
231
+ timer = setTimeout(() => { resolve('timeout'); req.destroy(); }, Math.max(1, deadline - Date.now()));
232
+ req.end();
233
+ });
234
+ if (outcome === 'stop')
235
+ return 1;
236
+ if (outcome === 'timeout')
237
+ return 0;
238
+ write(JSON.stringify({ type: 'connection', state: 'reconnecting', retry_in_ms: backoff }));
239
+ await new Promise(resolve => setTimeout(resolve, Math.min(backoff, Math.max(0, deadline - Date.now()))));
240
+ backoff = Math.min(backoff * 2, 30000);
241
+ }
242
+ return 0;
243
+ }