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
@@ -0,0 +1,557 @@
1
+ /**
2
+ * AgentWorkShop 实机演示录屏工具 v4.1 —— 英文界面 + Edge 神经语音 + 章节化合成。
3
+ *
4
+ * 产出:docs/site/public/demo/agentworkshop-demo.mp4(1600×900@30,含配音)
5
+ * docs/site/public/demo/poster.jpg
6
+ *
7
+ * 架构:录制期间 Node 零 Runtime.evaluate(场景脚本整体下推页面内单函数自跑,
8
+ * Node 只负责 screencast 启停、定长 sleep 与孪生鼠标运镜)。场景级重试:
9
+ * 帧不足(渲染进程被重页面拖挂等)自动 reload 后重录一次。
10
+ *
11
+ * 用法:
12
+ * node scripts/ui/record-demo.mjs tts # 生成英文配音(edge-tts,增量)
13
+ * node scripts/ui/record-demo.mjs record # 录制 + 配音对齐 + 合成(含 poster)
14
+ */
15
+ import fs from 'node:fs'
16
+ import path from 'node:path'
17
+ import { execSync } from 'node:child_process'
18
+ import puppeteer from 'puppeteer-core'
19
+
20
+ const BASE = process.env.AW_BASE ?? 'http://127.0.0.1:3001'
21
+ const CHROME = process.env.AW_CHROME ?? 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
22
+ const OUT_DIR = path.resolve('docs/site/public/demo')
23
+ const WORK = path.resolve('.tmp-demo')
24
+ const EMAIL = 'admin@awshop.local'
25
+ const PASSWORD = 'admin123'
26
+ const VOICE = 'en-US-AndrewNeural'
27
+ const RATE = '-4%'
28
+ const HEAD = 1.6
29
+
30
+ const sleep = ms => new Promise(r => setTimeout(r, ms))
31
+ const sh = cmd => execSync(cmd, { stdio: ['ignore', 'ignore', 'pipe'] })
32
+ const probeDur = f => Number(execSync(`ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "${f}"`).toString().trim())
33
+
34
+ // ════ 解说词与场景规划(单一事实源) ═════════════════════════════════════════
35
+ const PLAN = [
36
+ {
37
+ id: 'title', chapter: null, url: 'card',
38
+ clips: [
39
+ { cap: 'AgentWorkShop', sub: 'INDUSTRIAL AGENT RUNTIME · RECORDED LIVE', say: 'Agent Work Shop — an industrial agent runtime, recorded live. Real protocols, real control — nothing in this demo is scripted.' },
40
+ ],
41
+ },
42
+ {
43
+ id: 'platform', chapter: '01|THE CONTROL ROOM', url: '/',
44
+ clips: [
45
+ { cap: 'The control room', sub: 'Every line, control node and sample in one view — live', say: 'The control room. Every production line, control node, and sample in one view — live.' },
46
+ { cap: '14 engines · 4 entry points', sub: 'WebSocket · MCP · A2A · REST', say: 'Fourteen agent engines behind one contract, and four entry points: WebSocket, M C P, A to A, and REST.' },
47
+ ],
48
+ },
49
+ {
50
+ id: 'telemetry', chapter: '02|LIVE TELEMETRY', url: '/daq',
51
+ clips: [
52
+ { cap: 'DAQ console — live telemetry', sub: '2,000+ channels across six field protocols', say: 'The data acquisition console. Over two thousand live channels across six field protocols: Modbus T C P and R T U, O P C U A, M Q T T, H T T P, and serial.' },
53
+ { cap: 'driver → queue → storage → WebSocket', sub: 'Every node keeps its own cadence', say: 'Samples flow from driver, through the queue, into time-series storage, then fan out over WebSockets. Every node keeps its own cadence.' },
54
+ ],
55
+ },
56
+ {
57
+ id: 'control', chapter: '03|GOVERNED CONTROL', url: '/dcw/ln-bcc8ea44',
58
+ clips: [
59
+ { cap: 'Writing to a real PLC', sub: 'Recipe interlock → safety limits → field', say: 'Now writing to a real PLC. Every setpoint passes the recipe interlock and the safety limits before anything reaches the field.' },
60
+ { cap: 'SET 150 °C → Modbus → read-back', sub: 'Watch the write land, then read the register straight back', say: 'Watch the write land: the platform drives the Modbus holding registers, then reads the value straight back from the device.' },
61
+ { cap: 'Read-back agrees — audit signed', sub: 'Who · when · why — every entry signed', say: 'One hundred and fifty degrees, confirmed by read-back, with a signed entry in the audit trail: who, when, and why.' },
62
+ ],
63
+ },
64
+ {
65
+ id: 'plugins', chapter: '04|PROTOCOLS ARE PLUGINS', url: '/plugins',
66
+ clips: [
67
+ { cap: 'Protocols are plugins', sub: 'ctx.daq.registerDriver · ctx.dcw.registerWriteDriver', say: 'Protocols are plugins. A driver registered through the SDK appears in the interface with its own configuration form — zero front-end changes.' },
68
+ { cap: 'serial-bridge — direct RS-232/485', sub: 'Modbus RTU + ASCII line, probe API included', say: 'The built-in serial bridge opens a real COM port and probes it. If nothing answers, it says so — honestly.' },
69
+ ],
70
+ },
71
+ {
72
+ id: 'agents', chapter: '05|AGENT TEAMS', url: 'workshop',
73
+ clips: [
74
+ { cap: 'The melt-optimization crew', sub: 'A lead agent · trend analyst · setpoint writer', say: 'This is the agent workshop, and this crew owns melt temperature optimization: a lead agent, a trend analyst, and a setpoint writer, supervised over A to A.' },
75
+ { cap: 'Dispatch a goal', sub: 'Lead decomposes → workers execute with tools', say: 'Dispatch a goal. The lead decomposes it, workers stream progress as they execute with tools, and every message lands on the audit trail.' },
76
+ { cap: 'Execution, live', sub: '7-state task machine · artifacts · real-time events', say: 'Task state, artifacts, and messages update in real time. The same seven-state machine backs every engine — from the scripted mock to a real L L M.' },
77
+ ],
78
+ },
79
+ {
80
+ id: 'loop', chapter: '06|THE CLOSED LOOP', url: 'pvnode',
81
+ clips: [
82
+ { cap: 'The closed loop', sub: 'Analyze → propose → approve → write → verify', say: 'The closed loop, end to end. Analyze the trend, propose a setpoint, take the human approval, write to the PLC, and verify — the process value follows.' },
83
+ { cap: 'PV tracks the setpoint', sub: 'SET and ACT — one calibration, both directions', say: 'The process value tracks the setpoint through the real control chain. The same calibration reads back what was written: S E T and A C T, side by side.' },
84
+ ],
85
+ },
86
+ {
87
+ id: 'twin', chapter: '07|THE DIGITAL TWIN', url: '/town',
88
+ clips: [
89
+ { cap: 'The digital twin', sub: 'Live tags · device health · alarms — one event bus', say: 'And everything streams into a three-D digital twin. Live tags, device health, and alarms — all rendered from the same event bus.' },
90
+ { cap: '2,000+ channels · one scene', sub: 'Nothing mocked', say: 'Two thousand channels, one scene — nothing mocked.' },
91
+ ],
92
+ },
93
+ {
94
+ id: 'outro', chapter: null, url: '/',
95
+ clips: [
96
+ { cap: 'AgentWorkShop v0.7.41', sub: 'Open source · PolyForm NC · github.com/kingdol666/AgentWorkShop', say: 'Agent Work Shop, version zero point seven forty one. Open source under PolyForm N C. Find it on Git Hub — king dol sixty six, slash, Agent Work Shop.' },
97
+ ],
98
+ },
99
+ ]
100
+
101
+ // ════ 阶段 1:TTS(edge-tts 神经语音,增量) ═════════════════════════════════
102
+ async function ttsPhase() {
103
+ const narrDir = path.join(WORK, 'narr')
104
+ fs.mkdirSync(narrDir, { recursive: true })
105
+ for (const scene of PLAN) {
106
+ for (let k = 0; k < scene.clips.length; k++) {
107
+ const id = `${scene.id}_${k}`
108
+ const mp3 = path.join(narrDir, `${id}.mp3`)
109
+ const wav = path.join(narrDir, `${id}.wav`)
110
+ if (fs.existsSync(wav)) continue
111
+ const text = scene.clips[k].say.replace(/"/g, '\\"')
112
+ sh(`edge-tts --voice ${VOICE} --rate=${RATE} --text "${text}" --write-media "${mp3}"`)
113
+ sh(`ffmpeg -y -v error -i "${mp3}" -af "loudnorm=I=-16:TP=-1.5" -ar 44100 -ac 2 "${wav}"`)
114
+ console.log(` tts ${id}`)
115
+ }
116
+ }
117
+ const durations = {}
118
+ for (const scene of PLAN) {
119
+ for (let k = 0; k < scene.clips.length; k++) {
120
+ durations[`${scene.id}_${k}`] = probeDur(path.join(narrDir, `${scene.id}_${k}.wav`))
121
+ }
122
+ }
123
+ fs.writeFileSync(path.join(narrDir, 'durations.json'), JSON.stringify(durations, null, 2))
124
+ console.log('✅ TTS 完成:', JSON.stringify(durations))
125
+ }
126
+
127
+ // ════ 页面内叠加层(序列化注入) ══════════════════════════════════════════════
128
+ const OVERLAY_FN = () => {
129
+ if (window.__demoInstalled) {
130
+ window.__demoRebuild()
131
+ return
132
+ }
133
+ window.__demoInstalled = true
134
+ const css = document.createElement('style')
135
+ css.textContent = `
136
+ #aw-demo-cap { position: fixed; left: 50%; bottom: 42px; transform: translateX(-50%);
137
+ max-width: 82vw; z-index: 2147483000; pointer-events: none; text-align: center;
138
+ background: rgba(7,11,19,.84); border: 1px solid rgba(65,200,244,.35);
139
+ border-radius: 12px; padding: 14px 26px;
140
+ font: 600 21px/1.45 'Segoe UI', system-ui, sans-serif; color: #eaf6ff;
141
+ box-shadow: 0 8px 32px rgba(0,0,0,.45); backdrop-filter: blur(6px);
142
+ transition: opacity .45s ease; opacity: 0; }
143
+ #aw-demo-cap .sub { display: block; margin-top: 4px; font: 400 15px/1.4 'Segoe UI', system-ui, sans-serif;
144
+ color: #7dd8c8; letter-spacing: .4px; }
145
+ #aw-demo-cap .tag { position: absolute; top: -11px; left: 18px; background: #35e0a0; color: #06251a;
146
+ font: 700 11px/1 'Segoe UI', sans-serif; letter-spacing: 1.5px; padding: 4px 9px; border-radius: 6px; }
147
+ #aw-demo-veil { position: fixed; inset: 0; background: #000; z-index: 2147483001;
148
+ pointer-events: none; opacity: 0; transition: opacity .4s ease; }
149
+ #aw-demo-card { position: fixed; inset: 0; background: #05080f; z-index: 2147482999;
150
+ display: none; align-items: center; justify-content: center; flex-direction: column; gap: 14px; }
151
+ #aw-demo-card .no { font: 700 15px/1 'Segoe UI', sans-serif; letter-spacing: 4px; color: #35e0a0; }
152
+ #aw-demo-card .tt { font: 600 54px/1.2 Georgia, 'Times New Roman', serif; color: #eaf2ff; }
153
+ #aw-demo-card .rule { width: 120px; height: 2px; background: #2c4568; animation: awpulse 1.4s ease-in-out infinite; }
154
+ @keyframes awpulse { 0%, 100% { width: 120px; opacity: .55 } 50% { width: 168px; opacity: 1 } }
155
+ #aw-demo-steps { position: fixed; left: 50%; top: 34px; transform: translateX(-50%);
156
+ display: none; gap: 10px; z-index: 2147483000; pointer-events: none; }
157
+ #aw-demo-steps span { font: 600 13px/1 'Segoe UI', sans-serif; letter-spacing: 1px;
158
+ padding: 8px 14px; border-radius: 8px; color: #8fa0b5;
159
+ background: rgba(7,11,19,.8); border: 1px solid rgba(45,69,104,.6); transition: all .3s ease; }
160
+ #aw-demo-steps span.on { color: #06251a; background: #35e0a0; border-color: #35e0a0; }
161
+ #aw-demo-beat { position: fixed; width: 2px; height: 2px; bottom: 0; left: 0;
162
+ opacity: 0; animation: awbeat .5s steps(1) infinite; }
163
+ @keyframes awbeat { 0% { opacity: 0 } 50% { opacity: .02 } 100% { opacity: 0 } }
164
+ `
165
+ document.head.append(css)
166
+ for (const id of ['aw-demo-cap', 'aw-demo-veil', 'aw-demo-card', 'aw-demo-steps', 'aw-demo-beat']) {
167
+ const el = document.createElement('div')
168
+ el.id = id
169
+ document.body.append(el)
170
+ }
171
+ window.__demoRebuild = () => {
172
+ for (const id of ['aw-demo-cap', 'aw-demo-veil', 'aw-demo-card', 'aw-demo-steps', 'aw-demo-beat']) {
173
+ let el = document.getElementById(id)
174
+ if (!el || !el.isConnected) {
175
+ el?.remove()
176
+ el = document.createElement('div')
177
+ el.id = id
178
+ document.body.append(el)
179
+ }
180
+ }
181
+ }
182
+ window.__demoCap = (main, sub) => {
183
+ window.__demoRebuild()
184
+ const c = document.getElementById('aw-demo-cap')
185
+ if (!main) {
186
+ c.style.opacity = 0
187
+ return
188
+ }
189
+ c.innerHTML = `<span class="tag">AGENTWORKSHOP</span>${main}${sub ? `<span class="sub">${sub}</span>` : ''}`
190
+ c.style.opacity = 1
191
+ }
192
+ window.__demoVeil = async (on) => {
193
+ window.__demoRebuild()
194
+ document.getElementById('aw-demo-veil').style.opacity = on ? 1 : 0
195
+ await new Promise(r => setTimeout(r, 430))
196
+ }
197
+ window.__demoCard = (no) => {
198
+ window.__demoRebuild()
199
+ const c = document.getElementById('aw-demo-card')
200
+ if (!no) {
201
+ c.style.display = 'none'
202
+ return
203
+ }
204
+ const [noTxt, ...rest] = String(no).split('|')
205
+ c.innerHTML = `<span class="no">${noTxt}</span><span class="tt">${rest.join('|')}</span><span class="rule"></span>`
206
+ c.style.display = 'flex'
207
+ }
208
+ window.__demoSteps = (names, active) => {
209
+ window.__demoRebuild()
210
+ const s = document.getElementById('aw-demo-steps')
211
+ if (!names) {
212
+ s.style.display = 'none'
213
+ return
214
+ }
215
+ s.style.display = 'flex'
216
+ s.innerHTML = names.map((n, i) => `<span class="${i <= active ? 'on' : ''}">${n}</span>`).join('')
217
+ }
218
+ window.__demoScroll = async (toY, ms = 1000) => {
219
+ const from = window.scrollY
220
+ const t0 = performance.now()
221
+ await new Promise((done) => {
222
+ const step = (t) => {
223
+ const k = Math.min(1, (t - t0) / ms)
224
+ const e = k < 0.5 ? 2 * k * k : 1 - (-2 * k + 2) ** 2 / 2
225
+ window.scrollTo(0, from + (toY - from) * e)
226
+ if (k < 1) requestAnimationFrame(step)
227
+ else done()
228
+ }
229
+ requestAnimationFrame(step)
230
+ })
231
+ }
232
+ }
233
+
234
+ /**
235
+ * 场景运行器(页面内自跑;录制期间 Node 零 evaluate)。返回实际耗时(秒)。
236
+ */
237
+ const SCENE_RUNNER = async ({ clips, chapter, isTitle, actions, durs }) => {
238
+ const t0 = Date.now()
239
+ const sleep = ms => new Promise(r => setTimeout(r, ms))
240
+ const cap = (m, s2) => window.__demoCap(m, s2)
241
+ const qa = sel => [...document.querySelectorAll(sel)]
242
+ const setVal = (inp, v) => {
243
+ const set = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set
244
+ set.call(inp, v)
245
+ inp.dispatchEvent(new Event('input', { bubbles: true }))
246
+ inp.dispatchEvent(new Event('change', { bubbles: true }))
247
+ }
248
+ await window.__demoVeil(false)
249
+ if (chapter) {
250
+ window.__demoCard(chapter)
251
+ await sleep(1700)
252
+ window.__demoCard(null)
253
+ await sleep(350)
254
+ }
255
+ if (isTitle) {
256
+ window.__demoCard('★|AgentWorkShop')
257
+ }
258
+ for (let k = 0; k < clips.length; k++) {
259
+ cap(clips[k].cap, clips[k].sub)
260
+ const act = actions[k]
261
+ if (act === 'scrollcard') {
262
+ await window.__demoScroll(document.body.scrollHeight, 1400)
263
+ await sleep(800)
264
+ }
265
+ if (act === 'scroll430') {
266
+ await window.__demoScroll(430, 1100)
267
+ await sleep(900)
268
+ }
269
+ if (act === 'scroll320') {
270
+ await window.__demoScroll(320, 1200)
271
+ await sleep(1100)
272
+ }
273
+ if (act === 'pause3400') await sleep(3400)
274
+ if (act === 'write150') {
275
+ const inp = qa('input[type=number]').find(i => /^\d+~\d+$/.test((i.placeholder || '').replace(/\s/g, '')))
276
+ if (inp) {
277
+ inp.closest('tr, [class*="row"]')?.scrollIntoView({ block: 'center', behavior: 'smooth' })
278
+ await sleep(700)
279
+ setVal(inp, '150')
280
+ await sleep(250)
281
+ qa('button').find(b => b.textContent.trim() === '下发' || b.textContent.trim() === 'Dispatch')?.click()
282
+ }
283
+ await sleep(5200)
284
+ qa('button').find(b => ['读取', 'Read'].includes(b.textContent.trim()))?.click()
285
+ await sleep(3200)
286
+ }
287
+ if (act === 'history') {
288
+ await window.__demoScroll(document.body.scrollHeight, 1400)
289
+ await sleep(1500)
290
+ }
291
+ if (act === 'probe') {
292
+ const form = document.querySelector('.aw-serial-form')
293
+ if (form) {
294
+ const inputs = [...form.querySelectorAll('input')]
295
+ const nums = inputs.filter(i => i.type === 'number')
296
+ setVal(inputs[0], 'COM1')
297
+ if (nums[0]) setVal(nums[0], '9600')
298
+ if (nums[1]) setVal(nums[1], '1')
299
+ if (nums[2]) setVal(nums[2], '40001')
300
+ }
301
+ await sleep(400)
302
+ qa('.aw-serial-btn').find(b => (b.textContent || '').includes('测试连接') || (b.textContent || '').toLowerCase().includes('test'))?.click()
303
+ await sleep(4200)
304
+ }
305
+ if (act === 'sendtask') {
306
+ const any = qa('textarea')[0]
307
+ if (any) {
308
+ const st = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set
309
+ st.call(any, 'Demo run: optimize the melt temperature setpoint')
310
+ any.dispatchEvent(new Event('input', { bubbles: true }))
311
+ any.focus()
312
+ }
313
+ await sleep(700)
314
+ qa('button').find(b => /发送|Send/.test(b.title ?? ''))?.click()
315
+ await sleep(8500)
316
+ }
317
+ if (act === 'stages') {
318
+ const names = ['ANALYZE', 'PROPOSE', 'APPROVE', 'WRITE', 'VERIFY']
319
+ window.__demoSteps(names, -1)
320
+ for (let i = 0; i < names.length; i++) {
321
+ window.__demoSteps(names, i)
322
+ await sleep(1550)
323
+ }
324
+ await sleep(400)
325
+ window.__demoSteps(null)
326
+ }
327
+ await sleep(Math.max(1200, ((durs[k] ?? 6) + 0.7) * 1000))
328
+ }
329
+ cap(null)
330
+ await window.__demoVeil(true)
331
+ await sleep(700)
332
+ return (Date.now() - t0) / 1000
333
+ }
334
+
335
+ // ════ 阶段 2:录制(场景级重试) ══════════════════════════════════════════════
336
+ async function recordPhase() {
337
+ const narrDir = path.join(WORK, 'narr')
338
+ const durations = JSON.parse(fs.readFileSync(path.join(narrDir, 'durations.json'), 'utf8'))
339
+ fs.rmSync(path.join(WORK, 'frames'), { recursive: true, force: true })
340
+ fs.mkdirSync(path.join(WORK, 'frames'), { recursive: true })
341
+ const browser = await puppeteer.launch({
342
+ executablePath: CHROME,
343
+ headless: false,
344
+ defaultViewport: { width: 1600, height: 900, deviceScaleFactor: 1 },
345
+ args: ['--no-first-run', '--no-default-browser-check', '--window-size=1620,960', '--use-gl=angle'],
346
+ protocolTimeout: 600000,
347
+ })
348
+ const page = await browser.newPage()
349
+ await page.evaluateOnNewDocument(() => {
350
+ try {
351
+ localStorage.setItem('aw.locale', 'en')
352
+ }
353
+ catch { /* about:blank */ }
354
+ })
355
+ await page.goto(BASE + '/', { waitUntil: 'domcontentloaded', timeout: 60000 })
356
+ await sleep(1500)
357
+ const token = await page.evaluate(async ({ email, password }) => {
358
+ const res = await fetch('/api/users/login', {
359
+ method: 'POST', headers: { 'content-type': 'application/json' },
360
+ body: JSON.stringify({ email, password }),
361
+ })
362
+ const body = await res.json()
363
+ if (body?.code !== 0) return null
364
+ document.cookie = `token=${body.data.token}; path=/; max-age=86400`
365
+ return body.data.token
366
+ }, { email: EMAIL, password: PASSWORD })
367
+ if (!token) throw new Error('登录失败')
368
+
369
+ const sceneFiles = []
370
+ for (const scene of PLAN) {
371
+ let recorded = null
372
+ for (let attempt = 0; attempt < 2 && !recorded; attempt++) {
373
+ const durs = scene.clips.map((_, k) => durations[`${scene.id}_${k}`] ?? 6)
374
+ const narrTotal = durs.reduce((a, b) => a + b, 0) + 0.7 * scene.clips.length
375
+ console.log(`● 场景 ${scene.id}${attempt ? '(重试)' : ''}(解说 ${narrTotal.toFixed(1)}s)`)
376
+
377
+ let navTo = scene.url.startsWith('/') ? BASE + scene.url : null
378
+ if (scene.url === 'workshop') {
379
+ const wsId = await page.evaluate(async (t) => {
380
+ const r = await fetch('/api/workshop/workspaces', { headers: { authorization: `Bearer ${t}` } }).then(x => x.json())
381
+ return r?.data?.[0]?.id ?? null
382
+ }, token)
383
+ navTo = wsId ? `${BASE}/workshop/w/${wsId}` : `${BASE}/workshop`
384
+ }
385
+ if (scene.url === 'pvnode') {
386
+ const nid = await page.evaluate(async (t) => {
387
+ const r = await fetch('/api/workshop/daq', { headers: { authorization: `Bearer ${t}` } }).then(x => x.json())
388
+ const nodes = r.data?.nodes ?? []
389
+ return (nodes.find(n => n.name.includes('Temp PV')) ?? nodes[0])?.id ?? null
390
+ }, token)
391
+ navTo = nid ? `${BASE}/daq/${nid}` : `${BASE}/daq`
392
+ }
393
+ if (scene.url === 'card') {
394
+ await page.goto('about:blank').catch(() => {})
395
+ }
396
+ else {
397
+ await page.goto(navTo, { waitUntil: 'domcontentloaded', timeout: 60000 }).catch(() => {})
398
+ }
399
+ await sleep(800)
400
+ await page.evaluate(OVERLAY_FN)
401
+ await sleep(2200)
402
+
403
+ const actions = {
404
+ telemetry: { 1: 'scroll430' },
405
+ control: { 1: 'write150', 2: 'history' },
406
+ plugins: { 1: 'probe' },
407
+ agents: { 1: 'sendtask' },
408
+ loop: { 1: 'stages' },
409
+ twin: { 0: 'pause3400' },
410
+ }
411
+ const payload = {
412
+ clips: scene.clips.map(c => ({ cap: c.cap, sub: c.sub })),
413
+ chapter: scene.chapter,
414
+ isTitle: scene.id === 'title',
415
+ actions: actions[scene.id] ?? {},
416
+ durs,
417
+ }
418
+ const attemptSuffix = attempt ? `-r${attempt}` : ''
419
+ const sceneDir = path.join(WORK, 'frames', `${scene.id}${attemptSuffix}`)
420
+ fs.mkdirSync(sceneDir, { recursive: true })
421
+ let frameNo = 0
422
+ let pending = 0
423
+ const stamps = []
424
+ const client = await page.createCDPSession()
425
+ client.on('Page.screencastFrame', async (ev) => {
426
+ const at = ev.metadata.timestamp ?? Date.now() / 1000
427
+ if (pending < 24) {
428
+ pending++
429
+ const f = path.join(sceneDir, `f${String(frameNo++).padStart(5, '0')}.jpg`)
430
+ stamps.push({ file: f, at })
431
+ fs.promises.writeFile(f, Buffer.from(ev.data, 'base64')).catch(() => {}).finally(() => pending--)
432
+ }
433
+ await client.send('Page.screencastFrameAck', { sessionId: ev.sessionId }).catch(() => {})
434
+ })
435
+
436
+ // 场景脚本下推(不等待;录制期间零 evaluate)。超时/异常 → 由 attempt 重试兜底。
437
+ const runnerPromise = page.evaluate(SCENE_RUNNER, payload).catch(err => console.warn(' runner:', String(err).slice(0, 70)))
438
+ await sleep(600)
439
+ await client.send('Page.startScreencast', { format: 'jpeg', quality: 74, maxWidth: 1600, maxHeight: 900, everyNthFrame: 3 })
440
+
441
+ if (scene.id === 'twin') {
442
+ await sleep(4200)
443
+ const orbit = async (dx, steps = 24) => {
444
+ const box = await page.evaluate(() => {
445
+ const c = document.querySelector('canvas')
446
+ const r = c?.getBoundingClientRect()
447
+ return r ? { x: r.x + r.width / 2, y: r.y + r.height / 2 } : null
448
+ })
449
+ if (!box) return
450
+ await page.mouse.move(box.x, box.y)
451
+ await page.mouse.down()
452
+ for (let i = 0; i < steps; i++) {
453
+ const k = (i + 1) / steps
454
+ const e = 1 - (1 - k) ** 2
455
+ await page.mouse.move(box.x + dx * e, box.y + Math.sin(k * Math.PI) * 30)
456
+ await sleep(46)
457
+ }
458
+ await page.mouse.up()
459
+ }
460
+ await orbit(300)
461
+ await sleep(600)
462
+ await orbit(-240)
463
+ await sleep(500)
464
+ }
465
+
466
+ await runnerPromise.catch(() => {})
467
+ await sleep(600)
468
+ await client.send('Page.stopScreencast').catch(() => {})
469
+ await sleep(300)
470
+ console.log(` 帧 ${stamps.length}`)
471
+
472
+ if (stamps.length >= 8) {
473
+ const lines = []
474
+ for (let i = 0; i < stamps.length; i++) {
475
+ const next = stamps[i + 1]?.at
476
+ const d = next ? Math.max(0.02, Math.min(3, next - stamps[i].at)) : 0.12
477
+ lines.push(`file '${stamps[i].file.replace(/\\/g, '/')}'`)
478
+ lines.push(`duration ${d.toFixed(3)}`)
479
+ }
480
+ lines.push(`file '${stamps[stamps.length - 1].file.replace(/\\/g, '/')}'`)
481
+ const durFile = path.join(sceneDir, 'durations.txt')
482
+ fs.writeFileSync(durFile, lines.join('\n'))
483
+ const out = path.join(WORK, 'frames', `${scene.id}${attemptSuffix}.mp4`)
484
+ execSync(`ffmpeg -y -v error -f concat -safe 0 -i "${durFile}" -vf "fps=30,format=yuv420p" -c:v libx264 -preset medium -crf 24 "${out}"`)
485
+ recorded = { id: scene.id, video: out }
486
+ }
487
+ else {
488
+ console.warn(` ⚠ ${scene.id} 帧不足(attempt=${attempt})`)
489
+ // 渲染器可能被拖挂:整页 reload 复位后再试
490
+ await page.reload({ waitUntil: 'domcontentloaded', timeout: 60000 }).catch(() => {})
491
+ await sleep(2500)
492
+ }
493
+ await client.detach().catch(() => {})
494
+ }
495
+ if (recorded) sceneFiles.push(recorded)
496
+ else console.warn(` ✖ ${scene.id} 两次尝试均失败,跳过该场景`)
497
+ }
498
+
499
+ // ── 配音对齐 + 混流(clip 边缘 afade)+ 拼接 + 封面 ──
500
+ console.log('● 配音对齐与混流 …')
501
+ const finalOut = path.join(OUT_DIR, 'agentworkshop-demo.mp4')
502
+ const parts = []
503
+ for (const scene of PLAN) {
504
+ const sf = sceneFiles.find(x => x.id === scene.id)
505
+ if (!sf) continue
506
+ const vdur = probeDur(sf.video)
507
+ const inputs = []
508
+ const filters = []
509
+ const mixIns = []
510
+ let t = HEAD
511
+ scene.clips.forEach((c, k) => {
512
+ const d = durations[`${scene.id}_${k}`] ?? 0
513
+ const narr = path.join(narrDir, `${scene.id}_${k}.wav`)
514
+ if (fs.existsSync(narr)) {
515
+ inputs.push('-i', narr)
516
+ const ms = Math.round(t * 1000)
517
+ filters.push(`[${k}:a]adelay=${ms}|${ms},afade=t=in:d=0.025,afade=t=out:st=${Math.max(0, d - 0.06).toFixed(3)}:d=0.06[a${k}]`)
518
+ mixIns.push(`[a${k}]`)
519
+ }
520
+ t += d + 0.7
521
+ })
522
+ const sceneWav = path.join(WORK, 'frames', `${scene.id}.wav`)
523
+ if (mixIns.length) {
524
+ execSync(`ffmpeg -y -v error ${inputs.join(' ')} -filter_complex "${filters.join(';')};${mixIns.join('')}amix=inputs=${mixIns.length}:normalize=0,apad=whole_dur=${vdur.toFixed(3)}[out]" -map "[out]" -ar 44100 -ac 2 "${sceneWav}"`)
525
+ }
526
+ else {
527
+ execSync(`ffmpeg -y -v error -f lavfi -i anullsrc=r=44100:cl=stereo -t ${vdur.toFixed(3)} "${sceneWav}"`)
528
+ }
529
+ const av = path.join(WORK, 'frames', `${scene.id}.av.mp4`)
530
+ execSync(`ffmpeg -y -v error -i "${sf.video}" -i "${sceneWav}" -c:v copy -c:a aac -b:a 160k -shortest "${av}"`)
531
+ parts.push(av)
532
+ }
533
+ const listFile = path.join(WORK, 'frames', 'concat.txt')
534
+ fs.writeFileSync(listFile, parts.map(p2 => `file '${p2.replace(/\\/g, '/')}'`).join('\n'))
535
+ execSync(`ffmpeg -y -v error -f concat -safe 0 -i "${listFile}" -c copy -movflags +faststart "${finalOut}"`)
536
+ const dur = probeDur(finalOut)
537
+ const size = fs.statSync(finalOut).size
538
+ console.log(`✅ 完成:${finalOut.replace(process.cwd(), '.')}(${(size / 1e6).toFixed(1)} MB,${dur.toFixed(1)}s)`)
539
+
540
+ const posterAt = Math.min(dur - 2, dur * 0.86)
541
+ execSync(`ffmpeg -y -v error -ss ${posterAt.toFixed(1)} -i "${finalOut}" -frames:v 1 -q:v 3 "${path.join(OUT_DIR, 'poster.jpg')}"`)
542
+ await browser.close()
543
+ }
544
+
545
+ // ════ 入口 ══════════════════════════════════════════════════════════════════
546
+ const phase = process.argv[2] ?? 'record'
547
+ fs.mkdirSync(OUT_DIR, { recursive: true })
548
+ if (phase === 'tts') {
549
+ await ttsPhase()
550
+ }
551
+ else if (phase === 'record') {
552
+ await recordPhase()
553
+ }
554
+ else {
555
+ console.error('用法: node scripts/ui/record-demo.mjs [tts|record]')
556
+ process.exit(1)
557
+ }