agentworkshop 0.7.41 → 0.7.44

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 (265) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/B8uy9iRW.js +1 -0
  3. package/.output/public/_nuxt/BGTYYQH-.js +1 -0
  4. package/.output/public/_nuxt/BUmHEJ77.js +2 -0
  5. package/.output/public/_nuxt/BY7YrV_D.js +1 -0
  6. package/.output/public/_nuxt/Bqcgz95s.js +18 -0
  7. package/.output/public/_nuxt/C7UlqPeD.js +1 -0
  8. package/.output/public/_nuxt/CTmDn-YP.js +1 -0
  9. package/.output/public/_nuxt/Cs8pVeVG.js +1 -0
  10. package/.output/public/_nuxt/DKySmNPI.js +14 -0
  11. package/.output/public/_nuxt/Di0NY_ht.js +1 -0
  12. package/.output/public/_nuxt/Du9v6qGB.js +1 -0
  13. package/.output/public/_nuxt/{DGbd-UiG.js → EHlEMRii.js} +1 -1
  14. package/.output/public/_nuxt/Eke1fs-U.js +1 -0
  15. package/.output/public/_nuxt/{DeJykBFf.js → H0BcqZtT.js} +1 -1
  16. package/.output/public/_nuxt/{C4oW1HsE.js → HSYEkkce.js} +1 -1
  17. package/.output/public/_nuxt/{D_OTvQza.js → J9oU00D1.js} +1 -1
  18. package/.output/public/_nuxt/OmpTerminalPanel.BxR5-lvi.css +1 -0
  19. package/.output/public/_nuxt/SSyAPaHc.js +1 -0
  20. package/.output/public/_nuxt/TownView.li4EMQxK.css +1 -0
  21. package/.output/public/_nuxt/VdLk4jLE2.js +1 -0
  22. package/.output/public/_nuxt/_id_.BhsXoEuk.css +1 -0
  23. package/.output/public/_nuxt/_id_.DQyj-WKN.css +1 -0
  24. package/.output/public/_nuxt/{_wsId_.B4WiqkIS.css → _wsId_.CTx-BlfF.css} +1 -1
  25. package/.output/public/_nuxt/aShsv_rG.js +19 -0
  26. package/.output/public/_nuxt/{yF0aYMF1.js → aesgXKSr.js} +3 -3
  27. package/.output/public/_nuxt/agents.B21nUEUX.css +1 -0
  28. package/.output/public/_nuxt/aml.ekTjxFkf.css +1 -0
  29. package/.output/public/_nuxt/builds/latest.json +1 -1
  30. package/.output/public/_nuxt/builds/meta/b5506ef0-f48e-4f14-a6c0-d65e505d0b09.json +1 -0
  31. package/.output/public/_nuxt/channel-templates.DplM1pJ3.css +1 -0
  32. package/.output/public/_nuxt/daq.BdVmoIfe.css +1 -0
  33. package/.output/public/_nuxt/dcw.DCgyzpWV.css +1 -0
  34. package/.output/public/_nuxt/{default.J32SgqFY.css → default.Bh3L2HU8.css} +1 -1
  35. package/.output/public/_nuxt/lHAxdSsj.js +1 -0
  36. package/.output/public/_nuxt/pages.j9rzRocr.css +1 -0
  37. package/.output/public/_nuxt/plugins.DhiZbHU8.css +1 -0
  38. package/.output/public/_nuxt/settings.BRx9rIDg.css +1 -0
  39. package/.output/public/_nuxt/teams.BLlOPB_Z.css +1 -0
  40. package/.output/public/_nuxt/tokens.De8xzszn.css +1 -0
  41. package/.output/public/_nuxt/workshop.D1jFNkrn.css +1 -0
  42. package/.output/server/chunks/_/nitro.mjs +748 -733
  43. package/.output/server/chunks/build/{OmpTerminalPanel-Cu_s4i0A.mjs → OmpTerminalPanel-CVvxpsF7.mjs} +15 -15
  44. package/.output/server/chunks/build/{OmpTerminalPanel-Cu_s4i0A.mjs.map → OmpTerminalPanel-CVvxpsF7.mjs.map} +1 -1
  45. package/.output/server/chunks/build/{TownView--otsnr_7.mjs → TownView-CJ6IsDCc.mjs} +226 -225
  46. package/.output/server/chunks/build/{TownView--otsnr_7.mjs.map → TownView-CJ6IsDCc.mjs.map} +1 -1
  47. package/.output/server/chunks/build/{_id_-Brv-JSvr.mjs → _id_-CVD_H0ir.mjs} +143 -142
  48. package/.output/server/chunks/build/_id_-CVD_H0ir.mjs.map +1 -0
  49. package/.output/server/chunks/build/{_id_-D9pl1OZy.mjs → _id_-CtxMb3qp.mjs} +41 -41
  50. package/.output/server/chunks/build/_id_-CtxMb3qp.mjs.map +1 -0
  51. package/.output/server/chunks/build/{_wsId_-BASfDf0s.mjs → _wsId_-DpY3T-md.mjs} +514 -444
  52. package/.output/server/chunks/build/{_wsId_-BASfDf0s.mjs.map → _wsId_-DpY3T-md.mjs.map} +1 -1
  53. package/.output/server/chunks/build/{agents-CLQqJF2y.mjs → agents-DsCkuXDV.mjs} +49 -46
  54. package/.output/server/chunks/build/agents-DsCkuXDV.mjs.map +1 -0
  55. package/.output/server/chunks/build/{aml-_7FdFL2p.mjs → aml-CT0xKGKI.mjs} +122 -105
  56. package/.output/server/chunks/build/aml-CT0xKGKI.mjs.map +1 -0
  57. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs +117 -0
  58. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs.map +1 -0
  59. package/.output/server/chunks/build/{channel-templates-p6SZNjlM.mjs → channel-templates-Dla9FbYa.mjs} +49 -37
  60. package/.output/server/chunks/build/channel-templates-Dla9FbYa.mjs.map +1 -0
  61. package/.output/server/chunks/build/{daq-DkMvD8sg.mjs → daq-DWWSKGAV.mjs} +89 -88
  62. package/.output/server/chunks/build/daq-DWWSKGAV.mjs.map +1 -0
  63. package/.output/server/chunks/build/{dcw-C1jgVJkO.mjs → dcw-CT8k17_E.mjs} +44 -43
  64. package/.output/server/chunks/build/dcw-CT8k17_E.mjs.map +1 -0
  65. package/.output/server/chunks/build/{default-BE4r0FZN.mjs → default-D3525UFX.mjs} +16 -15
  66. package/.output/server/chunks/build/{default-BE4r0FZN.mjs.map → default-D3525UFX.mjs.map} +1 -1
  67. package/.output/server/chunks/build/{monitor-C0okQaXz.mjs → monitor-Dh2Kvaq5.mjs} +2 -2
  68. package/.output/server/chunks/build/{monitor-C0okQaXz.mjs.map → monitor-Dh2Kvaq5.mjs.map} +1 -1
  69. package/.output/server/chunks/build/{pages-B0bUWnC6.mjs → pages-BHcSBM2D.mjs} +24 -18
  70. package/.output/server/chunks/build/pages-BHcSBM2D.mjs.map +1 -0
  71. package/.output/server/chunks/build/{plugins-lGlUr1lj.mjs → plugins-BNgIi61W.mjs} +23 -17
  72. package/.output/server/chunks/build/plugins-BNgIi61W.mjs.map +1 -0
  73. package/.output/server/chunks/build/{settings-Ddd1qx2Z.mjs → settings-ipYBDWdn.mjs} +45 -44
  74. package/.output/server/chunks/build/settings-ipYBDWdn.mjs.map +1 -0
  75. package/.output/server/chunks/build/{teams-MEDLZdMn.mjs → teams-5lx-CwFa.mjs} +47 -44
  76. package/.output/server/chunks/build/teams-5lx-CwFa.mjs.map +1 -0
  77. package/.output/server/chunks/build/{tokens-C7fTM5C2.mjs → tokens-q-IDT8Io.mjs} +73 -53
  78. package/.output/server/chunks/build/tokens-q-IDT8Io.mjs.map +1 -0
  79. package/.output/server/chunks/build/{town-CoQdblbZ.mjs → town-QJWB5wng.mjs} +3 -2
  80. package/.output/server/chunks/build/town-QJWB5wng.mjs.map +1 -0
  81. package/.output/server/chunks/build/{workshop-BL5bhfs0.mjs → workshop-BIlCj_ZP.mjs} +45 -45
  82. package/.output/server/chunks/build/workshop-BIlCj_ZP.mjs.map +1 -0
  83. package/.output/server/chunks/routes/renderer.mjs +1 -1
  84. package/.output/server/chunks/virtual/entry.mjs +637 -86
  85. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  86. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  87. package/.output/server/package.json +1 -1
  88. package/README-zh.md +13 -3
  89. package/README.md +13 -3
  90. package/app/components/AppHeader.vue +961 -959
  91. package/app/components/workshop/A2aRpcDebugger.vue +237 -237
  92. package/app/components/workshop/AgentInspectorDrawer.vue +424 -424
  93. package/app/components/workshop/AgentLanesView.vue +998 -998
  94. package/app/components/workshop/ArtifactCard.vue +120 -120
  95. package/app/components/workshop/AssetLibrary.vue +452 -452
  96. package/app/components/workshop/ChannelSessionList.vue +812 -804
  97. package/app/components/workshop/CommandPalette.vue +269 -269
  98. package/app/components/workshop/Composer.vue +827 -827
  99. package/app/components/workshop/DeviceTwinPanel.vue +643 -643
  100. package/app/components/workshop/EventBlock.vue +602 -602
  101. package/app/components/workshop/FileSelectorModal.vue +188 -188
  102. package/app/components/workshop/InspectorPanel.vue +301 -301
  103. package/app/components/workshop/MemoryPanel.vue +364 -364
  104. package/app/components/workshop/MultiChannelView.vue +189 -189
  105. package/app/components/workshop/TaskBoardView.vue +686 -686
  106. package/app/components/workshop/TaskInspectorDrawer.vue +390 -390
  107. package/app/components/workshop/TranscriptTimeline.vue +601 -601
  108. package/app/components/workshop/blocks/ClusterArtifact.vue +61 -61
  109. package/app/components/workshop/blocks/ClusterError.vue +85 -85
  110. package/app/components/workshop/blocks/ClusterLife.vue +87 -87
  111. package/app/components/workshop/blocks/ClusterMember.vue +95 -93
  112. package/app/components/workshop/blocks/ClusterMemory.vue +84 -84
  113. package/app/components/workshop/blocks/ClusterOther.vue +67 -67
  114. package/app/components/workshop/blocks/ClusterStatus.vue +149 -147
  115. package/app/components/workshop/blocks/ClusterTool.vue +158 -158
  116. package/app/components/workshop/terminal/OmpTerminalPanel.vue +1011 -1011
  117. package/app/components/workshop/town/TownView.vue +56 -56
  118. package/app/middleware/locale-cookie.global.ts +22 -0
  119. package/app/pages/aml/index.vue +24 -2
  120. package/app/pages/daq/[id].vue +11 -11
  121. package/app/pages/daq/index.vue +2316 -2316
  122. package/app/pages/dcw/[id].vue +18 -19
  123. package/app/pages/dcw/index.vue +3 -3
  124. package/app/pages/index.vue +987 -981
  125. package/app/pages/plugins/index.vue +317 -311
  126. package/app/pages/settings.vue +1564 -1562
  127. package/app/pages/tokens.vue +15 -15
  128. package/app/pages/workshop/agents.vue +612 -609
  129. package/app/pages/workshop/channel-templates.vue +18 -11
  130. package/app/pages/workshop/index.vue +668 -668
  131. package/app/pages/workshop/teams.vue +743 -740
  132. package/app/pages/workshop/w/[wsId].vue +704 -704
  133. package/app/plugins/locale-restore.client.ts +16 -1
  134. package/app/utils/builtin-catalog.ts +104 -0
  135. package/config.yml +170 -170
  136. package/docs/full-test-plan.md +2 -3
  137. package/i18n/locales/en.ts +293 -35
  138. package/i18n/locales/zh-CN.ts +265 -7
  139. package/package.json +2 -2
  140. package/scripts/_dbg-perms-e2e.mjs +132 -109
  141. package/scripts/_demo-agentteam-capture.mjs +278 -0
  142. package/scripts/_e2e-ui-functional.mjs +371 -0
  143. package/scripts/_i18n-en-cjk-scan.mjs +28 -0
  144. package/scripts/_i18n-en-verify.mjs +107 -0
  145. package/scripts/_i18n-extra-checks.mjs +53 -0
  146. package/scripts/_i18n-scan-hardcoded.mjs +180 -0
  147. package/scripts/_i18n-verify-keys.mjs +50 -0
  148. package/scripts/_loop-biax-campaign.mjs +15 -9
  149. package/scripts/_sweep-button-contrast.mjs +87 -0
  150. package/scripts/ui/record-demo.mjs +557 -0
  151. package/server/plugins-builtin/diag-bridge/index.mjs +608 -661
  152. package/server/plugins-builtin/rag-bridge/index.mjs +57 -133
  153. package/server/services/workshop/daq/drivers.ts +11 -0
  154. package/.output/public/_nuxt/88GOowgO2.js +0 -1
  155. package/.output/public/_nuxt/BN16aRdQ.js +0 -1
  156. package/.output/public/_nuxt/BWVhZntO.js +0 -1
  157. package/.output/public/_nuxt/BXxH0UQE.js +0 -1
  158. package/.output/public/_nuxt/BsROmY89.js +0 -1
  159. package/.output/public/_nuxt/C0ZrS1KL.js +0 -19
  160. package/.output/public/_nuxt/C4s_niy-.js +0 -14
  161. package/.output/public/_nuxt/D6mbFA-a.js +0 -1
  162. package/.output/public/_nuxt/DS8qj8EL.js +0 -1
  163. package/.output/public/_nuxt/DUjW5Yq5.js +0 -1
  164. package/.output/public/_nuxt/Dap5PmTL.js +0 -2
  165. package/.output/public/_nuxt/Dqw1lpr-.js +0 -1
  166. package/.output/public/_nuxt/DvLxILQP.js +0 -1
  167. package/.output/public/_nuxt/OmpTerminalPanel.B_Pl5Ynm.css +0 -1
  168. package/.output/public/_nuxt/TownView.f-YOdXRs.css +0 -1
  169. package/.output/public/_nuxt/_id_.D9ymtHB5.css +0 -1
  170. package/.output/public/_nuxt/_id_.jf-_8E_c.css +0 -1
  171. package/.output/public/_nuxt/agents.ZD0rVdHE.css +0 -1
  172. package/.output/public/_nuxt/aml.BN8ZEW4h.css +0 -1
  173. package/.output/public/_nuxt/builds/meta/78a295bb-2072-48a4-8b46-6d545fdae743.json +0 -1
  174. package/.output/public/_nuxt/channel-templates.BOtahzPi.css +0 -1
  175. package/.output/public/_nuxt/daq.DjSgY94l.css +0 -1
  176. package/.output/public/_nuxt/dcw.8Y7FqCVN.css +0 -1
  177. package/.output/public/_nuxt/eqq3wWQF.js +0 -18
  178. package/.output/public/_nuxt/pages.D7aSDlUI.css +0 -1
  179. package/.output/public/_nuxt/plugins.sb4nDGqr.css +0 -1
  180. package/.output/public/_nuxt/qr6R6Ha1.js +0 -1
  181. package/.output/public/_nuxt/settings.BTgR-NiE.css +0 -1
  182. package/.output/public/_nuxt/teams.CxnxKVVs.css +0 -1
  183. package/.output/public/_nuxt/tokens.BFY7qv4f.css +0 -1
  184. package/.output/public/_nuxt/workshop.CR_QzeAN.css +0 -1
  185. package/.output/server/chunks/build/_id_-Brv-JSvr.mjs.map +0 -1
  186. package/.output/server/chunks/build/_id_-D9pl1OZy.mjs.map +0 -1
  187. package/.output/server/chunks/build/agents-CLQqJF2y.mjs.map +0 -1
  188. package/.output/server/chunks/build/aml-_7FdFL2p.mjs.map +0 -1
  189. package/.output/server/chunks/build/channel-templates-p6SZNjlM.mjs.map +0 -1
  190. package/.output/server/chunks/build/daq-DkMvD8sg.mjs.map +0 -1
  191. package/.output/server/chunks/build/dcw-C1jgVJkO.mjs.map +0 -1
  192. package/.output/server/chunks/build/pages-B0bUWnC6.mjs.map +0 -1
  193. package/.output/server/chunks/build/plugins-lGlUr1lj.mjs.map +0 -1
  194. package/.output/server/chunks/build/settings-Ddd1qx2Z.mjs.map +0 -1
  195. package/.output/server/chunks/build/teams-MEDLZdMn.mjs.map +0 -1
  196. package/.output/server/chunks/build/tokens-C7fTM5C2.mjs.map +0 -1
  197. package/.output/server/chunks/build/town-CoQdblbZ.mjs.map +0 -1
  198. package/.output/server/chunks/build/workshop-BL5bhfs0.mjs.map +0 -1
  199. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.continue.json +0 -1
  200. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.json +0 -1
  201. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/054bb4bc4e4217a2ab0b0c6b663747214a9af464f5568ea60e784704e340bb0f.source +0 -153
  202. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/0554197c3d2bac203a1f5c48a5d52495d1336db1bd7aa4f4c19875810363e684.source +0 -153
  203. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/05c203d12a954fffba942e1d626e3f5fec05b18a5aef2bac003b7884a4b77406.source +0 -431
  204. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/145a6e6ba811af35aed31e0cc3211f53706a14980fa069ee9e3c1591139f96f0.source +0 -180
  205. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/1ae0fb281f97899c025e368ca73f41349b01fb5f85b19e08d7ebccff49095ed5.source +0 -112
  206. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/20ee9967aa0541c516db7575bdd4a1a745939bc7016bd10d7635903113edb8ec.source +0 -227
  207. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/233751843aeba9d4c5263f275b8102de00443c06f286918cbd23e0b6729e01aa.source +0 -131
  208. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/263c2e05b425e5c322e60c6475279f963bab3a873eb521b21df7fec935a46597.source +0 -160
  209. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/2ac5eaac28eaaee2178c4b32014df8e732f9dd432a285a872f5b7f31c1395fa4.source +0 -157
  210. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/33a0db0d2d95d2c11d0720090458e5fba1425376f5ceb5b422d1d3471be3226b.source +0 -348
  211. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/359e474ae83db35e4615d3728de6bf694b64d4dce9b536730a3b6518f9c0494a.source +0 -296
  212. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/37a4c3c31c4b70f6b719c53d1e9c4fcba603f31adfdd11bb6ef9f0d094923c56.source +0 -285
  213. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/461feca1c14a695eb8b0f17a6f95fe97eeceabc0510faaea4ba6d25bde147d8d.source +0 -217
  214. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/4cfadbda8591f29d5e1e230dc000e701b756e850441b3900fb596a4d2f6e98c2.source +0 -301
  215. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/50ca2810cf0b248c96948994c0c404531bbad6e553166b6816b3b03bfa0f75d2.source +0 -151
  216. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/52d9e8cb591a9ae86e238c3620a610cd386717bee222c0f37b25b2ac7e523dc4.source +0 -135
  217. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/6c87daafa4c006560a954636a97333f6123153c9d34d96203f7ee3a14e556357.source +0 -156
  218. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/77bc47854b577900621cacf1697f81fa2bc005af129d37614a97a3441c08f99f.source +0 -72
  219. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/7bbb789d3a527817118cf8399ed1861d6a962ade10878fd07223435d333a7089.source +0 -469
  220. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/86b7c1daafc8b60ba9982dde5bf1bcc74265709483c176e71f23ec6fc267451f.source +0 -259
  221. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/8df66d62bd41984d0970e8236882080c5085ac937d07a29779463d6a03b37c76.source +0 -97
  222. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/9962f2d1b3a85137bd40cc835725600b39f89ee02a27c06b2e0402e1eafde115.source +0 -277
  223. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/a1090ea066b792cb201739f4994e37bf7c12f52e805239a1eab87f18a537f266.source +0 -171
  224. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/a5241091650134d0919897e086a606a3846c8b2b54f8b4c84a8696c145ac3e9e.source +0 -425
  225. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/af19fa4c6e34d5540028be4b17600161283af3a2a2dfc61a3fdc0834436a0c14.source +0 -99
  226. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/b3713d78e2b2f93905ff6be8d58a8d0a2f42dea322eb67c987fda22ff6a084d5.source +0 -325
  227. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/b3849943c3aff102d1af815631fc843a2a52c17646a4b04696ece323e483bbec.source +0 -332
  228. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/bac735a3803a6650b7f1eb8f587e6dc5c68ea055000c3c99a11789438b78e837.source +0 -43
  229. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/d32c24d61eb8b33c73e5a8fc7e4dc7ef437aed238ee4371c2b00617e6104090a.source +0 -154
  230. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/d5170dc9a9879fda04fdf91d8a110d4efb6787ee38dda596d4da899883d36a72.source +0 -531
  231. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/dc59bcd7bb397be63ba2f2c3fec23f3782dcb17d2d75a9981eeced761f33eb32.source +0 -439
  232. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/eb5ff8cf66b92aec7bf6726781d8df74faa2b030c3aaac17d6b00c1fc04c9b32.source +0 -323
  233. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f10615a6fae18436e70d1201b2d44fdae3174a3aa7bb4db97dea1b3ed291d721.source +0 -433
  234. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f36d3e271668bc1260c2823542d22dbf1d0f7041ff16b1ac175bce2256e582ca.source +0 -280
  235. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f94449380af09f31ac352152007146a75cc80bae8d6411ffe57b2c56f933b0ff.source +0 -117
  236. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/fe4dfd81178fd6b648335f6405d9ede71319aebde796008e50db21f8adf44c99.source +0 -160
  237. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/ffb4e3aa548cfdadabaa44ab599f9b6a3ca6288176a2cc7a4b2fc2a12b5fb848.source +0 -101
  238. package/scripts/.mimosa/hook-status/sess_aeaecb58-8833-4b83-b93c-050467d21e03-d944d71bb3.json +0 -14
  239. package/scripts/_dbg-audit-all-pages.mjs +0 -43
  240. package/scripts/_dbg-daq-frames-e2e.mjs +0 -118
  241. package/scripts/_dbg-daq-rowstyle-verify.mjs +0 -112
  242. package/scripts/_dbg-hitl-timeout-e2e.mjs +0 -93
  243. package/scripts/_dbg-live-line-e2e.mjs +0 -279
  244. package/scripts/_dbg-minimal-omp.mjs +0 -77
  245. package/scripts/_dbg-mode-nav.mjs +0 -173
  246. package/scripts/_dbg-real-scenario-timeline.log +0 -55
  247. package/scripts/_dbg-team-repro.mjs +0 -76
  248. package/scripts/_dbg-town-agents-probe.mjs +0 -60
  249. package/scripts/_dbg-visual-acceptance.mjs +0 -63
  250. package/scripts/_townview_style.css +0 -1185
  251. package/scripts/_townview_template.html +0 -1215
  252. package/server/data/agent-node-bindings.json +0 -554
  253. package/server/data/daq-templates.json +0 -16
  254. package/server/data/daqs.json +0 -7464
  255. package/server/data/dcw-lines.json +0 -1787
  256. package/server/data/dcw-products.json +0 -1626
  257. package/server/data/dcw-recipes.json +0 -4672
  258. package/server/data/dcw-rollback.json +0 -20754
  259. package/server/data/dcw-runs.json +0 -6354
  260. package/server/data/dcw-templates.json +0 -146
  261. package/server/data/dcw-writes.json +0 -15650
  262. package/server/data/dcws.json +0 -9033
  263. package/server/data/device-twins.json +0 -133
  264. package/server/data/line-runs.json +0 -322
  265. package/server/data/scene-layouts.json +0 -277
@@ -1,602 +1,602 @@
1
- <script setup lang="ts">
2
- /**
3
- * 事件聚合块 — open-tag 聊天行声部(.msg 网格:头像列 + 内容列):
4
- * - 头部:26px 头像 + 名字 + 类别小标 + 计数/时间;正文落在内容列(块体组件复用);
5
- * - 连续同发送者块 compact 分组:隐藏头像与名字(Slack 消息分组),保留左列对齐;
6
- * - 悬停工具条(open-tag msg-toolbar):流/消息块可复制全文 / 引用到输入框(经 Composer 总线);
7
- * - 各行渲染按 kind 分发到隔离组件 —— 流式更新只触发命中 kind 的组件。
8
- */
9
- import { computed } from 'vue'
10
- import type { Component } from 'vue'
11
- import { useEntitiesStore } from '@/app/stores/workshop/entities'
12
- import { useComposerBus } from '@/app/composables/workshop/useComposerBus'
13
- import { KIND_META, buildStreamText, blockTier, agentHueColor, type EventBlock } from '@/app/composables/workshop/useEventBlocks'
14
- import { formatLocalClock } from '@/app/composables/workshop/useLocalTime'
15
- import ClusterStream from '@/app/components/workshop/blocks/ClusterStream.vue'
16
- import ClusterTool from '@/app/components/workshop/blocks/ClusterTool.vue'
17
- import ClusterStatus from '@/app/components/workshop/blocks/ClusterStatus.vue'
18
- import ClusterLife from '@/app/components/workshop/blocks/ClusterLife.vue'
19
- import ClusterRoute from '@/app/components/workshop/blocks/ClusterRoute.vue'
20
- import ClusterTask from '@/app/components/workshop/blocks/ClusterTask.vue'
21
- import ClusterArtifact from '@/app/components/workshop/blocks/ClusterArtifact.vue'
22
- import ClusterMember from '@/app/components/workshop/blocks/ClusterMember.vue'
23
- import ClusterMemory from '@/app/components/workshop/blocks/ClusterMemory.vue'
24
- import ClusterError from '@/app/components/workshop/blocks/ClusterError.vue'
25
- import ClusterOther from '@/app/components/workshop/blocks/ClusterOther.vue'
26
-
27
- const props = defineProps<{
28
- block: EventBlock
29
- turnStart?: boolean
30
- /** 连续同发送者紧凑分组(隐藏头像/名字,Slack 式) */
31
- compact?: boolean
32
- /** 进场编排(open-tag motion):实时新块带 60ms burst stagger;历史/重建块直接显示 */
33
- enterStage?: { enter: boolean, delay: number }
34
- }>()
35
-
36
- const entities = useEntitiesStore()
37
- const { quote } = useComposerBus()
38
- const cid = computed(() => props.block.events[0]?.channelId ?? '')
39
-
40
- const time = computed(() => formatLocalClock(props.block.firstAt))
41
- const agentLabel = computed(() => {
42
- const id = props.block.agentId
43
- if (!id) return 'system'
44
- return entities.agentName(cid.value, id)
45
- })
46
- /**
47
- * 人类发送者名(a2a.message 且 from 空 + x-aw-from-label):
48
- * 头部以"用户章"呈现 —— Slack 声部里人也是会话一方。
49
- */
50
- const humanLabel = computed(() => {
51
- if (props.block.agentId) return null
52
- const e = props.block.events[0]
53
- if (!e || e.type !== 'a2a.message') return null
54
- const meta = (e.payload as { metadata?: Record<string, unknown> }).metadata ?? {}
55
- const label = meta['x-aw-from-label']
56
- return typeof label === 'string' && label ? label : null
57
- })
58
- /** 头像章首字母(名字或 id 首字符;system 用 cpu 图标) */
59
- const agentInitial = computed(() => {
60
- const id = props.block.agentId
61
- if (!id) return ''
62
- const name = entities.agentName(cid.value, id)
63
- return (name || id).charAt(0).toUpperCase()
64
- })
65
-
66
- /** 身份色(agentId 哈希 → 稳定色相;与泳道头/提及卡同一来源,全站不再另造配色) */
67
- const avColor = computed(() =>
68
- props.block.agentId ? agentHueColor(props.block.agentId) : undefined,
69
- )
70
-
71
- const meta = computed(() => KIND_META[props.block.kind])
72
-
73
- /** 头像点击 → 打开 Agent 抽屉(与 @pill 同入口) */
74
- const openAgent = inject<(target: { channelId: string, agentId: string }) => void>(
75
- 'aw:open-agent',
76
- () => {},
77
- )
78
- const onAvatarClick = (): void => {
79
- if (props.block.agentId) openAgent({ channelId: cid.value, agentId: props.block.agentId })
80
- }
81
-
82
- /** 发送方身份字幕(open-tag msg-role):lead/worker · harness,agent 行的身份描述 */
83
- const roleLabel = computed(() => {
84
- const id = props.block.agentId
85
- if (!id) return ''
86
- const a = (entities.agents[cid.value] ?? []).find(x => x.agentId === id)
87
- if (!a) return 'agent'
88
- const role = a.role === 'lead' ? 'lead' : 'worker'
89
- const harness = a.harness ?? ''
90
- return harness ? `${role} · ${harness}` : role
91
- })
92
-
93
- /**
94
- * 注意力档位(open-tag deliveryTier 移植):terminal(终局产出)= 成功色左缘 +
95
- * 加重名字;attention(等待回应/错误)= 琥珀左缘 + 脉搏点;silent(过程噪声)=
96
- * 轻微收敛。视觉层级随"该不该打断人"伸缩,状态不只靠颜色(chip 文本仍在)。
97
- */
98
- const tier = computed(() => blockTier(props.block.events))
99
-
100
- /** 头像状态 pip(open-tag av-status 移植):agent 实时状态叠层(busy 暖橙呼吸/idle 静灰) */
101
- const agentState = computed(() => {
102
- const id = props.block.agentId
103
- if (!id) return null as 'idle' | 'busy' | 'stopped' | null
104
- const a = (entities.agents[cid.value] ?? []).find(x => x.agentId === id)
105
- return (a?.state ?? null) as 'idle' | 'busy' | 'stopped' | null
106
- })
107
-
108
- /** 流式运行指示(open-tag msg-agent-state 移植):未落定流块 + agent busy → "运行中" */
109
- const runningNow = computed(() =>
110
- props.block.kind === 'stream'
111
- && !props.block.settled
112
- && agentState.value === 'busy')
113
-
114
- /** 消费完整性观测:块首事件 seq + 块内事件数(浏览器测试对账用) */
115
- const firstSeq = computed(() => props.block.events[0]?.seq ?? 0)
116
-
117
- const KIND_COMPONENT: Record<string, Component> = {
118
- stream: ClusterStream,
119
- tool: ClusterTool,
120
- status: ClusterStatus,
121
- life: ClusterLife,
122
- route: ClusterRoute,
123
- task: ClusterTask,
124
- artifact: ClusterArtifact,
125
- member: ClusterMember,
126
- memory: ClusterMemory,
127
- error: ClusterError,
128
- other: ClusterOther,
129
- }
130
- const body = computed(() => KIND_COMPONENT[props.block.kind] ?? ClusterOther)
131
-
132
- /** 工具条可用正文:流块取累计文本;路由块取消息 parts(供复制/引用) */
133
- const toolbarText = computed(() => {
134
- if (props.block.kind === 'stream') {
135
- const t = buildStreamText(props.block).trim()
136
- return t || null
137
- }
138
- if (props.block.kind === 'route') {
139
- const t = props.block.events
140
- .map((e) => {
141
- const parts = (e.payload as { parts?: Array<{ text?: string }> }).parts ?? []
142
- return parts.map(p => p.text ?? '').join('\n').trim()
143
- })
144
- .filter(Boolean)
145
- .join('\n')
146
- return t || null
147
- }
148
- return null
149
- })
150
-
151
- const copied = ref(false)
152
- const copyAll = async (): Promise<void> => {
153
- const t = toolbarText.value
154
- if (!t) return
155
- try {
156
- await navigator.clipboard.writeText(t)
157
- copied.value = true
158
- setTimeout(() => {
159
- copied.value = false
160
- }, 1400)
161
- }
162
- catch { /* 剪贴板不可用时静默 */ }
163
- }
164
-
165
- /** 引用到 Composer:块正文以 `> ` 前缀注入输入框 */
166
- const quoteToComposer = (): void => {
167
- const t = toolbarText.value
168
- if (t) quote(t)
169
- }
170
- </script>
171
-
172
- <template>
173
- <section
174
- class="event-block"
175
- :class="{ 'turn-start': turnStart, compact, 'enter': enterStage?.enter }"
176
- :style="enterStage?.enter ? { '--d': `${enterStage.delay}ms` } : undefined"
177
- :data-kind="block.kind"
178
- :data-tier="tier"
179
- :data-settled="block.settled ? 'true' : 'false'"
180
- :data-covered="block.coveredBy ? 'true' : 'false'"
181
- :data-seq="firstSeq"
182
- :data-events="block.events.length"
183
- :data-folded="block.folded"
184
- >
185
- <button
186
- type="button"
187
- class="agent-avatar"
188
- :class="{ 'is-agent': !!block.agentId, 'is-human': !!humanLabel, 'clickable': !!block.agentId }"
189
- :title="humanLabel ?? `${agentLabel}${roleLabel ? ` · ${roleLabel}` : ''}`"
190
- :style="avColor ? { '--av': avColor } : undefined"
191
- @click="onAvatarClick"
192
- >
193
- <span
194
- v-if="humanLabel"
195
- class="i-tabler-user system-icon"
196
- />
197
- <span
198
- v-else-if="!block.agentId"
199
- class="i-tabler-cpu system-icon"
200
- />
201
- <template v-else>
202
- {{ agentInitial }}
203
- </template>
204
- <!-- 状态 pip:busy 呼吸圈 / idle 静点(open-tag av-status) -->
205
- <span
206
- v-if="block.agentId && agentState"
207
- class="av-status"
208
- :class="agentState"
209
- :title="agentState === 'busy' ? '运行中' : agentState === 'stopped' ? '已停止' : '空闲'"
210
- />
211
- </button>
212
-
213
- <div class="eb-main">
214
- <header
215
- v-show="!compact"
216
- class="block-head"
217
- >
218
- <span class="agent-name">{{ humanLabel ?? agentLabel }}</span>
219
- <span
220
- v-if="roleLabel"
221
- class="role-label"
222
- >{{ roleLabel }}</span>
223
- <span
224
- v-if="tier === 'attention'"
225
- class="tier-attention"
226
- :title="$t('eventBlock.kc918hn001')"
227
- ><span class="i-tabler-alert-circle" />{{ $t('eventBlock.k3wmcv4004') }}</span>
228
- <span class="head-right">
229
- <!-- 流式运行指示(open-tag msg-agent-state):当前 agent 正在产出 -->
230
- <span
231
- v-if="runningNow"
232
- class="running-chip"
233
- ><span class="running-dot" />{{ $t('eventBlock.k3vp67i005') }}</span>
234
- <span
235
- v-if="block.folded > 0"
236
- class="folded"
237
- :title="$t('eventBlock.kcugdph002')"
238
- >{{ $t('eventBlock.k3xk4t006') }} {{ block.folded }}</span>
239
- <span
240
- v-if="block.events.length > 1"
241
- class="merged"
242
- >×{{ block.events.length }}</span>
243
- <span class="kind-chip">{{ meta.label }}</span>
244
- <span class="time">{{ time }}</span>
245
- </span>
246
- <!-- 悬停工具条:复制全文 / 引用到输入框(open-tag msg-toolbar) -->
247
- <span
248
- v-if="toolbarText"
249
- class="eb-toolbar"
250
- >
251
- <button
252
- type="button"
253
- class="eb-tool"
254
- :title="copied ? '已复制' : '复制全文'"
255
- @click="copyAll"
256
- >
257
- <span :class="copied ? 'i-tabler-check' : 'i-tabler-copy'" />
258
- </button>
259
- <button
260
- type="button"
261
- class="eb-tool"
262
- :title="$t('eventBlock.kknq700003')"
263
- @click="quoteToComposer"
264
- >
265
- <span class="i-tabler-quote" />
266
- </button>
267
- </span>
268
- </header>
269
-
270
- <!-- 紧凑态副作用:紧凑态隐藏头部后,悬停显示抹去的时间(chat 侧厢时间轴) -->
271
- <span
272
- v-if="compact"
273
- class="ghost-time"
274
- >{{ time.slice(0, 5) }}</span>
275
-
276
- <component
277
- :is="body"
278
- :block="block"
279
- class="eb-body"
280
- />
281
- </div>
282
- </section>
283
- </template>
284
-
285
- <style scoped>
286
- /* Slack 聊天行:行跨度经头像列成组;默认无左缘,仅终局/注意级/流式/错误插色缘 */
287
- .event-block {
288
- position: relative;
289
- display: grid;
290
- grid-template-columns: 30px minmax(0, 1fr);
291
- column-gap: 11px;
292
- padding: 5px 10px 4px 12px;
293
- margin: 0;
294
- transition: background 0.15s ease;
295
- }
296
-
297
- .event-block:hover {
298
- background: var(--hover-tint);
299
- border-radius: 4px;
300
- }
301
-
302
- /* 进场编排(open-tag motion charter):仅实时新块,60ms burst stagger;
303
- * 历史/过滤重建直接显示(reduced-motion 直显) */
304
- .event-block.enter {
305
- animation: block-in 0.32s var(--ease-out-quart) backwards;
306
- animation-delay: var(--d, 0ms);
307
- }
308
- @media (prefers-reduced-motion: reduce) {
309
- .event-block.enter { animation: none; }
310
- }
311
-
312
- /* turn 边界:不同 agent 的新回合 → 加大间距 + 顶部 hairline(角色回合切换) */
313
- .event-block.turn-start {
314
- margin-top: 13px;
315
- padding-top: 9px;
316
- border-top: 1px solid var(--line);
317
- }
318
- .event-block.turn-start.compact {
319
- margin-top: 0;
320
- padding-top: 5px;
321
- border-top: 0;
322
- }
323
-
324
- .event-block[data-kind='stream']:not([data-settled='true']) {
325
- background: color-mix(in srgb, var(--ink) 2.5%, transparent);
326
- border-radius: 4px;
327
- }
328
- /* 仅注意/错误级接入色缘(兑色低饱和度;终局不加彩色缘,靠名字加粗表意) */
329
- .event-block[data-tier='attention'] {
330
- box-shadow: inset 2px 0 0 color-mix(in srgb, var(--tone-warning-dot) 55%, transparent);
331
- }
332
- .event-block[data-kind='error'] {
333
- box-shadow: inset 2px 0 0 color-mix(in srgb, var(--tone-danger-dot) 70%, transparent);
334
- }
335
- .event-block[data-covered='true'] { opacity: 0.72; }
336
-
337
- .event-block[data-tier='terminal'] .agent-name { font-weight: 700; }
338
- .event-block[data-tier='silent'] { opacity: 0.88; }
339
- .event-block[data-tier='silent']:hover { opacity: 1; }
340
-
341
- .tier-attention {
342
- display: inline-flex;
343
- gap: 3px;
344
- align-items: center;
345
- padding: 0 5px;
346
- font-size: 10px;
347
- color: var(--tone-warning-dot);
348
- background: color-mix(in srgb, var(--tone-warning-dot) 13%, transparent);
349
- border-radius: var(--radius-chip);
350
- }
351
- @keyframes block-in {
352
- from {
353
- opacity: 0;
354
- transform: translateY(4px);
355
- }
356
- to {
357
- opacity: 1;
358
- transform: none;
359
- }
360
- }
361
-
362
- /* 头像列:agent = 身份色(agentId 哈希 → --av,同源色相,白字首字母);
363
- human/system = surface(open-tag av 尺寸档 36/28) */
364
- .agent-avatar {
365
- position: relative;
366
- display: flex;
367
- align-items: center;
368
- justify-content: center;
369
- width: 30px;
370
- height: 30px;
371
- min-width: 30px;
372
- margin-top: 0;
373
- padding: 0;
374
- font-family: var(--font-body);
375
- font-size: 12px;
376
- font-weight: 600;
377
- color: var(--ink);
378
- background: var(--paper-deep);
379
- border: 0;
380
- border-radius: 50%;
381
- }
382
- .agent-avatar.clickable {
383
- cursor: pointer;
384
- transition: transform var(--transition-fast) var(--im-spring), box-shadow var(--transition-fast);
385
- }
386
- .agent-avatar.clickable:hover {
387
- transform: scale(1.06);
388
- box-shadow: 0 0 0 var(--radius-chip) transparent, 0 3px 10px rgb(12 10 9 / 16%);
389
- }
390
- .agent-avatar.is-agent {
391
- color: var(--on-av);
392
- background: var(--av, var(--av-fallback));
393
- }
394
- .agent-avatar.is-human {
395
- color: var(--ink-soft);
396
- background: var(--paper-deep);
397
- box-shadow: inset 0 0 0 1px var(--line-strong);
398
- }
399
- .agent-avatar .system-icon {
400
- font-size: 15px;
401
- line-height: 1;
402
- }
403
-
404
- /* 状态 pip:头像右下 8px 叠层(open-tag av-status);busy 呼吸,stopped 灰,idle 淡 */
405
- .av-status {
406
- position: absolute;
407
- right: -2px;
408
- bottom: -2px;
409
- width: 8px;
410
- height: 8px;
411
- background: var(--ink-fainter);
412
- border: 1.5px solid var(--paper-raised);
413
- border-radius: 50%;
414
- }
415
- .av-status.busy {
416
- background: var(--tone-live-dot);
417
- animation: av-breathe 1.9s ease-in-out infinite;
418
- }
419
- .av-status.stopped { background: var(--tone-danger-dot); }
420
- @keyframes av-breathe {
421
- 0%, 100% { opacity: 0.55; }
422
- 50% { opacity: 1; }
423
- }
424
- @media (prefers-reduced-motion: reduce) {
425
- .av-status.busy { animation: none; opacity: 0.9; }
426
- }
427
-
428
- /* 紧凑分组:隐藏头像与头部,保留列对齐(Slack 连续消息;ghost 时间月台悬浮显) */
429
- .event-block.compact .agent-avatar {
430
- visibility: hidden;
431
- height: 0;
432
- margin-top: 0;
433
- }
434
- .event-block.compact {
435
- padding-top: 2px;
436
- padding-bottom: 2px;
437
- }
438
- .event-block.compact + .event-block.compact {
439
- margin-top: -2px;
440
- }
441
-
442
- .eb-main {
443
- min-width: 0;
444
- }
445
-
446
- .block-head {
447
- position: relative;
448
- display: flex;
449
- gap: 8px;
450
- align-items: center;
451
- min-height: 20px;
452
- padding-bottom: 1px;
453
- font-family: var(--font-body);
454
- }
455
-
456
- .agent-name {
457
- overflow: hidden;
458
- max-width: 220px;
459
- font-size: 13px;
460
- font-weight: 600;
461
- color: var(--ink);
462
- text-overflow: ellipsis;
463
- white-space: nowrap;
464
- }
465
-
466
- /* 身份字幕(open-tag msg-role):lead/worker · harness,灰调不与之争关注 */
467
- .role-label {
468
- overflow: hidden;
469
- font-family: var(--font-body);
470
- font-size: 10.5px;
471
- color: var(--ink-faint);
472
- text-overflow: ellipsis;
473
- white-space: nowrap;
474
- }
475
-
476
- /* 类别小标:中性等宽纯文本(无边框/无彩色点 —— 类别是元语不是状态,
477
- 彩色语义只留给 attention/error 边缘) */
478
- .kind-chip {
479
- display: inline-flex;
480
- align-items: center;
481
- padding: 0 2px;
482
- font-family: var(--font-mono);
483
- font-size: 10px;
484
- letter-spacing: 0.06em;
485
- line-height: 14px;
486
- color: var(--ink-faint);
487
- }
488
- .head-right {
489
- display: flex;
490
- flex: 1 1 auto;
491
- gap: 6px;
492
- align-items: center;
493
- justify-content: flex-end;
494
- font-size: 9.5px;
495
- font-variant-numeric: tabular-nums;
496
- color: var(--ink-faint);
497
- }
498
- .folded {
499
- padding: 0 4px;
500
- color: var(--ink-faint);
501
- background: color-mix(in srgb, var(--ink) 7%, transparent);
502
- border-radius: var(--radius-chip);
503
- }
504
- .merged {
505
- padding: 0 4px;
506
- background: color-mix(in srgb, var(--ink) 7%, transparent);
507
- border-radius: var(--radius-chip);
508
- }
509
- .time {
510
- flex: 0 0 auto;
511
- width: 60px;
512
- font-family: var(--font-mono);
513
- font-size: 9.5px;
514
- font-variant-numeric: tabular-nums;
515
- text-align: right;
516
- }
517
-
518
- /* 紧凑态月台时间:悬停行时右侧浮现(Slack 紧凑组的时间轴补偿;仅住行头) */
519
- .ghost-time {
520
- position: absolute;
521
- top: 3px;
522
- right: 10px;
523
- z-index: 2;
524
- padding: 0 5px;
525
- font-family: var(--font-mono);
526
- font-size: 10px;
527
- font-variant-numeric: tabular-nums;
528
- color: var(--ink-faint);
529
- pointer-events: none;
530
- opacity: 0;
531
- background: var(--paper-raised);
532
- border-radius: var(--radius-chip);
533
- transition: opacity var(--transition-fast);
534
- }
535
- .event-block.compact:hover .ghost-time {
536
- opacity: 1;
537
- }
538
-
539
- /* 流式运行指示(open-tag msg-agent-state):暖橙呼吸点 + 词 */
540
- .running-chip {
541
- display: inline-flex;
542
- gap: 4px;
543
- align-items: center;
544
- color: var(--ink-faint);
545
- }
546
- .running-chip .running-dot {
547
- width: 6px;
548
- height: 6px;
549
- background: var(--tone-live-dot);
550
- border-radius: 50%;
551
- animation: av-breathe 1.9s ease-in-out infinite;
552
- }
553
- @media (prefers-reduced-motion: reduce) {
554
- .running-chip .running-dot { animation: none; opacity: 0.9; }
555
- }
556
-
557
- /* 悬停工具条:头部右侧浮出(复制/引用) */
558
- .eb-toolbar {
559
- position: absolute;
560
- top: -4px;
561
- right: 56px;
562
- z-index: 5;
563
- display: inline-flex;
564
- gap: 2px;
565
- padding: 1px;
566
- opacity: 0;
567
- pointer-events: none;
568
- background: var(--paper-raised);
569
- border: 1px solid var(--line);
570
- border-radius: var(--radius-chip);
571
- transition: opacity var(--transition-fast);
572
- }
573
- .event-block:hover .eb-toolbar {
574
- opacity: 1;
575
- pointer-events: auto;
576
- }
577
- .eb-tool {
578
- display: inline-flex;
579
- align-items: center;
580
- justify-content: center;
581
- width: 22px;
582
- height: 22px;
583
- padding: 0;
584
- font-size: 12px;
585
- color: var(--ink-faint);
586
- cursor: pointer;
587
- background: transparent;
588
- border: 0;
589
- border-radius: var(--radius-chip);
590
- transition: color var(--transition-fast), background var(--transition-fast);
591
- }
592
- .eb-tool:hover {
593
- color: var(--ink);
594
- background: var(--paper-deep);
595
- }
596
-
597
- /* 块体组件统一缩进归零(布局由本壳层的头像列接管;子组件自带 padding-left 归拢到内容列起点) */
598
- .eb-body {
599
- padding-left: 2px !important;
600
- margin-top: 1px;
601
- }
602
- </style>
1
+ <script setup lang="ts">
2
+ /**
3
+ * 事件聚合块 — open-tag 聊天行声部(.msg 网格:头像列 + 内容列):
4
+ * - 头部:26px 头像 + 名字 + 类别小标 + 计数/时间;正文落在内容列(块体组件复用);
5
+ * - 连续同发送者块 compact 分组:隐藏头像与名字(Slack 消息分组),保留左列对齐;
6
+ * - 悬停工具条(open-tag msg-toolbar):流/消息块可复制全文 / 引用到输入框(经 Composer 总线);
7
+ * - 各行渲染按 kind 分发到隔离组件 —— 流式更新只触发命中 kind 的组件。
8
+ */
9
+ import { computed } from 'vue'
10
+ import type { Component } from 'vue'
11
+ import { useEntitiesStore } from '@/app/stores/workshop/entities'
12
+ import { useComposerBus } from '@/app/composables/workshop/useComposerBus'
13
+ import { KIND_META, buildStreamText, blockTier, agentHueColor, type EventBlock } from '@/app/composables/workshop/useEventBlocks'
14
+ import { formatLocalClock } from '@/app/composables/workshop/useLocalTime'
15
+ import ClusterStream from '@/app/components/workshop/blocks/ClusterStream.vue'
16
+ import ClusterTool from '@/app/components/workshop/blocks/ClusterTool.vue'
17
+ import ClusterStatus from '@/app/components/workshop/blocks/ClusterStatus.vue'
18
+ import ClusterLife from '@/app/components/workshop/blocks/ClusterLife.vue'
19
+ import ClusterRoute from '@/app/components/workshop/blocks/ClusterRoute.vue'
20
+ import ClusterTask from '@/app/components/workshop/blocks/ClusterTask.vue'
21
+ import ClusterArtifact from '@/app/components/workshop/blocks/ClusterArtifact.vue'
22
+ import ClusterMember from '@/app/components/workshop/blocks/ClusterMember.vue'
23
+ import ClusterMemory from '@/app/components/workshop/blocks/ClusterMemory.vue'
24
+ import ClusterError from '@/app/components/workshop/blocks/ClusterError.vue'
25
+ import ClusterOther from '@/app/components/workshop/blocks/ClusterOther.vue'
26
+
27
+ const props = defineProps<{
28
+ block: EventBlock
29
+ turnStart?: boolean
30
+ /** 连续同发送者紧凑分组(隐藏头像/名字,Slack 式) */
31
+ compact?: boolean
32
+ /** 进场编排(open-tag motion):实时新块带 60ms burst stagger;历史/重建块直接显示 */
33
+ enterStage?: { enter: boolean, delay: number }
34
+ }>()
35
+
36
+ const entities = useEntitiesStore()
37
+ const { quote } = useComposerBus()
38
+ const cid = computed(() => props.block.events[0]?.channelId ?? '')
39
+
40
+ const time = computed(() => formatLocalClock(props.block.firstAt))
41
+ const agentLabel = computed(() => {
42
+ const id = props.block.agentId
43
+ if (!id) return 'system'
44
+ return entities.agentName(cid.value, id)
45
+ })
46
+ /**
47
+ * 人类发送者名(a2a.message 且 from 空 + x-aw-from-label):
48
+ * 头部以"用户章"呈现 —— Slack 声部里人也是会话一方。
49
+ */
50
+ const humanLabel = computed(() => {
51
+ if (props.block.agentId) return null
52
+ const e = props.block.events[0]
53
+ if (!e || e.type !== 'a2a.message') return null
54
+ const meta = (e.payload as { metadata?: Record<string, unknown> }).metadata ?? {}
55
+ const label = meta['x-aw-from-label']
56
+ return typeof label === 'string' && label ? label : null
57
+ })
58
+ /** 头像章首字母(名字或 id 首字符;system 用 cpu 图标) */
59
+ const agentInitial = computed(() => {
60
+ const id = props.block.agentId
61
+ if (!id) return ''
62
+ const name = entities.agentName(cid.value, id)
63
+ return (name || id).charAt(0).toUpperCase()
64
+ })
65
+
66
+ /** 身份色(agentId 哈希 → 稳定色相;与泳道头/提及卡同一来源,全站不再另造配色) */
67
+ const avColor = computed(() =>
68
+ props.block.agentId ? agentHueColor(props.block.agentId) : undefined,
69
+ )
70
+
71
+ const meta = computed(() => KIND_META[props.block.kind])
72
+
73
+ /** 头像点击 → 打开 Agent 抽屉(与 @pill 同入口) */
74
+ const openAgent = inject<(target: { channelId: string, agentId: string }) => void>(
75
+ 'aw:open-agent',
76
+ () => {},
77
+ )
78
+ const onAvatarClick = (): void => {
79
+ if (props.block.agentId) openAgent({ channelId: cid.value, agentId: props.block.agentId })
80
+ }
81
+
82
+ /** 发送方身份字幕(open-tag msg-role):lead/worker · harness,agent 行的身份描述 */
83
+ const roleLabel = computed(() => {
84
+ const id = props.block.agentId
85
+ if (!id) return ''
86
+ const a = (entities.agents[cid.value] ?? []).find(x => x.agentId === id)
87
+ if (!a) return 'agent'
88
+ const role = a.role === 'lead' ? 'lead' : 'worker'
89
+ const harness = a.harness ?? ''
90
+ return harness ? `${role} · ${harness}` : role
91
+ })
92
+
93
+ /**
94
+ * 注意力档位(open-tag deliveryTier 移植):terminal(终局产出)= 成功色左缘 +
95
+ * 加重名字;attention(等待回应/错误)= 琥珀左缘 + 脉搏点;silent(过程噪声)=
96
+ * 轻微收敛。视觉层级随"该不该打断人"伸缩,状态不只靠颜色(chip 文本仍在)。
97
+ */
98
+ const tier = computed(() => blockTier(props.block.events))
99
+
100
+ /** 头像状态 pip(open-tag av-status 移植):agent 实时状态叠层(busy 暖橙呼吸/idle 静灰) */
101
+ const agentState = computed(() => {
102
+ const id = props.block.agentId
103
+ if (!id) return null as 'idle' | 'busy' | 'stopped' | null
104
+ const a = (entities.agents[cid.value] ?? []).find(x => x.agentId === id)
105
+ return (a?.state ?? null) as 'idle' | 'busy' | 'stopped' | null
106
+ })
107
+
108
+ /** 流式运行指示(open-tag msg-agent-state 移植):未落定流块 + agent busy → "运行中" */
109
+ const runningNow = computed(() =>
110
+ props.block.kind === 'stream'
111
+ && !props.block.settled
112
+ && agentState.value === 'busy')
113
+
114
+ /** 消费完整性观测:块首事件 seq + 块内事件数(浏览器测试对账用) */
115
+ const firstSeq = computed(() => props.block.events[0]?.seq ?? 0)
116
+
117
+ const KIND_COMPONENT: Record<string, Component> = {
118
+ stream: ClusterStream,
119
+ tool: ClusterTool,
120
+ status: ClusterStatus,
121
+ life: ClusterLife,
122
+ route: ClusterRoute,
123
+ task: ClusterTask,
124
+ artifact: ClusterArtifact,
125
+ member: ClusterMember,
126
+ memory: ClusterMemory,
127
+ error: ClusterError,
128
+ other: ClusterOther,
129
+ }
130
+ const body = computed(() => KIND_COMPONENT[props.block.kind] ?? ClusterOther)
131
+
132
+ /** 工具条可用正文:流块取累计文本;路由块取消息 parts(供复制/引用) */
133
+ const toolbarText = computed(() => {
134
+ if (props.block.kind === 'stream') {
135
+ const t = buildStreamText(props.block).trim()
136
+ return t || null
137
+ }
138
+ if (props.block.kind === 'route') {
139
+ const t = props.block.events
140
+ .map((e) => {
141
+ const parts = (e.payload as { parts?: Array<{ text?: string }> }).parts ?? []
142
+ return parts.map(p => p.text ?? '').join('\n').trim()
143
+ })
144
+ .filter(Boolean)
145
+ .join('\n')
146
+ return t || null
147
+ }
148
+ return null
149
+ })
150
+
151
+ const copied = ref(false)
152
+ const copyAll = async (): Promise<void> => {
153
+ const t = toolbarText.value
154
+ if (!t) return
155
+ try {
156
+ await navigator.clipboard.writeText(t)
157
+ copied.value = true
158
+ setTimeout(() => {
159
+ copied.value = false
160
+ }, 1400)
161
+ }
162
+ catch { /* 剪贴板不可用时静默 */ }
163
+ }
164
+
165
+ /** 引用到 Composer:块正文以 `> ` 前缀注入输入框 */
166
+ const quoteToComposer = (): void => {
167
+ const t = toolbarText.value
168
+ if (t) quote(t)
169
+ }
170
+ </script>
171
+
172
+ <template>
173
+ <section
174
+ class="event-block"
175
+ :class="{ 'turn-start': turnStart, compact, 'enter': enterStage?.enter }"
176
+ :style="enterStage?.enter ? { '--d': `${enterStage.delay}ms` } : undefined"
177
+ :data-kind="block.kind"
178
+ :data-tier="tier"
179
+ :data-settled="block.settled ? 'true' : 'false'"
180
+ :data-covered="block.coveredBy ? 'true' : 'false'"
181
+ :data-seq="firstSeq"
182
+ :data-events="block.events.length"
183
+ :data-folded="block.folded"
184
+ >
185
+ <button
186
+ type="button"
187
+ class="agent-avatar"
188
+ :class="{ 'is-agent': !!block.agentId, 'is-human': !!humanLabel, 'clickable': !!block.agentId }"
189
+ :title="humanLabel ?? `${agentLabel}${roleLabel ? ` · ${roleLabel}` : ''}`"
190
+ :style="avColor ? { '--av': avColor } : undefined"
191
+ @click="onAvatarClick"
192
+ >
193
+ <span
194
+ v-if="humanLabel"
195
+ class="i-tabler-user system-icon"
196
+ />
197
+ <span
198
+ v-else-if="!block.agentId"
199
+ class="i-tabler-cpu system-icon"
200
+ />
201
+ <template v-else>
202
+ {{ agentInitial }}
203
+ </template>
204
+ <!-- 状态 pip:busy 呼吸圈 / idle 静点(open-tag av-status) -->
205
+ <span
206
+ v-if="block.agentId && agentState"
207
+ class="av-status"
208
+ :class="agentState"
209
+ :title="agentState === 'busy' ? $t('eventBlock.stBusy') : agentState === 'stopped' ? $t('eventBlock.stStopped') : $t('eventBlock.stIdle')"
210
+ />
211
+ </button>
212
+
213
+ <div class="eb-main">
214
+ <header
215
+ v-show="!compact"
216
+ class="block-head"
217
+ >
218
+ <span class="agent-name">{{ humanLabel ?? agentLabel }}</span>
219
+ <span
220
+ v-if="roleLabel"
221
+ class="role-label"
222
+ >{{ roleLabel }}</span>
223
+ <span
224
+ v-if="tier === 'attention'"
225
+ class="tier-attention"
226
+ :title="$t('eventBlock.kc918hn001')"
227
+ ><span class="i-tabler-alert-circle" />{{ $t('eventBlock.k3wmcv4004') }}</span>
228
+ <span class="head-right">
229
+ <!-- 流式运行指示(open-tag msg-agent-state):当前 agent 正在产出 -->
230
+ <span
231
+ v-if="runningNow"
232
+ class="running-chip"
233
+ ><span class="running-dot" />{{ $t('eventBlock.k3vp67i005') }}</span>
234
+ <span
235
+ v-if="block.folded > 0"
236
+ class="folded"
237
+ :title="$t('eventBlock.kcugdph002')"
238
+ >{{ $t('eventBlock.k3xk4t006') }} {{ block.folded }}</span>
239
+ <span
240
+ v-if="block.events.length > 1"
241
+ class="merged"
242
+ >×{{ block.events.length }}</span>
243
+ <span class="kind-chip">{{ meta.label }}</span>
244
+ <span class="time">{{ time }}</span>
245
+ </span>
246
+ <!-- 悬停工具条:复制全文 / 引用到输入框(open-tag msg-toolbar) -->
247
+ <span
248
+ v-if="toolbarText"
249
+ class="eb-toolbar"
250
+ >
251
+ <button
252
+ type="button"
253
+ class="eb-tool"
254
+ :title="copied ? $t('eventBlock.copied') : $t('eventBlock.copyAll')"
255
+ @click="copyAll"
256
+ >
257
+ <span :class="copied ? 'i-tabler-check' : 'i-tabler-copy'" />
258
+ </button>
259
+ <button
260
+ type="button"
261
+ class="eb-tool"
262
+ :title="$t('eventBlock.kknq700003')"
263
+ @click="quoteToComposer"
264
+ >
265
+ <span class="i-tabler-quote" />
266
+ </button>
267
+ </span>
268
+ </header>
269
+
270
+ <!-- 紧凑态副作用:紧凑态隐藏头部后,悬停显示抹去的时间(chat 侧厢时间轴) -->
271
+ <span
272
+ v-if="compact"
273
+ class="ghost-time"
274
+ >{{ time.slice(0, 5) }}</span>
275
+
276
+ <component
277
+ :is="body"
278
+ :block="block"
279
+ class="eb-body"
280
+ />
281
+ </div>
282
+ </section>
283
+ </template>
284
+
285
+ <style scoped>
286
+ /* Slack 聊天行:行跨度经头像列成组;默认无左缘,仅终局/注意级/流式/错误插色缘 */
287
+ .event-block {
288
+ position: relative;
289
+ display: grid;
290
+ grid-template-columns: 30px minmax(0, 1fr);
291
+ column-gap: 11px;
292
+ padding: 5px 10px 4px 12px;
293
+ margin: 0;
294
+ transition: background 0.15s ease;
295
+ }
296
+
297
+ .event-block:hover {
298
+ background: var(--hover-tint);
299
+ border-radius: 4px;
300
+ }
301
+
302
+ /* 进场编排(open-tag motion charter):仅实时新块,60ms burst stagger;
303
+ * 历史/过滤重建直接显示(reduced-motion 直显) */
304
+ .event-block.enter {
305
+ animation: block-in 0.32s var(--ease-out-quart) backwards;
306
+ animation-delay: var(--d, 0ms);
307
+ }
308
+ @media (prefers-reduced-motion: reduce) {
309
+ .event-block.enter { animation: none; }
310
+ }
311
+
312
+ /* turn 边界:不同 agent 的新回合 → 加大间距 + 顶部 hairline(角色回合切换) */
313
+ .event-block.turn-start {
314
+ margin-top: 13px;
315
+ padding-top: 9px;
316
+ border-top: 1px solid var(--line);
317
+ }
318
+ .event-block.turn-start.compact {
319
+ margin-top: 0;
320
+ padding-top: 5px;
321
+ border-top: 0;
322
+ }
323
+
324
+ .event-block[data-kind='stream']:not([data-settled='true']) {
325
+ background: color-mix(in srgb, var(--ink) 2.5%, transparent);
326
+ border-radius: 4px;
327
+ }
328
+ /* 仅注意/错误级接入色缘(兑色低饱和度;终局不加彩色缘,靠名字加粗表意) */
329
+ .event-block[data-tier='attention'] {
330
+ box-shadow: inset 2px 0 0 color-mix(in srgb, var(--tone-warning-dot) 55%, transparent);
331
+ }
332
+ .event-block[data-kind='error'] {
333
+ box-shadow: inset 2px 0 0 color-mix(in srgb, var(--tone-danger-dot) 70%, transparent);
334
+ }
335
+ .event-block[data-covered='true'] { opacity: 0.72; }
336
+
337
+ .event-block[data-tier='terminal'] .agent-name { font-weight: 700; }
338
+ .event-block[data-tier='silent'] { opacity: 0.88; }
339
+ .event-block[data-tier='silent']:hover { opacity: 1; }
340
+
341
+ .tier-attention {
342
+ display: inline-flex;
343
+ gap: 3px;
344
+ align-items: center;
345
+ padding: 0 5px;
346
+ font-size: 10px;
347
+ color: var(--tone-warning-dot);
348
+ background: color-mix(in srgb, var(--tone-warning-dot) 13%, transparent);
349
+ border-radius: var(--radius-chip);
350
+ }
351
+ @keyframes block-in {
352
+ from {
353
+ opacity: 0;
354
+ transform: translateY(4px);
355
+ }
356
+ to {
357
+ opacity: 1;
358
+ transform: none;
359
+ }
360
+ }
361
+
362
+ /* 头像列:agent = 身份色(agentId 哈希 → --av,同源色相,白字首字母);
363
+ human/system = surface(open-tag av 尺寸档 36/28) */
364
+ .agent-avatar {
365
+ position: relative;
366
+ display: flex;
367
+ align-items: center;
368
+ justify-content: center;
369
+ width: 30px;
370
+ height: 30px;
371
+ min-width: 30px;
372
+ margin-top: 0;
373
+ padding: 0;
374
+ font-family: var(--font-body);
375
+ font-size: 12px;
376
+ font-weight: 600;
377
+ color: var(--ink);
378
+ background: var(--paper-deep);
379
+ border: 0;
380
+ border-radius: 50%;
381
+ }
382
+ .agent-avatar.clickable {
383
+ cursor: pointer;
384
+ transition: transform var(--transition-fast) var(--im-spring), box-shadow var(--transition-fast);
385
+ }
386
+ .agent-avatar.clickable:hover {
387
+ transform: scale(1.06);
388
+ box-shadow: 0 0 0 var(--radius-chip) transparent, 0 3px 10px rgb(12 10 9 / 16%);
389
+ }
390
+ .agent-avatar.is-agent {
391
+ color: var(--on-av);
392
+ background: var(--av, var(--av-fallback));
393
+ }
394
+ .agent-avatar.is-human {
395
+ color: var(--ink-soft);
396
+ background: var(--paper-deep);
397
+ box-shadow: inset 0 0 0 1px var(--line-strong);
398
+ }
399
+ .agent-avatar .system-icon {
400
+ font-size: 15px;
401
+ line-height: 1;
402
+ }
403
+
404
+ /* 状态 pip:头像右下 8px 叠层(open-tag av-status);busy 呼吸,stopped 灰,idle 淡 */
405
+ .av-status {
406
+ position: absolute;
407
+ right: -2px;
408
+ bottom: -2px;
409
+ width: 8px;
410
+ height: 8px;
411
+ background: var(--ink-fainter);
412
+ border: 1.5px solid var(--paper-raised);
413
+ border-radius: 50%;
414
+ }
415
+ .av-status.busy {
416
+ background: var(--tone-live-dot);
417
+ animation: av-breathe 1.9s ease-in-out infinite;
418
+ }
419
+ .av-status.stopped { background: var(--tone-danger-dot); }
420
+ @keyframes av-breathe {
421
+ 0%, 100% { opacity: 0.55; }
422
+ 50% { opacity: 1; }
423
+ }
424
+ @media (prefers-reduced-motion: reduce) {
425
+ .av-status.busy { animation: none; opacity: 0.9; }
426
+ }
427
+
428
+ /* 紧凑分组:隐藏头像与头部,保留列对齐(Slack 连续消息;ghost 时间月台悬浮显) */
429
+ .event-block.compact .agent-avatar {
430
+ visibility: hidden;
431
+ height: 0;
432
+ margin-top: 0;
433
+ }
434
+ .event-block.compact {
435
+ padding-top: 2px;
436
+ padding-bottom: 2px;
437
+ }
438
+ .event-block.compact + .event-block.compact {
439
+ margin-top: -2px;
440
+ }
441
+
442
+ .eb-main {
443
+ min-width: 0;
444
+ }
445
+
446
+ .block-head {
447
+ position: relative;
448
+ display: flex;
449
+ gap: 8px;
450
+ align-items: center;
451
+ min-height: 20px;
452
+ padding-bottom: 1px;
453
+ font-family: var(--font-body);
454
+ }
455
+
456
+ .agent-name {
457
+ overflow: hidden;
458
+ max-width: 220px;
459
+ font-size: 13px;
460
+ font-weight: 600;
461
+ color: var(--ink);
462
+ text-overflow: ellipsis;
463
+ white-space: nowrap;
464
+ }
465
+
466
+ /* 身份字幕(open-tag msg-role):lead/worker · harness,灰调不与之争关注 */
467
+ .role-label {
468
+ overflow: hidden;
469
+ font-family: var(--font-body);
470
+ font-size: 10.5px;
471
+ color: var(--ink-faint);
472
+ text-overflow: ellipsis;
473
+ white-space: nowrap;
474
+ }
475
+
476
+ /* 类别小标:中性等宽纯文本(无边框/无彩色点 —— 类别是元语不是状态,
477
+ 彩色语义只留给 attention/error 边缘) */
478
+ .kind-chip {
479
+ display: inline-flex;
480
+ align-items: center;
481
+ padding: 0 2px;
482
+ font-family: var(--font-mono);
483
+ font-size: 10px;
484
+ letter-spacing: 0.06em;
485
+ line-height: 14px;
486
+ color: var(--ink-faint);
487
+ }
488
+ .head-right {
489
+ display: flex;
490
+ flex: 1 1 auto;
491
+ gap: 6px;
492
+ align-items: center;
493
+ justify-content: flex-end;
494
+ font-size: 9.5px;
495
+ font-variant-numeric: tabular-nums;
496
+ color: var(--ink-faint);
497
+ }
498
+ .folded {
499
+ padding: 0 4px;
500
+ color: var(--ink-faint);
501
+ background: color-mix(in srgb, var(--ink) 7%, transparent);
502
+ border-radius: var(--radius-chip);
503
+ }
504
+ .merged {
505
+ padding: 0 4px;
506
+ background: color-mix(in srgb, var(--ink) 7%, transparent);
507
+ border-radius: var(--radius-chip);
508
+ }
509
+ .time {
510
+ flex: 0 0 auto;
511
+ width: 60px;
512
+ font-family: var(--font-mono);
513
+ font-size: 9.5px;
514
+ font-variant-numeric: tabular-nums;
515
+ text-align: right;
516
+ }
517
+
518
+ /* 紧凑态月台时间:悬停行时右侧浮现(Slack 紧凑组的时间轴补偿;仅住行头) */
519
+ .ghost-time {
520
+ position: absolute;
521
+ top: 3px;
522
+ right: 10px;
523
+ z-index: 2;
524
+ padding: 0 5px;
525
+ font-family: var(--font-mono);
526
+ font-size: 10px;
527
+ font-variant-numeric: tabular-nums;
528
+ color: var(--ink-faint);
529
+ pointer-events: none;
530
+ opacity: 0;
531
+ background: var(--paper-raised);
532
+ border-radius: var(--radius-chip);
533
+ transition: opacity var(--transition-fast);
534
+ }
535
+ .event-block.compact:hover .ghost-time {
536
+ opacity: 1;
537
+ }
538
+
539
+ /* 流式运行指示(open-tag msg-agent-state):暖橙呼吸点 + 词 */
540
+ .running-chip {
541
+ display: inline-flex;
542
+ gap: 4px;
543
+ align-items: center;
544
+ color: var(--ink-faint);
545
+ }
546
+ .running-chip .running-dot {
547
+ width: 6px;
548
+ height: 6px;
549
+ background: var(--tone-live-dot);
550
+ border-radius: 50%;
551
+ animation: av-breathe 1.9s ease-in-out infinite;
552
+ }
553
+ @media (prefers-reduced-motion: reduce) {
554
+ .running-chip .running-dot { animation: none; opacity: 0.9; }
555
+ }
556
+
557
+ /* 悬停工具条:头部右侧浮出(复制/引用) */
558
+ .eb-toolbar {
559
+ position: absolute;
560
+ top: -4px;
561
+ right: 56px;
562
+ z-index: 5;
563
+ display: inline-flex;
564
+ gap: 2px;
565
+ padding: 1px;
566
+ opacity: 0;
567
+ pointer-events: none;
568
+ background: var(--paper-raised);
569
+ border: 1px solid var(--line);
570
+ border-radius: var(--radius-chip);
571
+ transition: opacity var(--transition-fast);
572
+ }
573
+ .event-block:hover .eb-toolbar {
574
+ opacity: 1;
575
+ pointer-events: auto;
576
+ }
577
+ .eb-tool {
578
+ display: inline-flex;
579
+ align-items: center;
580
+ justify-content: center;
581
+ width: 22px;
582
+ height: 22px;
583
+ padding: 0;
584
+ font-size: 12px;
585
+ color: var(--ink-faint);
586
+ cursor: pointer;
587
+ background: transparent;
588
+ border: 0;
589
+ border-radius: var(--radius-chip);
590
+ transition: color var(--transition-fast), background var(--transition-fast);
591
+ }
592
+ .eb-tool:hover {
593
+ color: var(--ink);
594
+ background: var(--paper-deep);
595
+ }
596
+
597
+ /* 块体组件统一缩进归零(布局由本壳层的头像列接管;子组件自带 padding-left 归拢到内容列起点) */
598
+ .eb-body {
599
+ padding-left: 2px !important;
600
+ margin-top: 1px;
601
+ }
602
+ </style>