agentworkshop 0.7.6 → 0.7.7

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 (517) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +1 -1
  2. package/.output/.AgentWorkShop/prompts/host-tools.json +1 -1
  3. package/.output/nitro.json +1 -1
  4. package/.output/public/_nuxt/{rzGB_ojX.js → 3612gD2V.js} +2 -2
  5. package/.output/public/_nuxt/8eIQAVlb.js +1 -0
  6. package/.output/public/_nuxt/Ah9qOv1m.js +1 -0
  7. package/.output/public/_nuxt/{DdPeifHR.js → B4Fia4FB.js} +1 -1
  8. package/.output/public/_nuxt/B7aqqzkY.js +1 -0
  9. package/.output/public/_nuxt/BJ-fxrSw.js +1 -0
  10. package/.output/public/_nuxt/{DPDqAD1e.js → BSXx2vqR.js} +1 -1
  11. package/.output/public/_nuxt/{CdSgfcYR.js → BVZjSVs2.js} +1 -1
  12. package/.output/public/_nuxt/{DP6bdyIp.js → BVzDoF8t.js} +1 -1
  13. package/.output/public/_nuxt/BYL0Rjqj.js +7 -0
  14. package/.output/public/_nuxt/{CXmkVXS5.js → BjVLsC3M.js} +1 -1
  15. package/.output/public/_nuxt/{7ZABjMRh2.js → BkfchkK62.js} +1 -1
  16. package/.output/public/_nuxt/BnVoQ74r.js +1 -0
  17. package/.output/public/_nuxt/Bnp4vIAf.js +1 -0
  18. package/.output/public/_nuxt/BsMpJf7S.js +70 -0
  19. package/.output/public/_nuxt/{Z8k0uMSI.js → Bt_HDizI.js} +1 -1
  20. package/.output/public/_nuxt/Bu-P92Pe.js +18 -0
  21. package/.output/public/_nuxt/ButLXkjo.js +2 -0
  22. package/.output/public/_nuxt/C-GarxYC.js +1 -0
  23. package/.output/public/_nuxt/{D8DDDzV62.js → C2iWjzEC2.js} +1 -1
  24. package/.output/public/_nuxt/{HWXLx5Hz.js → C8dxXc6K.js} +5 -5
  25. package/.output/public/_nuxt/CGdPdJPP.js +1 -0
  26. package/.output/public/_nuxt/{CyygA0q4.js → CQiKcuoG.js} +4 -4
  27. package/.output/public/_nuxt/{CN7Zh8GQ.js → CRGlf1Gb.js} +1 -1
  28. package/.output/public/_nuxt/{DSBfvCi5.js → CblLEiCZ.js} +7 -7
  29. package/.output/public/_nuxt/Cd15nPnG2.js +1 -0
  30. package/.output/public/_nuxt/{OwJ1LJkF.js → CsCpu2Zh.js} +1 -1
  31. package/.output/public/_nuxt/CvbHIGQY2.js +1 -0
  32. package/.output/public/_nuxt/Cyk3du4K2.js +1 -0
  33. package/.output/public/_nuxt/{DVQAz9WI.js → D4qXvjuV.js} +2 -2
  34. package/.output/public/_nuxt/{CfIXY-ET.js → DCEyMaN-.js} +1 -1
  35. package/.output/public/_nuxt/{BFYNhG9S.js → DCXIGxzT.js} +1 -1
  36. package/.output/public/_nuxt/{B9aPoQvt.js → DM8DS9MA.js} +1 -1
  37. package/.output/public/_nuxt/{ChnfyQHz.js → DNzaswei.js} +1 -1
  38. package/.output/public/_nuxt/{CrFGZYVB2.js → DYZBdSSg2.js} +1 -1
  39. package/.output/public/_nuxt/{dObsRdSQ.js → DZk24ego.js} +1 -1
  40. package/.output/public/_nuxt/DeYsUzhr.js +1 -0
  41. package/.output/public/_nuxt/Dk6pq9JB2.js +1 -0
  42. package/.output/public/_nuxt/{ByGNWgAr.js → Do88WZG2.js} +3 -3
  43. package/.output/public/_nuxt/{R_WxTozV2.js → Du-eSpo2.js} +1 -1
  44. package/.output/public/_nuxt/OmpTerminalPanel.B_Pl5Ynm.css +1 -0
  45. package/.output/public/_nuxt/{Bsc69G4x.js → VnIWJ0ts.js} +3 -3
  46. package/.output/public/_nuxt/_id_.BzKMZnLe.css +1 -0
  47. package/.output/public/_nuxt/_id_.CbpDAWRh.css +1 -0
  48. package/.output/public/_nuxt/{_wsId_.DET_GinP.css → _wsId_.COUzMXpP.css} +1 -1
  49. package/.output/public/_nuxt/agents.BlejnOOC.css +1 -0
  50. package/.output/public/_nuxt/builds/latest.json +1 -1
  51. package/.output/public/_nuxt/builds/meta/14df171d-89cb-43ec-ad6f-9df72d6da7f5.json +1 -0
  52. package/.output/public/_nuxt/daq.zZ8GR433.css +1 -0
  53. package/.output/public/_nuxt/{default.D17kXlD6.css → default.V3_hUJq1.css} +1 -1
  54. package/.output/public/_nuxt/{B4GHHF6d2.js → fQUs58kX2.js} +1 -1
  55. package/.output/public/_nuxt/p7wSGMtc.js +1 -0
  56. package/.output/public/_nuxt/tRBT-plo.js +1 -0
  57. package/.output/server/chunks/_/SearchOutlined.mjs +4 -4
  58. package/.output/server/chunks/_/SearchOutlined.mjs.map +1 -1
  59. package/.output/server/chunks/_/character-asset.repo.mjs +3 -6
  60. package/.output/server/chunks/_/character-asset.repo.mjs.map +1 -1
  61. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  62. package/.output/server/chunks/_/nitro.mjs +4967 -2035
  63. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  64. package/.output/server/chunks/_/scene-layout.repo.mjs +4 -10
  65. package/.output/server/chunks/_/scene-layout.repo.mjs.map +1 -1
  66. package/.output/server/chunks/build/{Col-D7fjGDF6.mjs → Col-biaNnEPf.mjs} +2 -2
  67. package/.output/server/chunks/build/{Col-D7fjGDF6.mjs.map → Col-biaNnEPf.mjs.map} +1 -1
  68. package/.output/server/chunks/build/{OmpTerminalPanel-B_SYhmgb.mjs → OmpTerminalPanel-COphA1br.mjs} +20 -19
  69. package/.output/server/chunks/build/OmpTerminalPanel-COphA1br.mjs.map +1 -0
  70. package/.output/server/chunks/build/{TownView-Bl8Gkcxi.mjs → TownView-B5KifIaT.mjs} +4 -4
  71. package/.output/server/chunks/build/{TownView-Bl8Gkcxi.mjs.map → TownView-B5KifIaT.mjs.map} +1 -1
  72. package/.output/server/chunks/build/{_id_-GnRJPykX.mjs → _id_-C-ewLgfl.mjs} +119 -119
  73. package/.output/server/chunks/build/{_id_-GnRJPykX.mjs.map → _id_-C-ewLgfl.mjs.map} +1 -1
  74. package/.output/server/chunks/build/{_id_-CWLFGZjV.mjs → _id_-Ct4Jhvl1.mjs} +42 -38
  75. package/.output/server/chunks/build/_id_-Ct4Jhvl1.mjs.map +1 -0
  76. package/.output/server/chunks/build/{_wsId_-BhQMjyHG.mjs → _wsId_-CanI_6Su.mjs} +591 -53
  77. package/.output/server/chunks/build/{_wsId_-BhQMjyHG.mjs.map → _wsId_-CanI_6Su.mjs.map} +1 -1
  78. package/.output/server/chunks/build/{agents-D4l1icvn.mjs → agents-DSOptxXA.mjs} +146 -91
  79. package/.output/server/chunks/build/agents-DSOptxXA.mjs.map +1 -0
  80. package/.output/server/chunks/build/{alert-gH-s7yIh.mjs → alert-qJnjyRcP.mjs} +3 -3
  81. package/.output/server/chunks/build/{alert-gH-s7yIh.mjs.map → alert-qJnjyRcP.mjs.map} +1 -1
  82. package/.output/server/chunks/build/{button-BhbX5ACI.mjs → button-DEcZFcqN.mjs} +3 -3
  83. package/.output/server/chunks/build/{button-BhbX5ACI.mjs.map → button-DEcZFcqN.mjs.map} +1 -1
  84. package/.output/server/chunks/build/{card-l4BbX67w.mjs → card-Dipvaykh.mjs} +5 -5
  85. package/.output/server/chunks/build/{card-l4BbX67w.mjs.map → card-Dipvaykh.mjs.map} +1 -1
  86. package/.output/server/chunks/build/{channel-templates-DqjtC-R0.mjs → channel-templates-BK0KuPOd.mjs} +13 -12
  87. package/.output/server/chunks/build/channel-templates-BK0KuPOd.mjs.map +1 -0
  88. package/.output/server/chunks/build/{checkbox-BF11p3dH.mjs → checkbox-dzcpU_Cd.mjs} +4 -4
  89. package/.output/server/chunks/build/{checkbox-BF11p3dH.mjs.map → checkbox-dzcpU_Cd.mjs.map} +1 -1
  90. package/.output/server/chunks/build/{daq-BOgpn9sl.mjs → daq-D9RA_uze.mjs} +102 -102
  91. package/.output/server/chunks/build/{daq-BOgpn9sl.mjs.map → daq-D9RA_uze.mjs.map} +1 -1
  92. package/.output/server/chunks/build/dcw-BTM5YU-B.mjs +1 -1
  93. package/.output/server/chunks/build/{default-CKJWhkot.mjs → default-BfWGTlbj.mjs} +81 -23
  94. package/.output/server/chunks/build/{default-CKJWhkot.mjs.map → default-BfWGTlbj.mjs.map} +1 -1
  95. package/.output/server/chunks/build/{drawer-CVValqoh.mjs → drawer-Cmh90erI.mjs} +3 -3
  96. package/.output/server/chunks/build/{drawer-CVValqoh.mjs.map → drawer-Cmh90erI.mjs.map} +1 -1
  97. package/.output/server/chunks/build/{dropdown-ByCsEWlQ.mjs → dropdown-CGQ0KAzA.mjs} +2 -2
  98. package/.output/server/chunks/build/{dropdown-ByCsEWlQ.mjs.map → dropdown-CGQ0KAzA.mjs.map} +1 -1
  99. package/.output/server/chunks/build/{dropdown-Dex8PXu6.mjs → dropdown-vhn1NPFs.mjs} +4 -4
  100. package/.output/server/chunks/build/{dropdown-Dex8PXu6.mjs.map → dropdown-vhn1NPFs.mjs.map} +1 -1
  101. package/.output/server/chunks/build/{input-number-BBlRoAJ7.mjs → input-number-Bd55elNN.mjs} +5 -5
  102. package/.output/server/chunks/build/{input-number-BBlRoAJ7.mjs.map → input-number-Bd55elNN.mjs.map} +1 -1
  103. package/.output/server/chunks/build/{input--KMeLYqZ.mjs → input-sf_BT6o6.mjs} +3 -3
  104. package/.output/server/chunks/build/{input--KMeLYqZ.mjs.map → input-sf_BT6o6.mjs.map} +1 -1
  105. package/.output/server/chunks/build/logs-Dyk0I2I9.mjs +1 -1
  106. package/.output/server/chunks/build/{menu-xN-SXb9Q.mjs → menu-WCrlpYVh.mjs} +3 -3
  107. package/.output/server/chunks/build/{menu-xN-SXb9Q.mjs.map → menu-WCrlpYVh.mjs.map} +1 -1
  108. package/.output/server/chunks/build/{modal-DrCOcjrl.mjs → modal-yvUquPj5.mjs} +4 -4
  109. package/.output/server/chunks/build/{modal-DrCOcjrl.mjs.map → modal-yvUquPj5.mjs.map} +1 -1
  110. package/.output/server/chunks/build/{monitor-KW8WLOJd.mjs → monitor-MIOvsyLa.mjs} +21 -21
  111. package/.output/server/chunks/build/{monitor-KW8WLOJd.mjs.map → monitor-MIOvsyLa.mjs.map} +1 -1
  112. package/.output/server/chunks/build/pages-DR2bzczM.mjs +1 -1
  113. package/.output/server/chunks/build/{plugins-B-ZNey0Z.mjs → plugins-DnOBIWGg.mjs} +7 -7
  114. package/.output/server/chunks/build/{plugins-B-ZNey0Z.mjs.map → plugins-DnOBIWGg.mjs.map} +1 -1
  115. package/.output/server/chunks/build/{popconfirm-C5H1Qoh3.mjs → popconfirm-CRaHcz5O.mjs} +4 -4
  116. package/.output/server/chunks/build/{popconfirm-C5H1Qoh3.mjs.map → popconfirm-CRaHcz5O.mjs.map} +1 -1
  117. package/.output/server/chunks/build/{useWorkshopApi-Bh5VUHWu.mjs → segmented-DPe9ZzLO.mjs} +7 -78
  118. package/.output/server/chunks/build/segmented-DPe9ZzLO.mjs.map +1 -0
  119. package/.output/server/chunks/build/{select-D7H2ysgT.mjs → select-D-CeE5vY.mjs} +3 -3
  120. package/.output/server/chunks/build/{select-D7H2ysgT.mjs.map → select-D-CeE5vY.mjs.map} +1 -1
  121. package/.output/server/chunks/build/{settings-Cr06lbRy.mjs → settings-DA8IkGLo.mjs} +11 -11
  122. package/.output/server/chunks/build/{settings-Cr06lbRy.mjs.map → settings-DA8IkGLo.mjs.map} +1 -1
  123. package/.output/server/chunks/build/{space-DCwIlnkI.mjs → space-CCBYAkXt.mjs} +2 -2
  124. package/.output/server/chunks/build/{space-DCwIlnkI.mjs.map → space-CCBYAkXt.mjs.map} +1 -1
  125. package/.output/server/chunks/build/{switch-VC0m9ede.mjs → switch-CelRXpcy.mjs} +3 -3
  126. package/.output/server/chunks/build/{switch-VC0m9ede.mjs.map → switch-CelRXpcy.mjs.map} +1 -1
  127. package/.output/server/chunks/build/{table-BksLg3Q_.mjs → table-Cswq-l2r.mjs} +10 -10
  128. package/.output/server/chunks/build/{table-BksLg3Q_.mjs.map → table-Cswq-l2r.mjs.map} +1 -1
  129. package/.output/server/chunks/build/{tabs-CzUfD3iX.mjs → tabs-BM3tAh_J.mjs} +5 -5
  130. package/.output/server/chunks/build/{tabs-CzUfD3iX.mjs.map → tabs-BM3tAh_J.mjs.map} +1 -1
  131. package/.output/server/chunks/build/{tag-oQI3VtqM.mjs → tag-NO9jEqKy.mjs} +4 -4
  132. package/.output/server/chunks/build/{tag-oQI3VtqM.mjs.map → tag-NO9jEqKy.mjs.map} +1 -1
  133. package/.output/server/chunks/build/{teams-QR3BBF7A.mjs → teams-BhSKBBBM.mjs} +15 -14
  134. package/.output/server/chunks/build/teams-BhSKBBBM.mjs.map +1 -0
  135. package/.output/server/chunks/build/{tokens-DFvr_TLj.mjs → tokens-D_eyxmcv.mjs} +16 -16
  136. package/.output/server/chunks/build/{tokens-DFvr_TLj.mjs.map → tokens-D_eyxmcv.mjs.map} +1 -1
  137. package/.output/server/chunks/build/town-BUqRobze.mjs +1 -1
  138. package/.output/server/chunks/build/{town-_4tEEEVW.mjs → town-DPtOPRRO.mjs} +4 -4
  139. package/.output/server/chunks/build/{town-_4tEEEVW.mjs.map → town-DPtOPRRO.mjs.map} +1 -1
  140. package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs +42 -0
  141. package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs.map +1 -0
  142. package/.output/server/chunks/build/useWorkshopApi-D2gq06N2.mjs +81 -0
  143. package/.output/server/chunks/build/useWorkshopApi-D2gq06N2.mjs.map +1 -0
  144. package/.output/server/chunks/build/useWorkshopWs-B3j5wIAK.mjs +1 -1
  145. package/.output/server/chunks/build/user-Dk-ytEUV.mjs +1 -1
  146. package/.output/server/chunks/build/{users-4FZ0yFUO.mjs → users-CmVvb1oq.mjs} +16 -16
  147. package/.output/server/chunks/build/{users-4FZ0yFUO.mjs.map → users-CmVvb1oq.mjs.map} +1 -1
  148. package/.output/server/chunks/build/{workshop-k0XZTFKg.mjs → workshop-iCzNRifn.mjs} +9 -9
  149. package/.output/server/chunks/build/{workshop-k0XZTFKg.mjs.map → workshop-iCzNRifn.mjs.map} +1 -1
  150. package/.output/server/chunks/build/workspaces-IfORCDJE.mjs +1 -1
  151. package/.output/server/chunks/routes/api/health.get.mjs +1 -1
  152. package/.output/server/chunks/routes/api/index.get.mjs +1 -1
  153. package/.output/server/chunks/routes/api/index.post.mjs +1 -1
  154. package/.output/server/chunks/routes/api/mcp/workshop.mjs +1 -1
  155. package/.output/server/chunks/routes/api/metrics.mjs +1 -1
  156. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -1
  157. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +1 -1
  158. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +1 -1
  159. package/.output/server/chunks/routes/api/system/config.get.mjs +1 -1
  160. package/.output/server/chunks/routes/api/system/index.get.mjs +3 -3
  161. package/.output/server/chunks/routes/api/system/index.get.mjs.map +1 -1
  162. package/.output/server/chunks/routes/api/system/index.patch.mjs +1 -1
  163. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +1 -1
  164. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +1 -1
  165. package/.output/server/chunks/routes/api/system/monitor.get.mjs +1 -1
  166. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +1 -1
  167. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +1 -1
  168. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +1 -1
  169. package/.output/server/chunks/routes/api/users/_id_.get.mjs +1 -1
  170. package/.output/server/chunks/routes/api/users/_id_.put.mjs +1 -1
  171. package/.output/server/chunks/routes/api/users/index.get.mjs +1 -1
  172. package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
  173. package/.output/server/chunks/routes/api/users/login.post.mjs +1 -1
  174. package/.output/server/chunks/routes/api/users/logout.post.mjs +1 -1
  175. package/.output/server/chunks/routes/api/users/me.get.mjs +1 -1
  176. package/.output/server/chunks/routes/api/users/register.post.mjs +1 -1
  177. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +1 -1
  178. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +1 -1
  179. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
  180. package/.output/server/chunks/routes/api/workshop/_...path_.mjs +1 -1
  181. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +1 -1
  182. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +1 -1
  183. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
  184. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +1 -1
  185. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +1 -1
  186. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +1 -1
  187. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +1 -1
  188. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +1 -1
  189. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
  190. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +6 -14
  191. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
  192. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +39 -0
  193. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs.map +1 -0
  194. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +1 -1
  195. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +1 -1
  196. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
  197. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
  198. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +1 -1
  199. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +1 -1
  200. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +1 -1
  201. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +1 -1
  202. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +2 -2
  203. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -1
  204. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +2 -2
  205. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +1 -1
  206. package/.output/server/chunks/routes/api/workshop/caller.mjs +1 -1
  207. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +2 -2
  208. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +1 -1
  210. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
  211. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
  212. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -2
  213. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +1 -1
  214. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
  215. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +1 -1
  216. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
  217. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +1 -1
  218. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +1 -1
  219. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +1 -1
  220. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +1 -1
  221. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +1 -1
  222. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +1 -1
  223. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
  224. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +1 -1
  225. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +2 -2
  226. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +1 -1
  227. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
  228. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +1 -1
  229. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +1 -1
  231. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  232. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +1 -1
  233. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +1 -1
  234. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -2
  235. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +1 -1
  236. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -2
  237. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +9 -2
  238. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs.map +1 -1
  239. package/.output/server/chunks/routes/api/workshop/channels.get.mjs +1 -1
  240. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +2 -2
  241. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +2 -2
  242. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +2 -2
  243. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +2 -2
  244. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +6 -4
  245. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
  246. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -2
  247. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +2 -2
  248. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +2 -2
  249. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +2 -2
  250. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -2
  251. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +2 -2
  252. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -2
  253. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -2
  254. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -2
  255. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -2
  256. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -2
  257. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -2
  258. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +2 -2
  259. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -2
  260. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +2 -2
  261. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +2 -2
  262. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +2 -2
  263. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -2
  264. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +2 -2
  265. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -2
  266. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -2
  267. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +2 -2
  268. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +2 -2
  269. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +2 -2
  270. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -2
  271. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -2
  272. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -2
  273. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -2
  274. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +2 -2
  275. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -2
  276. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +2 -2
  277. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +2 -2
  278. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +2 -2
  279. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -2
  280. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -2
  281. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -2
  282. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -2
  283. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -2
  284. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -2
  285. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -2
  286. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -2
  287. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -2
  288. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -2
  289. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -2
  290. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -2
  291. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.patch.mjs +2 -2
  292. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -2
  293. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +2 -2
  294. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -2
  295. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -2
  296. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -2
  297. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -2
  298. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
  299. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
  300. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -2
  301. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -2
  302. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +1 -1
  303. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +247 -0
  304. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs.map +1 -0
  305. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +27 -0
  306. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs.map +1 -0
  307. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  308. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +19 -7
  309. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -1
  310. package/.output/server/chunks/routes/api/workshop/index.get.mjs +1 -1
  311. package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
  312. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +1 -1
  313. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
  314. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
  315. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +1 -1
  316. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +2 -2
  317. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +2 -2
  318. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -2
  319. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +2 -2
  320. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -2
  321. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
  322. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -2
  323. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
  324. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
  325. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +1 -1
  326. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
  327. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +1 -1
  328. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +1 -1
  329. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +1 -1
  330. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +1 -1
  331. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  332. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  333. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +1 -1
  334. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +1 -1
  335. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  336. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  337. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +1 -1
  338. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
  339. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
  340. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +1 -1
  341. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
  342. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +1 -1
  343. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +1 -1
  344. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +1 -1
  345. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +2 -2
  346. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +1 -1
  347. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
  348. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +1 -1
  349. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +1 -1
  350. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +1 -1
  351. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
  352. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +1 -1
  353. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +1 -1
  354. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
  355. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +1 -1
  356. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +1 -1
  357. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +1 -1
  358. package/.output/server/chunks/routes/renderer.mjs +1 -1
  359. package/.output/server/chunks/virtual/entry.mjs +123 -113
  360. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  361. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  362. package/.output/server/index.mjs +1 -1
  363. package/.output/server/package.json +1 -1
  364. package/app/components/AppHeader.vue +56 -2
  365. package/app/components/workshop/ChannelSessionList.vue +703 -593
  366. package/app/components/workshop/terminal/OmpTerminalPanel.vue +2 -1
  367. package/app/composables/workshop/useLocalTime.ts +16 -0
  368. package/app/composables/workshop/useSceneLayouts.ts +2 -1
  369. package/app/composables/workshop/useWorkshopApi.ts +249 -224
  370. package/app/pages/daq/[id].vue +7 -6
  371. package/app/pages/daq/index.vue +2 -2
  372. package/app/pages/dcw/[id].vue +3 -3
  373. package/app/pages/workshop/agents.vue +432 -382
  374. package/bin/aw.mjs +0 -0
  375. package/cli/aw.mjs +8 -1
  376. package/cli/commands/stop.mjs +7 -4
  377. package/cli/commands/tui.mjs +10 -1
  378. package/cli/core/registry.mjs +5 -3
  379. package/config.yml +134 -134
  380. package/docs/tui.md +1 -1
  381. package/i18n/locales/en.ts +5 -0
  382. package/i18n/locales/zh-CN.ts +5 -0
  383. package/package.json +148 -140
  384. package/scripts/_dbg-catalog-smoke.ts +20 -0
  385. package/scripts/_dbg-codex-probe.mjs +58 -0
  386. package/scripts/_dbg-dsh-probe.mjs +31 -0
  387. package/scripts/_dbg-interval-scenario.mjs +126 -0
  388. package/scripts/_dbg-line-spawn.ts +31 -0
  389. package/scripts/_dbg-live-engine-probe.mjs +80 -0
  390. package/scripts/_dbg-mcp-bridge-probe.mjs +147 -0
  391. package/scripts/_dbg-opencode-sse.mjs +101 -0
  392. package/scripts/_dbg-opencode-start.ts +57 -0
  393. package/scripts/_dbg-plugin-matrix.mjs +212 -0
  394. package/scripts/_dbg-protocol-matrix.mjs +425 -0
  395. package/scripts/_dbg-real-scenario-timeline.log +123 -0
  396. package/scripts/_dbg-registry-smoke.ts +14 -0
  397. package/scripts/_dbg-sim-keeper.mjs +100 -0
  398. package/scripts/_dbg-team-drill.mjs +173 -0
  399. package/scripts/dev-guard.mjs +11 -3
  400. package/scripts/dev-protocol-simulators.mjs +28 -1
  401. package/scripts/e2e-multi-harness.ts +374 -0
  402. package/scripts/e2e-multiharness-team.mjs +319 -0
  403. package/scripts/e2e-plc-scenario.mjs +292 -0
  404. package/scripts/e2e-real-scenario.mjs +452 -0
  405. package/scripts/migrate-local-time.mjs +123 -0
  406. package/scripts/start.mjs +30 -2
  407. package/server/api/system/settings/index.get.ts +3 -3
  408. package/server/api/workshop/agent-tools/invoke.post.ts +27 -41
  409. package/server/api/workshop/agent-tools/list.get.ts +25 -0
  410. package/server/api/workshop/channels/[id]/index.patch.ts +38 -30
  411. package/server/api/workshop/daq/[id]/samples.get.ts +6 -3
  412. package/server/api/workshop/harnesses/[id]/providers.get.ts +16 -0
  413. package/server/api/workshop/harnesses.get.ts +12 -0
  414. package/server/api/workshop/hitl/respond.post.ts +87 -67
  415. package/server/api/workshop/ws.ts +13 -0
  416. package/server/data/daqs.json +1366 -16
  417. package/server/data/dcw-lines.json +266 -0
  418. package/server/data/dcw-products.json +203 -0
  419. package/server/data/dcw-recipes.json +784 -0
  420. package/server/data/dcw-rollback.json +1144 -1
  421. package/server/data/dcw-runs.json +983 -791
  422. package/server/data/dcw-writes.json +1080 -0
  423. package/server/data/dcws.json +3278 -203
  424. package/server/data/line-runs.json +52 -2
  425. package/server/harness/aw-mcp-bridge.mjs +153 -0
  426. package/server/plugins/00-local-time.ts +10 -0
  427. package/server/plugins/aw-plugins.ts +3 -0
  428. package/server/plugins/backup.ts +116 -97
  429. package/server/plugins/dev-stability-guard.ts +24 -15
  430. package/server/plugins/retention.ts +1 -0
  431. package/server/plugins/security.ts +24 -3
  432. package/server/plugins/workshop.ts +156 -153
  433. package/server/repositories/user.repository.ts +414 -391
  434. package/server/services/system-config.ts +30 -6
  435. package/server/services/workshop/.mimosa/hook-state/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f.json +1 -0
  436. package/server/services/workshop/.mimosa/hook-status/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f-e6b75bbfe6.json +14 -0
  437. package/server/services/workshop/agents/adapters/line-spawn.ts +108 -0
  438. package/server/services/workshop/agents/adapters/stdio-jsonrpc.ts +316 -0
  439. package/server/services/workshop/agents/agent-interface.ts +17 -0
  440. package/server/services/workshop/agents/codex-agent.ts +822 -0
  441. package/server/services/workshop/agents/dsh-agent.ts +670 -0
  442. package/server/services/workshop/agents/factory.ts +4 -16
  443. package/server/services/workshop/agents/harness-env.ts +54 -0
  444. package/server/services/workshop/agents/harness-models.ts +270 -0
  445. package/server/services/workshop/agents/host-tool-bridge.ts +592 -0
  446. package/server/services/workshop/agents/industrial-tools.ts +5 -1
  447. package/server/services/workshop/agents/node-bindings.repo.ts +4 -5
  448. package/server/services/workshop/agents/omp-agent.ts +1178 -1957
  449. package/server/services/workshop/agents/opencode-agent.ts +987 -0
  450. package/server/services/workshop/agents/prompt-builder.ts +393 -0
  451. package/server/services/workshop/agents/registry.ts +125 -0
  452. package/server/services/workshop/assets/character-asset.repo.ts +3 -5
  453. package/server/services/workshop/assets/device-twin.repo.ts +3 -5
  454. package/server/services/workshop/daq/daq-controller.ts +8 -4
  455. package/server/services/workshop/daq/daq-node.repo.ts +3 -5
  456. package/server/services/workshop/daq/daq-node.ts +2 -2
  457. package/server/services/workshop/daq/daq-templates.ts +3 -5
  458. package/server/services/workshop/daq/drivers.ts +41 -12
  459. package/server/services/workshop/daq/storage/sqlite.adapter.ts +313 -309
  460. package/server/services/workshop/db/backup-registry.ts +33 -0
  461. package/server/services/workshop/db/channel.repo.ts +104 -101
  462. package/server/services/workshop/db/database.ts +956 -949
  463. package/server/services/workshop/dcw/dcw-controller.ts +3 -1
  464. package/server/services/workshop/dcw/dcw-line.repo.ts +4 -11
  465. package/server/services/workshop/dcw/dcw-node.repo.ts +3 -5
  466. package/server/services/workshop/dcw/dcw-node.ts +13 -1
  467. package/server/services/workshop/dcw/dcw-product.repo.ts +3 -4
  468. package/server/services/workshop/dcw/dcw-recipe.repo.ts +3 -19
  469. package/server/services/workshop/dcw/dcw-templates.ts +3 -5
  470. package/server/services/workshop/dcw/drivers.ts +37 -13
  471. package/server/services/workshop/dcw/line-run.ts +3 -5
  472. package/server/services/workshop/dcw/recipe-rollback.repo.ts +4 -10
  473. package/server/services/workshop/json-store.mjs +72 -0
  474. package/server/services/workshop/plugins/host.mjs +2 -1
  475. package/server/services/workshop/runtime/agent-runtime.ts +44 -0
  476. package/server/services/workshop/runtime/manager.ts +2953 -2868
  477. package/server/services/workshop/scene/scene-layout.repo.ts +4 -11
  478. package/server/services/workshop/settings.ts +7 -0
  479. package/shared/config/schema.json +5 -0
  480. package/shared/config/single-instance.mjs +5 -1
  481. package/shared/local-time.mjs +36 -0
  482. package/shared/workshop-protocol.ts +11 -5
  483. package/tui/aw-tui.mjs +28 -10
  484. package/tui/components/hitl-card.mjs +47 -36
  485. package/tui/lib/ws.mjs +2 -1
  486. package/.output/public/_nuxt/9X0fVBD7.js +0 -57
  487. package/.output/public/_nuxt/B6M2WJWm2.js +0 -1
  488. package/.output/public/_nuxt/B9Yie5HN.js +0 -2
  489. package/.output/public/_nuxt/BF9XPEuw.js +0 -1
  490. package/.output/public/_nuxt/BbQornXa.js +0 -1
  491. package/.output/public/_nuxt/Bxgaym6j.js +0 -1
  492. package/.output/public/_nuxt/Bxh5nf8j.js +0 -1
  493. package/.output/public/_nuxt/CXLI50Sq.js +0 -1
  494. package/.output/public/_nuxt/CdfAP_IH2.js +0 -1
  495. package/.output/public/_nuxt/Ce1zyNYu.js +0 -1
  496. package/.output/public/_nuxt/D-Ne4C9a.js +0 -1
  497. package/.output/public/_nuxt/DEHNjlTq2.js +0 -1
  498. package/.output/public/_nuxt/DFnGFEav.js +0 -18
  499. package/.output/public/_nuxt/DYWgGHNo.js +0 -7
  500. package/.output/public/_nuxt/OmpTerminalPanel.Bc9GjNU5.css +0 -1
  501. package/.output/public/_nuxt/W1E3-5ML.js +0 -14
  502. package/.output/public/_nuxt/XVB9_zwP.js +0 -1
  503. package/.output/public/_nuxt/Xaf_HIR3.js +0 -1
  504. package/.output/public/_nuxt/_id_.BeqSLvl_.css +0 -1
  505. package/.output/public/_nuxt/_id_.DN3U6EF9.css +0 -1
  506. package/.output/public/_nuxt/agents.BJwgTLFZ.css +0 -1
  507. package/.output/public/_nuxt/builds/meta/55c10854-ee0e-4be4-924b-a1b0e100fe11.json +0 -1
  508. package/.output/public/_nuxt/daq.BXsnevQv.css +0 -1
  509. package/.output/public/_nuxt/yIKY_V1P.js +0 -1
  510. package/.output/server/chunks/build/OmpTerminalPanel-B_SYhmgb.mjs.map +0 -1
  511. package/.output/server/chunks/build/_id_-CWLFGZjV.mjs.map +0 -1
  512. package/.output/server/chunks/build/agents-D4l1icvn.mjs.map +0 -1
  513. package/.output/server/chunks/build/channel-templates-DqjtC-R0.mjs.map +0 -1
  514. package/.output/server/chunks/build/interval-WlxgjTzO.mjs +0 -9
  515. package/.output/server/chunks/build/interval-WlxgjTzO.mjs.map +0 -1
  516. package/.output/server/chunks/build/teams-QR3BBF7A.mjs.map +0 -1
  517. package/.output/server/chunks/build/useWorkshopApi-Bh5VUHWu.mjs.map +0 -1
@@ -1,593 +1,703 @@
1
- <script setup lang="ts">
2
- /**
3
- * 左栏 Channel 会话列表(Zcode session 栏):workspace 内挂载的 channel,
4
- * 实时状态徽标(忙碌成员数/活跃任务数),点击聚焦;挂载/移出/设置操作。
5
- * v10 模板化:
6
- * - 「从模板挂载」:选择 Channel 模板 → 实例化 + 挂载一步完成(替代"挂载已有 Channel");
7
- * - 「设置」:热修改当前 Channel 实例的场景描述与工作目录(成员运行时自动回收重装配);
8
- * - 「保存为模板」:把当前 Channel 实例捕获为可复用模板(场景/目录/团队快照)。
9
- */
10
- import { message } from 'ant-design-vue'
11
- import { useWorkspacesStore } from '@/app/stores/workshop/workspaces'
12
- import { useEntitiesStore } from '@/app/stores/workshop/entities'
13
- import { useWorkshopApi, type ChannelDto, type ChannelTemplateDto } from '@/app/composables/workshop/useWorkshopApi'
14
-
15
- const { t } = useI18n()
16
-
17
- const props = defineProps<{ wsId: string }>()
18
- const wsStore = useWorkspacesStore()
19
- const entities = useEntitiesStore()
20
- const api = useWorkshopApi()
21
-
22
- const workspace = computed(() => wsStore.workspaces.find(w => w.id === props.wsId))
23
-
24
- const channels = ref<ChannelDto[]>([])
25
- const channelTemplates = ref<ChannelTemplateDto[]>([])
26
- const refreshChannels = async (): Promise<void> => {
27
- // SSR 守卫:axios 相对 baseURL 仅客户端有效(服务端拉取会 Invalid URL)
28
- if (typeof window === 'undefined') return
29
- const [ch, tpl] = await Promise.all([
30
- api.listChannels(),
31
- api.listChannelTemplates().catch(() => null),
32
- ])
33
- channels.value = (ch as unknown as { data?: ChannelDto[] })?.data ?? []
34
- channelTemplates.value = (tpl as unknown as { data?: ChannelTemplateDto[] } | null)?.data ?? []
35
- }
36
- void refreshChannels()
37
-
38
- const mountedChannels = computed(() =>
39
- (workspace.value?.channelIds ?? [])
40
- .map(id => ({ id, meta: channels.value.find(c => c.id === id), entity: entities.channels[id] }))
41
- .map(({ id, meta, entity }) => ({
42
- id,
43
- name: entity?.name ?? meta?.name ?? id.slice(0, 8),
44
- /** 实体基线(WS 快照)是否已到达:未到时计数不可信,展示"同步中"而非误导性的 0 */
45
- synced: entity !== undefined,
46
- busy: entities.busyCount(id),
47
- agents: entities.agents[id]?.length ?? 0,
48
- activeTasks: (entities.tasks[id] ?? []).filter(t => !['COMPLETED', 'CANCELED', 'FAILED'].includes(t.state)).length,
49
- workspace: meta?.workspace ?? '',
50
- })),
51
- )
52
-
53
- const select = (channelId: string): void => {
54
- wsStore.setActiveChannel(props.wsId, channelId)
55
- }
56
-
57
- /** 点击工作目录行:复制完整路径到剪贴板(有真实作用;title 提示全路径) */
58
- const copyWorkspace = async (path: string): Promise<void> => {
59
- try {
60
- await navigator.clipboard.writeText(path)
61
- message.success(t('channelSessionList.kud74vg040', { p0: path }))
62
- }
63
- catch {
64
- message.error(t('channelSessionList.krij3gg026'))
65
- }
66
- }
67
- /** 路径显示 basename(E:\codes\AgentWorkShop → AgentWorkShop),全路径在 title/复制 */
68
- const baseName = (path: string): string => path.replace(/[\\/]+$/, '').split(/[\\/]/).pop() ?? path
69
- /** 默认目录(data/workspaces/<uuid>)的 basename 是 36 位裸 UUID,对用户零信息量 → 不展示该行 */
70
- const UUID_RE = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i
71
- const displayWorkspace = (path: string): string => {
72
- const base = baseName(path)
73
- return UUID_RE.test(base) ? '' : base
74
- }
75
-
76
- // ===== 新建 Channel 并挂载(空团队) =====
77
- const mountModal = ref(false)
78
- const mountForm = reactive({ name: '', description: '', workspace: '', scenarioPrompt: '' })
79
- const mountSubmitting = ref(false)
80
- /** FileSelector 弹窗(选择服务器目录作为 workspace) */
81
- const fileSelectorOpen = ref(false)
82
- const createAndMount = async (): Promise<void> => {
83
- if (!mountForm.name.trim()) {
84
- message.warning('Channel 名称必填')
85
- return
86
- }
87
- mountSubmitting.value = true
88
- try {
89
- const res = await api.createChannel({
90
- name: mountForm.name.trim(),
91
- description: mountForm.description || undefined,
92
- scenarioPrompt: mountForm.scenarioPrompt.trim() || undefined,
93
- workspace: mountForm.workspace.trim() || undefined,
94
- })
95
- const created = (res as unknown as { data?: { channelId?: string } })?.data
96
- const channelId = created?.channelId
97
- if (!channelId) throw new Error(t('channelSessionList.k1bg6shc027'))
98
- await wsStore.mountChannel(props.wsId, channelId)
99
- mountModal.value = false
100
- mountForm.name = ''
101
- mountForm.description = ''
102
- mountForm.workspace = ''
103
- mountForm.scenarioPrompt = ''
104
- void refreshChannels()
105
- message.success(t('channelSessionList.kn89jvs028'))
106
- }
107
- catch (e) {
108
- message.error(t('channelSessionList.k1x2th9e041', { p0: e instanceof Error ? e.message : String(e) }))
109
- }
110
- finally {
111
- mountSubmitting.value = false
112
- }
113
- }
114
-
115
- // ===== 从 Channel 模板挂载(实例化 + mount 一步) =====
116
- const templateMountId = ref<string | undefined>()
117
- const templateMounting = ref(false)
118
- const mountFromTemplate = async (): Promise<void> => {
119
- if (!templateMountId.value) return
120
- templateMounting.value = true
121
- try {
122
- const res = await api.mountChannelTemplate(props.wsId, templateMountId.value)
123
- const data = (res as unknown as { data?: { agentCount?: number } })?.data
124
- message.success(t('channelSessionList.kai50qc042', { p0: data?.agentCount ?? 0 }))
125
- templateMountId.value = undefined
126
- void refreshChannels()
127
- }
128
- catch (e) {
129
- const err = e as { data?: { message?: string }, message?: string }
130
- message.error(err?.data?.message ?? err?.message ?? t('channelSessionList.k97xi7u029'))
131
- }
132
- finally {
133
- templateMounting.value = false
134
- }
135
- }
136
-
137
- const unmount = (channelId: string): void => {
138
- wsStore.unmountChannel(props.wsId, channelId)
139
- .catch((e: { data?: { message?: string }, message?: string }) => { message.error(e?.data?.message ?? e?.message ?? t('channelSessionList.k1hgfvdc030')) })
140
- }
141
-
142
- // ===== Channel 实例设置(场景/工作目录热更新)+ 保存为模板 =====
143
- const settingsOpen = ref(false)
144
- const settingsChannelId = ref<string>('')
145
- const settingsForm = reactive({ name: '', scenarioPrompt: '', workspace: '' })
146
- const settingsSaving = ref(false)
147
- const fileSelectorOpen2 = ref(false)
148
- const openSettings = (channelId: string): void => {
149
- const meta = channels.value.find(c => c.id === channelId)
150
- settingsChannelId.value = channelId
151
- settingsForm.name = meta?.name ?? ''
152
- settingsForm.scenarioPrompt = meta?.scenarioPrompt ?? ''
153
- settingsForm.workspace = meta?.workspace ?? ''
154
- settingsOpen.value = true
155
- }
156
- const saveSettings = async (): Promise<void> => {
157
- settingsSaving.value = true
158
- try {
159
- await api.patchChannel(settingsChannelId.value, {
160
- scenarioPrompt: settingsForm.scenarioPrompt,
161
- workspace: settingsForm.workspace.trim() || undefined,
162
- })
163
- message.success(t('channelSessionList.kvsxlu6031'))
164
- settingsOpen.value = false
165
- void refreshChannels()
166
- }
167
- catch (e) {
168
- message.error(e instanceof Error ? e.message : String(e))
169
- }
170
- finally {
171
- settingsSaving.value = false
172
- }
173
- }
174
-
175
- // 保存为模板(捕获当前 channel 的场景/目录/团队)
176
- const saveTplOpen = ref(false)
177
- const saveTplForm = reactive({ name: '', description: '', visibility: 'private' as 'private' | 'public' })
178
- const saveTplSubmitting = ref(false)
179
- const openSaveTemplate = (): void => {
180
- saveTplForm.name = t('channelSessionList.k2hfym5043', { p0: settingsForm.name || 'channel' })
181
- saveTplForm.description = ''
182
- saveTplForm.visibility = 'private'
183
- saveTplOpen.value = true
184
- }
185
- const saveAsTemplate = async (): Promise<void> => {
186
- if (!saveTplForm.name.trim()) {
187
- message.warning(t('channelSessionList.k1i0ji0y032'))
188
- return
189
- }
190
- saveTplSubmitting.value = true
191
- try {
192
- await api.captureChannelTemplate({
193
- channelId: settingsChannelId.value,
194
- name: saveTplForm.name.trim(),
195
- description: saveTplForm.description || undefined,
196
- visibility: saveTplForm.visibility,
197
- })
198
- message.success(t('channelSessionList.kjpguxw033'))
199
- saveTplOpen.value = false
200
- void refreshChannels()
201
- }
202
- catch (e) {
203
- message.error(e instanceof Error ? e.message : String(e))
204
- }
205
- finally {
206
- saveTplSubmitting.value = false
207
- }
208
- }
209
- </script>
210
-
211
- <template>
212
- <div class="channel-list">
213
- <div class="list-head">
214
- <span class="title">Channels</span>
215
- <span class="head-actions">
216
- <button
217
- class="head-op im"
218
- type="button"
219
- title="Channel 模板中心"
220
- @click="navigateTo('/workshop/channel-templates')"
221
- >
222
- <span class="i-tabler-layout-grid-add im-pop" />
223
- </button>
224
- <button
225
- class="head-op im"
226
- type="button"
227
- title="新建 Channel"
228
- @click="mountModal = true"
229
- >
230
- <span class="i-tabler-plus im-pop" />
231
- </button>
232
- </span>
233
- </div>
234
-
235
- <!-- 频道列表主体:数据源(REST channels + WS entities)均为客户端态,
236
- SSR 首帧为空 → 硬刷新水合时结构与客户端首渲染不一致,节点会错配到
237
- 相邻 antd Select 的 DOM 上(行内 .row1 布局丢失、按钮错位)。
238
- ClientOnly 隔离:SSR 输出空壳,客户端一次性渲染,无水合配对。 -->
239
- <ClientOnly>
240
- <div
241
- v-if="mountedChannels.length === 0"
242
- class="empty"
243
- >
244
- {{ $t('channelSessionList.kkv789s014') }}
245
- </div>
246
-
247
- <div
248
- v-for="ch in mountedChannels"
249
- :key="ch.id"
250
- class="channel-item"
251
- :class="{ active: workspace?.activeChannelId === ch.id }"
252
- @click="select(ch.id)"
253
- >
254
- <div class="row1">
255
- <span
256
- class="dot"
257
- :class="{ live: ch.activeTasks > 0 }"
258
- />
259
- <span class="ch-name">{{ ch.name }}</span>
260
- <button
261
- class="op im"
262
- type="button"
263
- :title="$t('channelSessionList.kne35ug001')"
264
- :aria-label="$t('channelSessionList.kjmldih035', { p0: ch.name })"
265
- @click.stop="openSettings(ch.id)"
266
- >
267
- <span class="i-tabler-settings2 im-pop" />
268
- </button>
269
- <button
270
- class="op im"
271
- type="button"
272
- title="移出 workspace"
273
- :aria-label="$t('channelSessionList.k1yurooi036', { p0: ch.name })"
274
- @click.stop="unmount(ch.id)"
275
- >
276
- <span class="i-tabler-x im-pop" />
277
- </button>
278
- </div>
279
- <div class="row2">
280
- <!-- 快照未到达:计数不可信,显示同步占位(不呈现误导性的"0 成员") -->
281
- <span
282
- v-if="!ch.synced"
283
- class="meta syncing"
284
- >{{ $t('channelSessionList.k1bst7s9015') }}</span>
285
- <span
286
- v-else
287
- class="meta"
288
- >{{ ch.agents }} {{ $t('channelSessionList.k1ggoa45025') }} {{ ch.busy }} / {{ $t('channelSessionList.k3wcox034') }} {{ ch.activeTasks }}</span>
289
- </div>
290
- <button
291
- v-if="displayWorkspace(ch.workspace)"
292
- class="row2 ws im"
293
- type="button"
294
- :title="$t('channelSessionList.kfe4pzq037', { p0: ch.workspace })"
295
- @click.stop="copyWorkspace(ch.workspace)"
296
- >
297
- <span class="i-tabler-folder" /> {{ displayWorkspace(ch.workspace) }}
298
- </button>
299
- </div>
300
- </ClientOnly>
301
-
302
- <div class="mount-template">
303
- <a-select
304
- v-model:value="templateMountId"
305
- size="small"
306
- :placeholder="'从 Channel 模板挂载'"
307
- class="select"
308
- :loading="templateMounting"
309
- :options="channelTemplates.map(t => ({
310
- value: t.id,
311
- label: $t('channelSessionList.k1oes209038', { p0: t.isBuiltin ? '内置 · ' : t.visibility === 'public' ? '公开 · ' : '', p1: t.name, p2: (t.lead ? 1 : 0) + t.members.length }),
312
- }))"
313
- @change="mountFromTemplate"
314
- />
315
- <div class="tpl-hint">
316
- {{ $t('channelSessionList.k18ppu31016') }}
317
- </div>
318
- </div>
319
-
320
- <a-modal
321
- v-model:open="mountModal"
322
- :title="$t('channelSessionList.k1qjyl6l002')"
323
- :confirm-loading="mountSubmitting"
324
- ok-text="创建"
325
- cancel-text="取消"
326
- @ok="createAndMount"
327
- >
328
- <a-form layout="vertical">
329
- <a-form-item label="Channel 名称">
330
- <a-input v-model:value="mountForm.name" />
331
- </a-form-item>
332
- <a-form-item :label="$t('channelSessionList.k40gkk003')">
333
- <a-input v-model:value="mountForm.description" />
334
- </a-form-item>
335
- <a-form-item :label="$t('channelSessionList.k1wj4f38004')">
336
- <a-textarea
337
- v-model:value="mountForm.scenarioPrompt"
338
- :rows="4"
339
- :placeholder="$t('channelSessionList.k1098zie005')"
340
- />
341
- <template #extra>
342
- <span class="ws-hint">{{ $t('channelSessionList.k1u3zsr5017') }}</span>
343
- </template>
344
- </a-form-item>
345
- <a-form-item :label="$t('channelSessionList.kmgv4h5006')">
346
- <a-input-group compact>
347
- <a-input
348
- v-model:value="mountForm.workspace"
349
- style="width: 70%"
350
- placeholder="留空 = data/workspaces/<channelId>"
351
- allow-clear
352
- @press-enter="createAndMount"
353
- />
354
- <a-button
355
- style="width: 30%"
356
- @click="fileSelectorOpen = true"
357
- >
358
- {{ $t('channelSessionList.k3pz0ma018') }}
359
- </a-button>
360
- </a-input-group>
361
- <template #extra>
362
- <span class="ws-hint">{{ $t('channelSessionList.kucq30k019') }}</span>
363
- </template>
364
- </a-form-item>
365
- <a-form-item>
366
- <span class="ws-hint">{{ $t('channelSessionList.k1ful761020') }}</span>
367
- </a-form-item>
368
- </a-form>
369
- </a-modal>
370
-
371
- <!-- Channel 实例设置:场景/工作目录热更新 + 保存为模板 -->
372
- <a-modal
373
- v-model:open="settingsOpen"
374
- :title="$t('channelSessionList.k1pmemvt039', { p0: settingsForm.name })"
375
- :confirm-loading="settingsSaving"
376
- ok-text="保存"
377
- cancel-text="取消"
378
- @ok="saveSettings"
379
- >
380
- <a-form layout="vertical">
381
- <a-form-item :label="$t('channelSessionList.k1i8q46x007')">
382
- <a-textarea
383
- v-model:value="settingsForm.scenarioPrompt"
384
- :rows="4"
385
- :placeholder="$t('channelSessionList.ku3ugac008')"
386
- />
387
- </a-form-item>
388
- <a-form-item :label="$t('channelSessionList.k67dzev009')">
389
- <a-input-group compact>
390
- <a-input
391
- v-model:value="settingsForm.workspace"
392
- style="width: 70%"
393
- placeholder="data/workspaces/<channelId>"
394
- allow-clear
395
- />
396
- <a-button
397
- style="width: 30%"
398
- @click="fileSelectorOpen2 = true"
399
- >
400
- {{ $t('channelSessionList.k3pz0ma018') }}
401
- </a-button>
402
- </a-input-group>
403
- </a-form-item>
404
- <a-form-item>
405
- <a-button
406
- size="small"
407
- @click="openSaveTemplate"
408
- >
409
- <span class="i-tabler-template" />
410
- {{ $t('channelSessionList.k6kpql010') }}
411
- </a-button>
412
- <span class="ws-hint">{{ $t('channelSessionList.k1x6kznr021') }}</span>
413
- </a-form-item>
414
- </a-form>
415
- </a-modal>
416
-
417
- <!-- 保存为模板 -->
418
- <a-modal
419
- v-model:open="saveTplOpen"
420
- :title="$t('channelSessionList.k6kpql010')"
421
- :confirm-loading="saveTplSubmitting"
422
- ok-text="保存模板"
423
- cancel-text="取消"
424
- @ok="saveAsTemplate"
425
- >
426
- <a-form layout="vertical">
427
- <a-form-item :label="$t('channelSessionList.k1f55q76011')">
428
- <a-input v-model:value="saveTplForm.name" />
429
- </a-form-item>
430
- <a-form-item :label="$t('channelSessionList.k40gkk003')">
431
- <a-input v-model:value="saveTplForm.description" />
432
- </a-form-item>
433
- <a-form-item :label="$t('channelSessionList.k3lrqn0012')">
434
- <a-radio-group v-model:value="saveTplForm.visibility">
435
- <a-radio value="private">
436
- {{ $t('channelSessionList.k1otvrfv022') }}
437
- </a-radio>
438
- <a-radio value="public">
439
- {{ $t('channelSessionList.k1cc399s023') }}
440
- </a-radio>
441
- </a-radio-group>
442
- </a-form-item>
443
- <a-form-item>
444
- <span class="ws-hint">{{ $t('channelSessionList.kl9btf7024') }}</span>
445
- </a-form-item>
446
- </a-form>
447
- </a-modal>
448
-
449
- <!-- FileSelector:服务器目录选择 -> 回填工作目录 -->
450
- <workshop-file-selector-modal
451
- v-model:open="fileSelectorOpen"
452
- :title="$t('channelSessionList.kbdp56k013')"
453
- :initial-path="mountForm.workspace || undefined"
454
- @select="(p) => { mountForm.workspace = p }"
455
- />
456
- <workshop-file-selector-modal
457
- v-model:open="fileSelectorOpen2"
458
- :title="$t('channelSessionList.kbdp56k013')"
459
- :initial-path="settingsForm.workspace || undefined"
460
- @select="(p) => { settingsForm.workspace = p }"
461
- />
462
- </div>
463
- </template>
464
-
465
- <style scoped>
466
- .channel-list {
467
- display: flex;
468
- flex-direction: column;
469
- min-height: 100%;
470
- padding: 12px 10px 8px;
471
- }
472
- .list-head {
473
- display: flex;
474
- align-items: center;
475
- justify-content: space-between;
476
- padding: 0 8px 8px;
477
- }
478
- .title {
479
- font-family: var(--font-display);
480
- font-size: 16px;
481
- letter-spacing: -0.01em;
482
- color: var(--ink);
483
- }
484
- .head-actions { display: inline-flex; gap: 2px; }
485
- .head-op {
486
- display: inline-flex;
487
- align-items: center;
488
- justify-content: center;
489
- width: 24px;
490
- height: 24px;
491
- font-size: 14px;
492
- color: var(--ink-faint);
493
- cursor: pointer;
494
- background: transparent;
495
- border: 0;
496
- border-radius: var(--radius-chip);
497
- transition: background var(--transition-fast), color var(--transition-fast);
498
- }
499
- .head-op:hover { color: var(--ink); background: var(--paper-deep); }
500
- .empty {
501
- padding: 14px 10px;
502
- font-size: 12px;
503
- color: var(--ink-faint);
504
- }
505
- .channel-item {
506
- padding: 7px 9px;
507
- margin: 1px 0;
508
- cursor: pointer;
509
- border-radius: var(--radius-panel-sm);
510
- transition: background var(--transition-fast);
511
- }
512
- .channel-item:hover { background: var(--paper-deep); }
513
- .channel-item.active { background: var(--paper-deep); box-shadow: inset 2px 0 0 var(--accent); }
514
- .row1 {
515
- display: flex;
516
- gap: 7px;
517
- align-items: center;
518
- font-size: 13px;
519
- color: var(--ink-soft);
520
- }
521
- .channel-item.active .row1 { color: var(--ink); font-weight: 500; }
522
- .dot {
523
- flex: 0 0 auto;
524
- width: 7px;
525
- height: 7px;
526
- background: var(--tone-neutral-dot);
527
- opacity: 0.55;
528
- border-radius: 50%;
529
- }
530
- .dot.live {
531
- background: var(--tone-success-dot);
532
- opacity: 1;
533
- }
534
- .ch-name {
535
- flex: 1 1 auto;
536
- overflow: hidden;
537
- text-overflow: ellipsis;
538
- white-space: nowrap;
539
- }
540
- .op {
541
- display: inline-flex;
542
- flex: 0 0 auto;
543
- align-items: center;
544
- justify-content: center;
545
- width: 20px;
546
- height: 20px;
547
- padding: 0;
548
- font-size: 13px;
549
- color: var(--ink-fainter);
550
- cursor: pointer;
551
- background: transparent;
552
- border: 0;
553
- border-radius: var(--radius-chip);
554
- /* 常显(低透明度):不再 hover-only——行级操作入口不应时隐时现 */
555
- opacity: 0.55;
556
- transition: opacity var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
557
- }
558
- .channel-item:hover .op,
559
- .channel-item.active .op { opacity: 0.9; }
560
- .op:hover { opacity: 1; color: var(--ink); background: var(--paper-deep); }
561
- .op:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
562
- .row2 { padding-left: 14px; font-size: 11px; color: var(--ink-faint); }
563
- .meta.syncing { font-style: italic; opacity: 0.6; }
564
- .row2.ws {
565
- display: flex;
566
- gap: 4px;
567
- align-items: center;
568
- overflow: hidden;
569
- max-width: 100%;
570
- padding: 0 2px 0 14px;
571
- font-family: var(--font-mono);
572
- font-size: 11px;
573
- text-overflow: ellipsis;
574
- white-space: nowrap;
575
- color: var(--ink-fainter);
576
- text-align: left;
577
- cursor: copy; /* 点击复制完整路径(title 提示) */
578
- background: transparent;
579
- border: 0;
580
- border-radius: var(--radius-chip);
581
- transition: color var(--transition-fast), background var(--transition-fast);
582
- }
583
- .row2.ws:hover { color: var(--ink-soft); background: color-mix(in srgb, currentColor 6%, transparent); }
584
- .row2.ws:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
585
- .mount-template { padding: 12px 6px 6px; border-top: 1px solid var(--line); margin-top: 10px; }
586
- .select { width: 100%; }
587
- .tpl-hint {
588
- padding: 5px 2px 0;
589
- font-size: 10.5px;
590
- color: var(--ink-fainter);
591
- }
592
- .ws-hint { font-size: 11px; color: var(--ink-faint); }
593
- </style>
1
+ <script setup lang="ts">
2
+ /**
3
+ * 左栏 Channel 会话列表(Zcode session 栏):workspace 内挂载的 channel,
4
+ * 实时状态徽标(忙碌成员数/活跃任务数),点击聚焦;挂载/移出/设置操作。
5
+ * v10 模板化:
6
+ * - 「从模板挂载」:选择 Channel 模板 → 实例化 + 挂载一步完成(替代"挂载已有 Channel");
7
+ * - 「设置」:热修改当前 Channel 实例的场景描述与工作目录(成员运行时自动回收重装配);
8
+ * - 「保存为模板」:把当前 Channel 实例捕获为可复用模板(场景/目录/团队快照)。
9
+ */
10
+ import { message } from 'ant-design-vue'
11
+ import { useWorkspacesStore } from '@/app/stores/workshop/workspaces'
12
+ import { useEntitiesStore } from '@/app/stores/workshop/entities'
13
+ import { useWorkshopApi, type ChannelDto, type ChannelTemplateDto } from '@/app/composables/workshop/useWorkshopApi'
14
+
15
+ const { t } = useI18n()
16
+
17
+ const props = defineProps<{ wsId: string }>()
18
+ const wsStore = useWorkspacesStore()
19
+ const entities = useEntitiesStore()
20
+ const api = useWorkshopApi()
21
+
22
+ const workspace = computed(() => wsStore.workspaces.find(w => w.id === props.wsId))
23
+
24
+ const channels = ref<ChannelDto[]>([])
25
+ const channelTemplates = ref<ChannelTemplateDto[]>([])
26
+ const refreshChannels = async (): Promise<void> => {
27
+ // SSR 守卫:axios 相对 baseURL 仅客户端有效(服务端拉取会 Invalid URL)
28
+ if (typeof window === 'undefined') return
29
+ const [ch, tpl] = await Promise.all([
30
+ api.listChannels(),
31
+ api.listChannelTemplates().catch(() => null),
32
+ ])
33
+ channels.value = (ch as unknown as { data?: ChannelDto[] })?.data ?? []
34
+ channelTemplates.value = (tpl as unknown as { data?: ChannelTemplateDto[] } | null)?.data ?? []
35
+ }
36
+ void refreshChannels()
37
+
38
+ const mountedChannels = computed(() =>
39
+ (workspace.value?.channelIds ?? [])
40
+ .map(id => ({ id, meta: channels.value.find(c => c.id === id), entity: entities.channels[id] }))
41
+ .map(({ id, meta, entity }) => ({
42
+ id,
43
+ name: entity?.name ?? meta?.name ?? id.slice(0, 8),
44
+ /** 实体基线(WS 快照)是否已到达:未到时计数不可信,展示"同步中"而非误导性的 0 */
45
+ synced: entity !== undefined,
46
+ busy: entities.busyCount(id),
47
+ agents: entities.agents[id]?.length ?? 0,
48
+ activeTasks: (entities.tasks[id] ?? []).filter(t => !['COMPLETED', 'CANCELED', 'FAILED'].includes(t.state)).length,
49
+ workspace: meta?.workspace ?? '',
50
+ })),
51
+ )
52
+
53
+ const select = (channelId: string): void => {
54
+ wsStore.setActiveChannel(props.wsId, channelId)
55
+ }
56
+
57
+ /** 点击工作目录行:复制完整路径到剪贴板(有真实作用;title 提示全路径) */
58
+ const copyWorkspace = async (path: string): Promise<void> => {
59
+ try {
60
+ await navigator.clipboard.writeText(path)
61
+ message.success(t('channelSessionList.kud74vg040', { p0: path }))
62
+ }
63
+ catch {
64
+ message.error(t('channelSessionList.krij3gg026'))
65
+ }
66
+ }
67
+ /** 路径显示 basename(E:\codes\AgentWorkShop → AgentWorkShop),全路径在 title/复制 */
68
+ const baseName = (path: string): string => path.replace(/[\\/]+$/, '').split(/[\\/]/).pop() ?? path
69
+ /** 默认目录(data/workspaces/<uuid>)的 basename 是 36 位裸 UUID,对用户零信息量 → 不展示该行 */
70
+ const UUID_RE = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i
71
+ const displayWorkspace = (path: string): string => {
72
+ const base = baseName(path)
73
+ return UUID_RE.test(base) ? '' : base
74
+ }
75
+
76
+ // ===== 新建 Channel 并挂载(空团队) =====
77
+ const mountModal = ref(false)
78
+ const mountForm = reactive({ name: '', description: '', workspace: '', scenarioPrompt: '' })
79
+ const mountSubmitting = ref(false)
80
+ /** FileSelector 弹窗(选择服务器目录作为 workspace) */
81
+ const fileSelectorOpen = ref(false)
82
+ const createAndMount = async (): Promise<void> => {
83
+ if (!mountForm.name.trim()) {
84
+ message.warning('Channel 名称必填')
85
+ return
86
+ }
87
+ mountSubmitting.value = true
88
+ try {
89
+ const res = await api.createChannel({
90
+ name: mountForm.name.trim(),
91
+ description: mountForm.description || undefined,
92
+ scenarioPrompt: mountForm.scenarioPrompt.trim() || undefined,
93
+ workspace: mountForm.workspace.trim() || undefined,
94
+ })
95
+ const created = (res as unknown as { data?: { channelId?: string } })?.data
96
+ const channelId = created?.channelId
97
+ if (!channelId) throw new Error(t('channelSessionList.k1bg6shc027'))
98
+ await wsStore.mountChannel(props.wsId, channelId)
99
+ mountModal.value = false
100
+ mountForm.name = ''
101
+ mountForm.description = ''
102
+ mountForm.workspace = ''
103
+ mountForm.scenarioPrompt = ''
104
+ void refreshChannels()
105
+ message.success(t('channelSessionList.kn89jvs028'))
106
+ }
107
+ catch (e) {
108
+ message.error(t('channelSessionList.k1x2th9e041', { p0: e instanceof Error ? e.message : String(e) }))
109
+ }
110
+ finally {
111
+ mountSubmitting.value = false
112
+ }
113
+ }
114
+
115
+ // ===== 从 Channel 模板挂载(实例化 + mount 一步) =====
116
+ const templateMountId = ref<string | undefined>()
117
+ const templateMounting = ref(false)
118
+ const mountFromTemplate = async (): Promise<void> => {
119
+ if (!templateMountId.value) return
120
+ templateMounting.value = true
121
+ try {
122
+ const res = await api.mountChannelTemplate(props.wsId, templateMountId.value)
123
+ const data = (res as unknown as { data?: { agentCount?: number } })?.data
124
+ message.success(t('channelSessionList.kai50qc042', { p0: data?.agentCount ?? 0 }))
125
+ templateMountId.value = undefined
126
+ void refreshChannels()
127
+ }
128
+ catch (e) {
129
+ const err = e as { data?: { message?: string }, message?: string }
130
+ message.error(err?.data?.message ?? err?.message ?? t('channelSessionList.k97xi7u029'))
131
+ }
132
+ finally {
133
+ templateMounting.value = false
134
+ }
135
+ }
136
+
137
+ const unmount = (channelId: string): void => {
138
+ wsStore.unmountChannel(props.wsId, channelId)
139
+ .catch((e: { data?: { message?: string }, message?: string }) => { message.error(e?.data?.message ?? e?.message ?? t('channelSessionList.k1hgfvdc030')) })
140
+ }
141
+
142
+ // ===== Channel 实例设置(场景/工作目录热更新)+ 保存为模板 =====
143
+ const settingsOpen = ref(false)
144
+ const settingsChannelId = ref<string>('')
145
+ const settingsForm = reactive({ name: '', scenarioPrompt: '', workspace: '' })
146
+
147
+ // ===== Channel 级默认 LLM(harness → provider/model/effort;空 = 用引擎默认) =====
148
+ interface CatalogProvider {
149
+ id: string
150
+ models: Array<{ id: string, efforts: string[], defaultEffort?: string }>
151
+ }
152
+ const llmForm = reactive({ harness: 'omp', provider: '', model: '', effort: '', enabled: false })
153
+ const llmProviders = ref<CatalogProvider[]>([])
154
+ const llmEffortMode = ref<'levels' | 'freetext' | 'unsupported'>('levels')
155
+ const llmLoading = ref(false)
156
+ const llmProviderOptions = computed(() => llmProviders.value.map(p => ({ value: p.id, label: p.id })))
157
+ const llmModelOptions = computed(() =>
158
+ (llmProviders.value.find(p => p.id === llmForm.provider)?.models ?? []).map(m => ({ value: m.id, label: m.id })),
159
+ )
160
+ const llmEffortOptions = computed(() => {
161
+ const m = llmProviders.value.find(p => p.id === llmForm.provider)?.models.find(x => x.id === llmForm.model)
162
+ return (m?.efforts ?? []).map(e => ({ value: e, label: e + (m?.defaultEffort === e ? '(默认)' : '') }))
163
+ })
164
+ const loadLlmCatalog = async (harness: string): Promise<void> => {
165
+ llmLoading.value = true
166
+ llmProviders.value = []
167
+ try {
168
+ const res = await api.listHarnessProviders(harness)
169
+ const cat = (res as unknown as { data?: { catalog?: { providers?: CatalogProvider[], effortMode?: 'levels' | 'freetext' | 'unsupported' } } })?.data?.catalog
170
+ llmProviders.value = cat?.providers ?? []
171
+ llmEffortMode.value = cat?.effortMode ?? 'unsupported'
172
+ }
173
+ catch { /* 目录拉取失败保留空表 */ }
174
+ finally { llmLoading.value = false }
175
+ }
176
+ const onLlmHarnessChange = async (): Promise<void> => {
177
+ llmForm.provider = ''
178
+ llmForm.model = ''
179
+ llmForm.effort = ''
180
+ await loadLlmCatalog(llmForm.harness)
181
+ }
182
+ const onLlmProviderChange = (): void => {
183
+ llmForm.model = ''
184
+ llmForm.effort = ''
185
+ }
186
+ const onLlmModelChange = (): void => {
187
+ llmForm.effort = ''
188
+ }
189
+ const settingsSaving = ref(false)
190
+ const fileSelectorOpen2 = ref(false)
191
+ const openSettings = (channelId: string): void => {
192
+ const meta = channels.value.find(c => c.id === channelId)
193
+ settingsChannelId.value = channelId
194
+ settingsForm.name = meta?.name ?? ''
195
+ settingsForm.scenarioPrompt = meta?.scenarioPrompt ?? ''
196
+ settingsForm.workspace = meta?.workspace ?? ''
197
+ // 预填 channel 默认 LLM(llmJson 由列表接口透传)
198
+ let saved: { provider?: string, model?: string, effort?: string } | null = null
199
+ try {
200
+ const metaAny = meta as unknown as { llmJson?: string } | undefined
201
+ saved = metaAny?.llmJson ? JSON.parse(metaAny.llmJson) as typeof saved : null
202
+ }
203
+ catch { saved = null }
204
+ llmForm.enabled = !!saved?.model
205
+ llmForm.harness = 'omp'
206
+ llmForm.provider = saved?.provider ?? ''
207
+ llmForm.model = saved?.model ?? ''
208
+ llmForm.effort = saved?.effort ?? ''
209
+ settingsOpen.value = true
210
+ if (llmForm.enabled) void loadLlmCatalog(llmForm.harness)
211
+ }
212
+ const saveSettings = async (): Promise<void> => {
213
+ settingsSaving.value = true
214
+ try {
215
+ await api.patchChannel(settingsChannelId.value, {
216
+ scenarioPrompt: settingsForm.scenarioPrompt,
217
+ workspace: settingsForm.workspace.trim() || undefined,
218
+ llm: llmForm.enabled && llmForm.model
219
+ ? { ...(llmForm.provider ? { provider: llmForm.provider } : {}), model: llmForm.model, ...(llmForm.effort ? { effort: llmForm.effort } : {}) }
220
+ : null,
221
+ })
222
+ message.success(t('channelSessionList.kvsxlu6031'))
223
+ settingsOpen.value = false
224
+ void refreshChannels()
225
+ }
226
+ catch (e) {
227
+ message.error(e instanceof Error ? e.message : String(e))
228
+ }
229
+ finally {
230
+ settingsSaving.value = false
231
+ }
232
+ }
233
+
234
+ // 保存为模板(捕获当前 channel 的场景/目录/团队)
235
+ const saveTplOpen = ref(false)
236
+ const saveTplForm = reactive({ name: '', description: '', visibility: 'private' as 'private' | 'public' })
237
+ const saveTplSubmitting = ref(false)
238
+ const openSaveTemplate = (): void => {
239
+ saveTplForm.name = t('channelSessionList.k2hfym5043', { p0: settingsForm.name || 'channel' })
240
+ saveTplForm.description = ''
241
+ saveTplForm.visibility = 'private'
242
+ saveTplOpen.value = true
243
+ }
244
+ const saveAsTemplate = async (): Promise<void> => {
245
+ if (!saveTplForm.name.trim()) {
246
+ message.warning(t('channelSessionList.k1i0ji0y032'))
247
+ return
248
+ }
249
+ saveTplSubmitting.value = true
250
+ try {
251
+ await api.captureChannelTemplate({
252
+ channelId: settingsChannelId.value,
253
+ name: saveTplForm.name.trim(),
254
+ description: saveTplForm.description || undefined,
255
+ visibility: saveTplForm.visibility,
256
+ })
257
+ message.success(t('channelSessionList.kjpguxw033'))
258
+ saveTplOpen.value = false
259
+ void refreshChannels()
260
+ }
261
+ catch (e) {
262
+ message.error(e instanceof Error ? e.message : String(e))
263
+ }
264
+ finally {
265
+ saveTplSubmitting.value = false
266
+ }
267
+ }
268
+ </script>
269
+
270
+ <template>
271
+ <div class="channel-list">
272
+ <div class="list-head">
273
+ <span class="title">Channels</span>
274
+ <span class="head-actions">
275
+ <button
276
+ class="head-op im"
277
+ type="button"
278
+ title="Channel 模板中心"
279
+ @click="navigateTo('/workshop/channel-templates')"
280
+ >
281
+ <span class="i-tabler-layout-grid-add im-pop" />
282
+ </button>
283
+ <button
284
+ class="head-op im"
285
+ type="button"
286
+ title="新建 Channel"
287
+ @click="mountModal = true"
288
+ >
289
+ <span class="i-tabler-plus im-pop" />
290
+ </button>
291
+ </span>
292
+ </div>
293
+
294
+ <!-- 频道列表主体:数据源(REST channels + WS entities)均为客户端态,
295
+ SSR 首帧为空 → 硬刷新水合时结构与客户端首渲染不一致,节点会错配到
296
+ 相邻 antd Select 的 DOM 上(行内 .row1 布局丢失、按钮错位)。
297
+ ClientOnly 隔离:SSR 输出空壳,客户端一次性渲染,无水合配对。 -->
298
+ <ClientOnly>
299
+ <div
300
+ v-if="mountedChannels.length === 0"
301
+ class="empty"
302
+ >
303
+ {{ $t('channelSessionList.kkv789s014') }}
304
+ </div>
305
+
306
+ <div
307
+ v-for="ch in mountedChannels"
308
+ :key="ch.id"
309
+ class="channel-item"
310
+ :class="{ active: workspace?.activeChannelId === ch.id }"
311
+ @click="select(ch.id)"
312
+ >
313
+ <div class="row1">
314
+ <span
315
+ class="dot"
316
+ :class="{ live: ch.activeTasks > 0 }"
317
+ />
318
+ <span class="ch-name">{{ ch.name }}</span>
319
+ <button
320
+ class="op im"
321
+ type="button"
322
+ :title="$t('channelSessionList.kne35ug001')"
323
+ :aria-label="$t('channelSessionList.kjmldih035', { p0: ch.name })"
324
+ @click.stop="openSettings(ch.id)"
325
+ >
326
+ <span class="i-tabler-settings2 im-pop" />
327
+ </button>
328
+ <button
329
+ class="op im"
330
+ type="button"
331
+ title="移出 workspace"
332
+ :aria-label="$t('channelSessionList.k1yurooi036', { p0: ch.name })"
333
+ @click.stop="unmount(ch.id)"
334
+ >
335
+ <span class="i-tabler-x im-pop" />
336
+ </button>
337
+ </div>
338
+ <div class="row2">
339
+ <!-- 快照未到达:计数不可信,显示同步占位(不呈现误导性的"0 成员") -->
340
+ <span
341
+ v-if="!ch.synced"
342
+ class="meta syncing"
343
+ >{{ $t('channelSessionList.k1bst7s9015') }}</span>
344
+ <span
345
+ v-else
346
+ class="meta"
347
+ >{{ ch.agents }} {{ $t('channelSessionList.k1ggoa45025') }} {{ ch.busy }} / {{ $t('channelSessionList.k3wcox034') }} {{ ch.activeTasks }}</span>
348
+ </div>
349
+ <button
350
+ v-if="displayWorkspace(ch.workspace)"
351
+ class="row2 ws im"
352
+ type="button"
353
+ :title="$t('channelSessionList.kfe4pzq037', { p0: ch.workspace })"
354
+ @click.stop="copyWorkspace(ch.workspace)"
355
+ >
356
+ <span class="i-tabler-folder" /> {{ displayWorkspace(ch.workspace) }}
357
+ </button>
358
+ </div>
359
+ </ClientOnly>
360
+
361
+ <div class="mount-template">
362
+ <a-select
363
+ v-model:value="templateMountId"
364
+ size="small"
365
+ :placeholder="'从 Channel 模板挂载'"
366
+ class="select"
367
+ :loading="templateMounting"
368
+ :options="channelTemplates.map(t => ({
369
+ value: t.id,
370
+ label: $t('channelSessionList.k1oes209038', { p0: t.isBuiltin ? '内置 · ' : t.visibility === 'public' ? '公开 · ' : '', p1: t.name, p2: (t.lead ? 1 : 0) + t.members.length }),
371
+ }))"
372
+ @change="mountFromTemplate"
373
+ />
374
+ <div class="tpl-hint">
375
+ {{ $t('channelSessionList.k18ppu31016') }}
376
+ </div>
377
+ </div>
378
+
379
+ <a-modal
380
+ v-model:open="mountModal"
381
+ :title="$t('channelSessionList.k1qjyl6l002')"
382
+ :confirm-loading="mountSubmitting"
383
+ ok-text="创建"
384
+ cancel-text="取消"
385
+ @ok="createAndMount"
386
+ >
387
+ <a-form layout="vertical">
388
+ <a-form-item label="Channel 名称">
389
+ <a-input v-model:value="mountForm.name" />
390
+ </a-form-item>
391
+ <a-form-item :label="$t('channelSessionList.k40gkk003')">
392
+ <a-input v-model:value="mountForm.description" />
393
+ </a-form-item>
394
+ <a-form-item :label="$t('channelSessionList.k1wj4f38004')">
395
+ <a-textarea
396
+ v-model:value="mountForm.scenarioPrompt"
397
+ :rows="4"
398
+ :placeholder="$t('channelSessionList.k1098zie005')"
399
+ />
400
+ <template #extra>
401
+ <span class="ws-hint">{{ $t('channelSessionList.k1u3zsr5017') }}</span>
402
+ </template>
403
+ </a-form-item>
404
+ <a-form-item :label="$t('channelSessionList.kmgv4h5006')">
405
+ <a-input-group compact>
406
+ <a-input
407
+ v-model:value="mountForm.workspace"
408
+ style="width: 70%"
409
+ placeholder="留空 = data/workspaces/<channelId>"
410
+ allow-clear
411
+ @press-enter="createAndMount"
412
+ />
413
+ <a-button
414
+ style="width: 30%"
415
+ @click="fileSelectorOpen = true"
416
+ >
417
+ {{ $t('channelSessionList.k3pz0ma018') }}
418
+ </a-button>
419
+ </a-input-group>
420
+ <template #extra>
421
+ <span class="ws-hint">{{ $t('channelSessionList.kucq30k019') }}</span>
422
+ </template>
423
+ </a-form-item>
424
+ <a-form-item>
425
+ <span class="ws-hint">{{ $t('channelSessionList.k1ful761020') }}</span>
426
+ </a-form-item>
427
+ </a-form>
428
+ </a-modal>
429
+
430
+ <!-- Channel 实例设置:场景/工作目录热更新 + 保存为模板 -->
431
+ <a-modal
432
+ v-model:open="settingsOpen"
433
+ :title="$t('channelSessionList.k1pmemvt039', { p0: settingsForm.name })"
434
+ :confirm-loading="settingsSaving"
435
+ ok-text="保存"
436
+ cancel-text="取消"
437
+ @ok="saveSettings"
438
+ >
439
+ <a-form layout="vertical">
440
+ <a-form-item :label="$t('channelSessionList.k1i8q46x007')">
441
+ <a-textarea
442
+ v-model:value="settingsForm.scenarioPrompt"
443
+ :rows="4"
444
+ :placeholder="$t('channelSessionList.ku3ugac008')"
445
+ />
446
+ </a-form-item>
447
+ <a-form-item :label="$t('channelSessionList.k67dzev009')">
448
+ <a-input-group compact>
449
+ <a-input
450
+ v-model:value="settingsForm.workspace"
451
+ style="width: 70%"
452
+ placeholder="data/workspaces/<channelId>"
453
+ allow-clear
454
+ />
455
+ <a-button
456
+ style="width: 30%"
457
+ @click="fileSelectorOpen2 = true"
458
+ >
459
+ {{ $t('channelSessionList.k3pz0ma018') }}
460
+ </a-button>
461
+ </a-input-group>
462
+ </a-form-item>
463
+ <a-form-item label="默认模型(可选;留空用各 Harness 默认)">
464
+ <a-space>
465
+ <a-switch
466
+ v-model:checked="llmForm.enabled"
467
+ size="small"
468
+ @change="(v: any) => { if (v) void loadLlmCatalog(llmForm.harness) }"
469
+ />
470
+ <a-select
471
+ v-model:value="llmForm.harness"
472
+ style="width: 130px"
473
+ :options="[{ value: 'omp', label: 'omp' }, { value: 'codex', label: 'codex' }, { value: 'opencode', label: 'opencode' }, { value: 'dsh', label: 'dsh' }]"
474
+ :disabled="!llmForm.enabled"
475
+ @change="onLlmHarnessChange"
476
+ />
477
+ <a-select
478
+ v-model:value="llmForm.provider"
479
+ style="width: 170px"
480
+ :placeholder="llmLoading ? '目录加载中…' : 'provider'"
481
+ :options="llmProviderOptions"
482
+ :disabled="!llmForm.enabled || llmLoading"
483
+ show-search
484
+ @change="onLlmProviderChange"
485
+ />
486
+ <a-select
487
+ v-model:value="llmForm.model"
488
+ style="width: 210px"
489
+ placeholder="model"
490
+ :options="llmModelOptions"
491
+ :disabled="!llmForm.enabled || !llmForm.provider"
492
+ show-search
493
+ @change="onLlmModelChange"
494
+ />
495
+ <a-select
496
+ v-if="llmEffortMode === 'levels'"
497
+ v-model:value="llmForm.effort"
498
+ style="width: 130px"
499
+ placeholder="effort(可选)"
500
+ :options="llmEffortOptions"
501
+ :disabled="!llmForm.enabled || !llmForm.model"
502
+ allow-clear
503
+ />
504
+ <a-input
505
+ v-else-if="llmEffortMode === 'freetext'"
506
+ v-model:value="llmForm.effort"
507
+ style="width: 130px"
508
+ placeholder="variant(可选)"
509
+ :disabled="!llmForm.enabled || !llmForm.model"
510
+ allow-clear
511
+ />
512
+ </a-space>
513
+ </a-form-item>
514
+ <a-form-item>
515
+ <a-button
516
+ size="small"
517
+ @click="openSaveTemplate"
518
+ >
519
+ <span class="i-tabler-template" />
520
+ {{ $t('channelSessionList.k6kpql010') }}
521
+ </a-button>
522
+ <span class="ws-hint">{{ $t('channelSessionList.k1x6kznr021') }}</span>
523
+ </a-form-item>
524
+ </a-form>
525
+ </a-modal>
526
+
527
+ <!-- 保存为模板 -->
528
+ <a-modal
529
+ v-model:open="saveTplOpen"
530
+ :title="$t('channelSessionList.k6kpql010')"
531
+ :confirm-loading="saveTplSubmitting"
532
+ ok-text="保存模板"
533
+ cancel-text="取消"
534
+ @ok="saveAsTemplate"
535
+ >
536
+ <a-form layout="vertical">
537
+ <a-form-item :label="$t('channelSessionList.k1f55q76011')">
538
+ <a-input v-model:value="saveTplForm.name" />
539
+ </a-form-item>
540
+ <a-form-item :label="$t('channelSessionList.k40gkk003')">
541
+ <a-input v-model:value="saveTplForm.description" />
542
+ </a-form-item>
543
+ <a-form-item :label="$t('channelSessionList.k3lrqn0012')">
544
+ <a-radio-group v-model:value="saveTplForm.visibility">
545
+ <a-radio value="private">
546
+ {{ $t('channelSessionList.k1otvrfv022') }}
547
+ </a-radio>
548
+ <a-radio value="public">
549
+ {{ $t('channelSessionList.k1cc399s023') }}
550
+ </a-radio>
551
+ </a-radio-group>
552
+ </a-form-item>
553
+ <a-form-item>
554
+ <span class="ws-hint">{{ $t('channelSessionList.kl9btf7024') }}</span>
555
+ </a-form-item>
556
+ </a-form>
557
+ </a-modal>
558
+
559
+ <!-- FileSelector:服务器目录选择 -> 回填工作目录 -->
560
+ <workshop-file-selector-modal
561
+ v-model:open="fileSelectorOpen"
562
+ :title="$t('channelSessionList.kbdp56k013')"
563
+ :initial-path="mountForm.workspace || undefined"
564
+ @select="(p) => { mountForm.workspace = p }"
565
+ />
566
+ <workshop-file-selector-modal
567
+ v-model:open="fileSelectorOpen2"
568
+ :title="$t('channelSessionList.kbdp56k013')"
569
+ :initial-path="settingsForm.workspace || undefined"
570
+ @select="(p) => { settingsForm.workspace = p }"
571
+ />
572
+ </div>
573
+ </template>
574
+
575
+ <style scoped>
576
+ .channel-list {
577
+ display: flex;
578
+ flex-direction: column;
579
+ min-height: 100%;
580
+ padding: 12px 10px 8px;
581
+ }
582
+ .list-head {
583
+ display: flex;
584
+ align-items: center;
585
+ justify-content: space-between;
586
+ padding: 0 8px 8px;
587
+ }
588
+ .title {
589
+ font-family: var(--font-display);
590
+ font-size: 16px;
591
+ letter-spacing: -0.01em;
592
+ color: var(--ink);
593
+ }
594
+ .head-actions { display: inline-flex; gap: 2px; }
595
+ .head-op {
596
+ display: inline-flex;
597
+ align-items: center;
598
+ justify-content: center;
599
+ width: 24px;
600
+ height: 24px;
601
+ font-size: 14px;
602
+ color: var(--ink-faint);
603
+ cursor: pointer;
604
+ background: transparent;
605
+ border: 0;
606
+ border-radius: var(--radius-chip);
607
+ transition: background var(--transition-fast), color var(--transition-fast);
608
+ }
609
+ .head-op:hover { color: var(--ink); background: var(--paper-deep); }
610
+ .empty {
611
+ padding: 14px 10px;
612
+ font-size: 12px;
613
+ color: var(--ink-faint);
614
+ }
615
+ .channel-item {
616
+ padding: 7px 9px;
617
+ margin: 1px 0;
618
+ cursor: pointer;
619
+ border-radius: var(--radius-panel-sm);
620
+ transition: background var(--transition-fast);
621
+ }
622
+ .channel-item:hover { background: var(--paper-deep); }
623
+ .channel-item.active { background: var(--paper-deep); box-shadow: inset 2px 0 0 var(--accent); }
624
+ .row1 {
625
+ display: flex;
626
+ gap: 7px;
627
+ align-items: center;
628
+ font-size: 13px;
629
+ color: var(--ink-soft);
630
+ }
631
+ .channel-item.active .row1 { color: var(--ink); font-weight: 500; }
632
+ .dot {
633
+ flex: 0 0 auto;
634
+ width: 7px;
635
+ height: 7px;
636
+ background: var(--tone-neutral-dot);
637
+ opacity: 0.55;
638
+ border-radius: 50%;
639
+ }
640
+ .dot.live {
641
+ background: var(--tone-success-dot);
642
+ opacity: 1;
643
+ }
644
+ .ch-name {
645
+ flex: 1 1 auto;
646
+ overflow: hidden;
647
+ text-overflow: ellipsis;
648
+ white-space: nowrap;
649
+ }
650
+ .op {
651
+ display: inline-flex;
652
+ flex: 0 0 auto;
653
+ align-items: center;
654
+ justify-content: center;
655
+ width: 20px;
656
+ height: 20px;
657
+ padding: 0;
658
+ font-size: 13px;
659
+ color: var(--ink-fainter);
660
+ cursor: pointer;
661
+ background: transparent;
662
+ border: 0;
663
+ border-radius: var(--radius-chip);
664
+ /* 常显(低透明度):不再 hover-only——行级操作入口不应时隐时现 */
665
+ opacity: 0.55;
666
+ transition: opacity var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
667
+ }
668
+ .channel-item:hover .op,
669
+ .channel-item.active .op { opacity: 0.9; }
670
+ .op:hover { opacity: 1; color: var(--ink); background: var(--paper-deep); }
671
+ .op:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
672
+ .row2 { padding-left: 14px; font-size: 11px; color: var(--ink-faint); }
673
+ .meta.syncing { font-style: italic; opacity: 0.6; }
674
+ .row2.ws {
675
+ display: flex;
676
+ gap: 4px;
677
+ align-items: center;
678
+ overflow: hidden;
679
+ max-width: 100%;
680
+ padding: 0 2px 0 14px;
681
+ font-family: var(--font-mono);
682
+ font-size: 11px;
683
+ text-overflow: ellipsis;
684
+ white-space: nowrap;
685
+ color: var(--ink-fainter);
686
+ text-align: left;
687
+ cursor: copy; /* 点击复制完整路径(title 提示) */
688
+ background: transparent;
689
+ border: 0;
690
+ border-radius: var(--radius-chip);
691
+ transition: color var(--transition-fast), background var(--transition-fast);
692
+ }
693
+ .row2.ws:hover { color: var(--ink-soft); background: color-mix(in srgb, currentColor 6%, transparent); }
694
+ .row2.ws:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
695
+ .mount-template { padding: 12px 6px 6px; border-top: 1px solid var(--line); margin-top: 10px; }
696
+ .select { width: 100%; }
697
+ .tpl-hint {
698
+ padding: 5px 2px 0;
699
+ font-size: 10.5px;
700
+ color: var(--ink-fainter);
701
+ }
702
+ .ws-hint { font-size: 11px; color: var(--ink-faint); }
703
+ </style>