agentworkshop 0.7.40 → 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 (327) 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/{DcsCcxp4.js → D98NH8kG.js} +1 -1
  11. package/.output/public/_nuxt/DKySmNPI.js +14 -0
  12. package/.output/public/_nuxt/Di0NY_ht.js +1 -0
  13. package/.output/public/_nuxt/Du9v6qGB.js +1 -0
  14. package/.output/public/_nuxt/{C_iYD-EB.js → EHlEMRii.js} +1 -1
  15. package/.output/public/_nuxt/Eke1fs-U.js +1 -0
  16. package/.output/public/_nuxt/{DeJykBFf.js → H0BcqZtT.js} +1 -1
  17. package/.output/public/_nuxt/{C4oW1HsE.js → HSYEkkce.js} +1 -1
  18. package/.output/public/_nuxt/{DZshyNLa.js → IREZ1eC2.js} +1 -1
  19. package/.output/public/_nuxt/{D_OTvQza.js → J9oU00D1.js} +1 -1
  20. package/.output/public/_nuxt/OmpTerminalPanel.BxR5-lvi.css +1 -0
  21. package/.output/public/_nuxt/SSyAPaHc.js +1 -0
  22. package/.output/public/_nuxt/TownView.li4EMQxK.css +1 -0
  23. package/.output/public/_nuxt/VdLk4jLE2.js +1 -0
  24. package/.output/public/_nuxt/_id_.BhsXoEuk.css +1 -0
  25. package/.output/public/_nuxt/_id_.DQyj-WKN.css +1 -0
  26. package/.output/public/_nuxt/{_wsId_.B4WiqkIS.css → _wsId_.CTx-BlfF.css} +1 -1
  27. package/.output/public/_nuxt/aShsv_rG.js +19 -0
  28. package/.output/public/_nuxt/{yF0aYMF1.js → aesgXKSr.js} +3 -3
  29. package/.output/public/_nuxt/agents.B21nUEUX.css +1 -0
  30. package/.output/public/_nuxt/aml.ekTjxFkf.css +1 -0
  31. package/.output/public/_nuxt/builds/latest.json +1 -1
  32. package/.output/public/_nuxt/builds/meta/b5506ef0-f48e-4f14-a6c0-d65e505d0b09.json +1 -0
  33. package/.output/public/_nuxt/ca4TJ3Op.js +1 -0
  34. package/.output/public/_nuxt/channel-templates.DplM1pJ3.css +1 -0
  35. package/.output/public/_nuxt/daq.BdVmoIfe.css +1 -0
  36. package/.output/public/_nuxt/dcw.DCgyzpWV.css +1 -0
  37. package/.output/public/_nuxt/{default.J32SgqFY.css → default.Bh3L2HU8.css} +1 -1
  38. package/.output/public/_nuxt/lHAxdSsj.js +1 -0
  39. package/.output/public/_nuxt/pages.j9rzRocr.css +1 -0
  40. package/.output/public/_nuxt/plugins.DhiZbHU8.css +1 -0
  41. package/.output/public/_nuxt/settings.BRx9rIDg.css +1 -0
  42. package/.output/public/_nuxt/teams.BLlOPB_Z.css +1 -0
  43. package/.output/public/_nuxt/tokens.De8xzszn.css +1 -0
  44. package/.output/public/_nuxt/workshop.D1jFNkrn.css +1 -0
  45. package/.output/server/chunks/_/nitro.mjs +1058 -830
  46. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  47. package/.output/server/chunks/build/{OmpTerminalPanel-Cu_s4i0A.mjs → OmpTerminalPanel-CVvxpsF7.mjs} +15 -15
  48. package/.output/server/chunks/build/{OmpTerminalPanel-Cu_s4i0A.mjs.map → OmpTerminalPanel-CVvxpsF7.mjs.map} +1 -1
  49. package/.output/server/chunks/build/{TownView-BuLAsmpR.mjs → TownView-CJ6IsDCc.mjs} +229 -228
  50. package/.output/server/chunks/build/{TownView-BuLAsmpR.mjs.map → TownView-CJ6IsDCc.mjs.map} +1 -1
  51. package/.output/server/chunks/build/{_id_-BU1wfOID.mjs → _id_-CVD_H0ir.mjs} +149 -147
  52. package/.output/server/chunks/build/_id_-CVD_H0ir.mjs.map +1 -0
  53. package/.output/server/chunks/build/{_id_-BYsEua57.mjs → _id_-CtxMb3qp.mjs} +47 -46
  54. package/.output/server/chunks/build/_id_-CtxMb3qp.mjs.map +1 -0
  55. package/.output/server/chunks/build/{_wsId_-BxlDcJHg.mjs → _wsId_-DpY3T-md.mjs} +516 -446
  56. package/.output/server/chunks/build/{_wsId_-BxlDcJHg.mjs.map → _wsId_-DpY3T-md.mjs.map} +1 -1
  57. package/.output/server/chunks/build/{agents-CLQqJF2y.mjs → agents-DsCkuXDV.mjs} +49 -46
  58. package/.output/server/chunks/build/agents-DsCkuXDV.mjs.map +1 -0
  59. package/.output/server/chunks/build/{aml-_7FdFL2p.mjs → aml-CT0xKGKI.mjs} +122 -105
  60. package/.output/server/chunks/build/aml-CT0xKGKI.mjs.map +1 -0
  61. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs +117 -0
  62. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs.map +1 -0
  63. package/.output/server/chunks/build/{channel-templates-p6SZNjlM.mjs → channel-templates-Dla9FbYa.mjs} +49 -37
  64. package/.output/server/chunks/build/channel-templates-Dla9FbYa.mjs.map +1 -0
  65. package/.output/server/chunks/build/{daq-cgyjKmJu.mjs → daq-DWWSKGAV.mjs} +95 -93
  66. package/.output/server/chunks/build/daq-DWWSKGAV.mjs.map +1 -0
  67. package/.output/server/chunks/build/{dcw-CoTxBlAZ.mjs → dcw-CT8k17_E.mjs} +46 -45
  68. package/.output/server/chunks/build/dcw-CT8k17_E.mjs.map +1 -0
  69. package/.output/server/chunks/build/{default-BE4r0FZN.mjs → default-D3525UFX.mjs} +16 -15
  70. package/.output/server/chunks/build/{default-BE4r0FZN.mjs.map → default-D3525UFX.mjs.map} +1 -1
  71. package/.output/server/chunks/build/{logs-BSOeZwwI.mjs → logs--dByNyhw.mjs} +2 -2
  72. package/.output/server/chunks/build/{logs-BSOeZwwI.mjs.map → logs--dByNyhw.mjs.map} +1 -1
  73. package/.output/server/chunks/build/{monitor-C0okQaXz.mjs → monitor-Dh2Kvaq5.mjs} +2 -2
  74. package/.output/server/chunks/build/{monitor-C0okQaXz.mjs.map → monitor-Dh2Kvaq5.mjs.map} +1 -1
  75. package/.output/server/chunks/build/{pages-DFxjn9Xa.mjs → pages-BHcSBM2D.mjs} +26 -20
  76. package/.output/server/chunks/build/pages-BHcSBM2D.mjs.map +1 -0
  77. package/.output/server/chunks/build/{plugins-lGlUr1lj.mjs → plugins-BNgIi61W.mjs} +23 -17
  78. package/.output/server/chunks/build/plugins-BNgIi61W.mjs.map +1 -0
  79. package/.output/server/chunks/build/{settings-Ddd1qx2Z.mjs → settings-ipYBDWdn.mjs} +45 -44
  80. package/.output/server/chunks/build/settings-ipYBDWdn.mjs.map +1 -0
  81. package/.output/server/chunks/build/{teams-MEDLZdMn.mjs → teams-5lx-CwFa.mjs} +47 -44
  82. package/.output/server/chunks/build/teams-5lx-CwFa.mjs.map +1 -0
  83. package/.output/server/chunks/build/{tokens-C7fTM5C2.mjs → tokens-q-IDT8Io.mjs} +73 -53
  84. package/.output/server/chunks/build/tokens-q-IDT8Io.mjs.map +1 -0
  85. package/.output/server/chunks/build/{town-qMPql9Se.mjs → town-QJWB5wng.mjs} +5 -4
  86. package/.output/server/chunks/build/town-QJWB5wng.mjs.map +1 -0
  87. package/.output/server/chunks/build/{useDaqStream-CIBaiGAl.mjs → useDaqStream-DfCFpb3p.mjs} +9 -3
  88. package/.output/server/chunks/build/useDaqStream-DfCFpb3p.mjs.map +1 -0
  89. package/.output/server/chunks/build/{useDcwStream-CBbiYnWe.mjs → useDcwStream-UPiX-3iO.mjs} +11 -2
  90. package/.output/server/chunks/build/useDcwStream-UPiX-3iO.mjs.map +1 -0
  91. package/.output/server/chunks/build/{workshop-BL5bhfs0.mjs → workshop-BIlCj_ZP.mjs} +45 -45
  92. package/.output/server/chunks/build/workshop-BIlCj_ZP.mjs.map +1 -0
  93. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  94. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +3 -3
  95. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
  96. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
  97. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
  98. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
  99. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
  100. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  101. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  102. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  103. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  104. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  105. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  106. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  107. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +3 -1
  108. package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
  109. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +3 -1
  110. package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
  111. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  112. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  113. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  114. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  115. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  116. package/.output/server/chunks/routes/renderer.mjs +2 -2
  117. package/.output/server/chunks/virtual/entry.mjs +639 -88
  118. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  119. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  120. package/.output/server/package.json +1 -1
  121. package/README-zh.md +16 -6
  122. package/README.md +17 -7
  123. package/app/components/AppHeader.vue +961 -959
  124. package/app/components/workshop/A2aRpcDebugger.vue +237 -237
  125. package/app/components/workshop/AgentInspectorDrawer.vue +424 -424
  126. package/app/components/workshop/AgentLanesView.vue +998 -998
  127. package/app/components/workshop/ArtifactCard.vue +120 -120
  128. package/app/components/workshop/AssetLibrary.vue +452 -452
  129. package/app/components/workshop/ChannelSessionList.vue +812 -804
  130. package/app/components/workshop/CommandPalette.vue +269 -269
  131. package/app/components/workshop/Composer.vue +827 -827
  132. package/app/components/workshop/DeviceTwinPanel.vue +643 -643
  133. package/app/components/workshop/EventBlock.vue +602 -602
  134. package/app/components/workshop/FileSelectorModal.vue +188 -188
  135. package/app/components/workshop/InspectorPanel.vue +301 -301
  136. package/app/components/workshop/MemoryPanel.vue +364 -364
  137. package/app/components/workshop/MultiChannelView.vue +189 -189
  138. package/app/components/workshop/TaskBoardView.vue +686 -686
  139. package/app/components/workshop/TaskInspectorDrawer.vue +390 -390
  140. package/app/components/workshop/TranscriptTimeline.vue +601 -601
  141. package/app/components/workshop/blocks/ClusterArtifact.vue +61 -61
  142. package/app/components/workshop/blocks/ClusterError.vue +85 -85
  143. package/app/components/workshop/blocks/ClusterLife.vue +87 -87
  144. package/app/components/workshop/blocks/ClusterMember.vue +95 -93
  145. package/app/components/workshop/blocks/ClusterMemory.vue +84 -84
  146. package/app/components/workshop/blocks/ClusterOther.vue +67 -67
  147. package/app/components/workshop/blocks/ClusterStatus.vue +149 -147
  148. package/app/components/workshop/blocks/ClusterTool.vue +158 -158
  149. package/app/components/workshop/terminal/OmpTerminalPanel.vue +1011 -1011
  150. package/app/components/workshop/town/TownView.vue +56 -56
  151. package/app/composables/workshop/useDaqStream.ts +7 -4
  152. package/app/composables/workshop/useDcwStream.ts +8 -2
  153. package/app/middleware/locale-cookie.global.ts +22 -0
  154. package/app/pages/aml/index.vue +24 -2
  155. package/app/pages/daq/[id].vue +20 -16
  156. package/app/pages/daq/index.vue +2310 -2307
  157. package/app/pages/dcw/[id].vue +26 -23
  158. package/app/pages/dcw/index.vue +3 -3
  159. package/app/pages/index.vue +987 -981
  160. package/app/pages/plugins/index.vue +317 -311
  161. package/app/pages/settings.vue +1564 -1562
  162. package/app/pages/tokens.vue +15 -15
  163. package/app/pages/workshop/agents.vue +612 -609
  164. package/app/pages/workshop/channel-templates.vue +18 -11
  165. package/app/pages/workshop/index.vue +668 -668
  166. package/app/pages/workshop/teams.vue +743 -740
  167. package/app/pages/workshop/w/[wsId].vue +704 -704
  168. package/app/plugins/locale-restore.client.ts +16 -1
  169. package/app/utils/builtin-catalog.ts +104 -0
  170. package/config.yml +170 -170
  171. package/docs/cli.en.md +2 -2
  172. package/docs/cli.md +2 -2
  173. package/docs/full-test-plan.md +2 -3
  174. package/docs/plugins.en.md +33 -1
  175. package/docs/plugins.md +29 -1
  176. package/docs/sdk.en.md +1 -1
  177. package/docs/sdk.md +1 -1
  178. package/i18n/locales/en.ts +293 -35
  179. package/i18n/locales/zh-CN.ts +265 -7
  180. package/package.json +4 -3
  181. package/scripts/_dbg-perms-e2e.mjs +132 -109
  182. package/scripts/_demo-agentteam-capture.mjs +278 -0
  183. package/scripts/_e2e-ui-functional.mjs +371 -0
  184. package/scripts/_i18n-en-cjk-scan.mjs +28 -0
  185. package/scripts/_i18n-en-verify.mjs +107 -0
  186. package/scripts/_i18n-extra-checks.mjs +53 -0
  187. package/scripts/_i18n-scan-hardcoded.mjs +180 -0
  188. package/scripts/_i18n-verify-keys.mjs +50 -0
  189. package/scripts/_loop-biax-campaign.mjs +130 -0
  190. package/scripts/_sweep-button-contrast.mjs +87 -0
  191. package/scripts/test-serial-bridge.mjs +418 -0
  192. package/scripts/ui/e2e-interactive.mjs +328 -0
  193. package/scripts/ui/record-demo.mjs +557 -0
  194. package/scripts/ui/seed-industrial-demo.mjs +171 -0
  195. package/server/api/workshop/daq/index.get.ts +3 -1
  196. package/server/api/workshop/dcw/index.get.ts +3 -0
  197. package/server/plugins/aw-plugins.ts +9 -7
  198. package/server/plugins-builtin/diag-bridge/index.mjs +608 -661
  199. package/server/plugins-builtin/rag-bridge/index.mjs +57 -133
  200. package/server/plugins-builtin/serial-bridge/client.mjs +210 -0
  201. package/server/plugins-builtin/serial-bridge/drivers.mjs +409 -0
  202. package/server/plugins-builtin/serial-bridge/i18n.json +62 -0
  203. package/server/plugins-builtin/serial-bridge/index.mjs +247 -0
  204. package/server/plugins-builtin/serial-bridge/lib.mjs +208 -0
  205. package/server/plugins-builtin/serial-bridge/rtu.mjs +168 -0
  206. package/server/services/workshop/daq/daq-controller.ts +7 -2
  207. package/server/services/workshop/daq/drivers.ts +89 -3
  208. package/server/services/workshop/dcw/dcw-controller.ts +5 -1
  209. package/server/services/workshop/dcw/drivers.ts +85 -2
  210. package/server/services/workshop/dcw/plugin-bridge.ts +45 -0
  211. package/server/services/workshop/plugins/host.mjs +30 -0
  212. package/shared/daq-protocol.ts +15 -0
  213. package/.output/public/_nuxt/88GOowgO2.js +0 -1
  214. package/.output/public/_nuxt/BOt2SP4z.js +0 -1
  215. package/.output/public/_nuxt/BP-NyKVG.js +0 -18
  216. package/.output/public/_nuxt/BXxH0UQE.js +0 -1
  217. package/.output/public/_nuxt/BsROmY89.js +0 -1
  218. package/.output/public/_nuxt/ClILjvWH.js +0 -1
  219. package/.output/public/_nuxt/CzOCSGLe.js +0 -1
  220. package/.output/public/_nuxt/D8qvkfyY.js +0 -1
  221. package/.output/public/_nuxt/DCn7QZ5N.js +0 -2
  222. package/.output/public/_nuxt/DS8qj8EL.js +0 -1
  223. package/.output/public/_nuxt/DUjW5Yq5.js +0 -1
  224. package/.output/public/_nuxt/Dihnimlk.js +0 -19
  225. package/.output/public/_nuxt/Dqw1lpr-.js +0 -1
  226. package/.output/public/_nuxt/Dr9v6C0f.js +0 -14
  227. package/.output/public/_nuxt/Du9ZJtnj.js +0 -1
  228. package/.output/public/_nuxt/OmpTerminalPanel.B_Pl5Ynm.css +0 -1
  229. package/.output/public/_nuxt/TownView.f-YOdXRs.css +0 -1
  230. package/.output/public/_nuxt/_id_.CM4bIgKY.css +0 -1
  231. package/.output/public/_nuxt/_id_.bNV69Dtf.css +0 -1
  232. package/.output/public/_nuxt/agents.ZD0rVdHE.css +0 -1
  233. package/.output/public/_nuxt/aml.BN8ZEW4h.css +0 -1
  234. package/.output/public/_nuxt/builds/meta/f4707884-7cf4-4a31-80d2-e3d72b73745f.json +0 -1
  235. package/.output/public/_nuxt/channel-templates.BOtahzPi.css +0 -1
  236. package/.output/public/_nuxt/daq.B0D3dPAc.css +0 -1
  237. package/.output/public/_nuxt/dcw.8Y7FqCVN.css +0 -1
  238. package/.output/public/_nuxt/pages.D7aSDlUI.css +0 -1
  239. package/.output/public/_nuxt/plugins.sb4nDGqr.css +0 -1
  240. package/.output/public/_nuxt/qr6R6Ha1.js +0 -1
  241. package/.output/public/_nuxt/settings.BTgR-NiE.css +0 -1
  242. package/.output/public/_nuxt/teams.CxnxKVVs.css +0 -1
  243. package/.output/public/_nuxt/tokens.BFY7qv4f.css +0 -1
  244. package/.output/public/_nuxt/workshop.CR_QzeAN.css +0 -1
  245. package/.output/server/chunks/build/_id_-BU1wfOID.mjs.map +0 -1
  246. package/.output/server/chunks/build/_id_-BYsEua57.mjs.map +0 -1
  247. package/.output/server/chunks/build/agents-CLQqJF2y.mjs.map +0 -1
  248. package/.output/server/chunks/build/aml-_7FdFL2p.mjs.map +0 -1
  249. package/.output/server/chunks/build/channel-templates-p6SZNjlM.mjs.map +0 -1
  250. package/.output/server/chunks/build/daq-cgyjKmJu.mjs.map +0 -1
  251. package/.output/server/chunks/build/dcw-CoTxBlAZ.mjs.map +0 -1
  252. package/.output/server/chunks/build/pages-DFxjn9Xa.mjs.map +0 -1
  253. package/.output/server/chunks/build/plugins-lGlUr1lj.mjs.map +0 -1
  254. package/.output/server/chunks/build/settings-Ddd1qx2Z.mjs.map +0 -1
  255. package/.output/server/chunks/build/teams-MEDLZdMn.mjs.map +0 -1
  256. package/.output/server/chunks/build/tokens-C7fTM5C2.mjs.map +0 -1
  257. package/.output/server/chunks/build/town-qMPql9Se.mjs.map +0 -1
  258. package/.output/server/chunks/build/useDaqStream-CIBaiGAl.mjs.map +0 -1
  259. package/.output/server/chunks/build/useDcwStream-CBbiYnWe.mjs.map +0 -1
  260. package/.output/server/chunks/build/workshop-BL5bhfs0.mjs.map +0 -1
  261. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.continue.json +0 -1
  262. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.json +0 -1
  263. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/054bb4bc4e4217a2ab0b0c6b663747214a9af464f5568ea60e784704e340bb0f.source +0 -153
  264. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/0554197c3d2bac203a1f5c48a5d52495d1336db1bd7aa4f4c19875810363e684.source +0 -153
  265. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/05c203d12a954fffba942e1d626e3f5fec05b18a5aef2bac003b7884a4b77406.source +0 -431
  266. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/145a6e6ba811af35aed31e0cc3211f53706a14980fa069ee9e3c1591139f96f0.source +0 -180
  267. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/1ae0fb281f97899c025e368ca73f41349b01fb5f85b19e08d7ebccff49095ed5.source +0 -112
  268. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/20ee9967aa0541c516db7575bdd4a1a745939bc7016bd10d7635903113edb8ec.source +0 -227
  269. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/233751843aeba9d4c5263f275b8102de00443c06f286918cbd23e0b6729e01aa.source +0 -131
  270. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/263c2e05b425e5c322e60c6475279f963bab3a873eb521b21df7fec935a46597.source +0 -160
  271. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/2ac5eaac28eaaee2178c4b32014df8e732f9dd432a285a872f5b7f31c1395fa4.source +0 -157
  272. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/33a0db0d2d95d2c11d0720090458e5fba1425376f5ceb5b422d1d3471be3226b.source +0 -348
  273. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/359e474ae83db35e4615d3728de6bf694b64d4dce9b536730a3b6518f9c0494a.source +0 -296
  274. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/37a4c3c31c4b70f6b719c53d1e9c4fcba603f31adfdd11bb6ef9f0d094923c56.source +0 -285
  275. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/461feca1c14a695eb8b0f17a6f95fe97eeceabc0510faaea4ba6d25bde147d8d.source +0 -217
  276. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/4cfadbda8591f29d5e1e230dc000e701b756e850441b3900fb596a4d2f6e98c2.source +0 -301
  277. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/50ca2810cf0b248c96948994c0c404531bbad6e553166b6816b3b03bfa0f75d2.source +0 -151
  278. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/52d9e8cb591a9ae86e238c3620a610cd386717bee222c0f37b25b2ac7e523dc4.source +0 -135
  279. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/6c87daafa4c006560a954636a97333f6123153c9d34d96203f7ee3a14e556357.source +0 -156
  280. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/77bc47854b577900621cacf1697f81fa2bc005af129d37614a97a3441c08f99f.source +0 -72
  281. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/7bbb789d3a527817118cf8399ed1861d6a962ade10878fd07223435d333a7089.source +0 -469
  282. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/86b7c1daafc8b60ba9982dde5bf1bcc74265709483c176e71f23ec6fc267451f.source +0 -259
  283. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/8df66d62bd41984d0970e8236882080c5085ac937d07a29779463d6a03b37c76.source +0 -97
  284. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/9962f2d1b3a85137bd40cc835725600b39f89ee02a27c06b2e0402e1eafde115.source +0 -277
  285. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/a1090ea066b792cb201739f4994e37bf7c12f52e805239a1eab87f18a537f266.source +0 -171
  286. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/a5241091650134d0919897e086a606a3846c8b2b54f8b4c84a8696c145ac3e9e.source +0 -425
  287. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/af19fa4c6e34d5540028be4b17600161283af3a2a2dfc61a3fdc0834436a0c14.source +0 -99
  288. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/b3713d78e2b2f93905ff6be8d58a8d0a2f42dea322eb67c987fda22ff6a084d5.source +0 -325
  289. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/b3849943c3aff102d1af815631fc843a2a52c17646a4b04696ece323e483bbec.source +0 -332
  290. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/bac735a3803a6650b7f1eb8f587e6dc5c68ea055000c3c99a11789438b78e837.source +0 -43
  291. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/d32c24d61eb8b33c73e5a8fc7e4dc7ef437aed238ee4371c2b00617e6104090a.source +0 -154
  292. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/d5170dc9a9879fda04fdf91d8a110d4efb6787ee38dda596d4da899883d36a72.source +0 -531
  293. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/dc59bcd7bb397be63ba2f2c3fec23f3782dcb17d2d75a9981eeced761f33eb32.source +0 -439
  294. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/eb5ff8cf66b92aec7bf6726781d8df74faa2b030c3aaac17d6b00c1fc04c9b32.source +0 -323
  295. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f10615a6fae18436e70d1201b2d44fdae3174a3aa7bb4db97dea1b3ed291d721.source +0 -433
  296. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f36d3e271668bc1260c2823542d22dbf1d0f7041ff16b1ac175bce2256e582ca.source +0 -280
  297. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/f94449380af09f31ac352152007146a75cc80bae8d6411ffe57b2c56f933b0ff.source +0 -117
  298. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/fe4dfd81178fd6b648335f6405d9ede71319aebde796008e50db21f8adf44c99.source +0 -160
  299. package/scripts/.mimosa/hook-state/sess_aeaecb58-8833-4b83-b93c-050467d21e03.mtxwtxme-61028-1f4519fbc4.baseline/ffb4e3aa548cfdadabaa44ab599f9b6a3ca6288176a2cc7a4b2fc2a12b5fb848.source +0 -101
  300. package/scripts/.mimosa/hook-status/sess_aeaecb58-8833-4b83-b93c-050467d21e03-d944d71bb3.json +0 -14
  301. package/scripts/_dbg-audit-all-pages.mjs +0 -43
  302. package/scripts/_dbg-daq-frames-e2e.mjs +0 -118
  303. package/scripts/_dbg-daq-rowstyle-verify.mjs +0 -112
  304. package/scripts/_dbg-hitl-timeout-e2e.mjs +0 -93
  305. package/scripts/_dbg-live-line-e2e.mjs +0 -279
  306. package/scripts/_dbg-minimal-omp.mjs +0 -77
  307. package/scripts/_dbg-mode-nav.mjs +0 -173
  308. package/scripts/_dbg-real-scenario-timeline.log +0 -55
  309. package/scripts/_dbg-team-repro.mjs +0 -76
  310. package/scripts/_dbg-town-agents-probe.mjs +0 -60
  311. package/scripts/_dbg-visual-acceptance.mjs +0 -63
  312. package/scripts/_townview_style.css +0 -1185
  313. package/scripts/_townview_template.html +0 -1215
  314. package/server/data/agent-node-bindings.json +0 -554
  315. package/server/data/daq-templates.json +0 -16
  316. package/server/data/daqs.json +0 -7464
  317. package/server/data/dcw-lines.json +0 -1787
  318. package/server/data/dcw-products.json +0 -1626
  319. package/server/data/dcw-recipes.json +0 -4672
  320. package/server/data/dcw-rollback.json +0 -20754
  321. package/server/data/dcw-runs.json +0 -6354
  322. package/server/data/dcw-templates.json +0 -146
  323. package/server/data/dcw-writes.json +0 -15650
  324. package/server/data/dcws.json +0 -9033
  325. package/server/data/device-twins.json +0 -133
  326. package/server/data/line-runs.json +0 -322
  327. 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>