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
@@ -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
+ }