agentworkshop 0.7.38 → 0.7.40

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 (392) hide show
  1. package/.AgentWorkShop/prompts/aml-mission-default.md +20 -20
  2. package/.AgentWorkShop/prompts/aml-playbook.md +49 -49
  3. package/.AgentWorkShop/prompts/host-tools.json +1293 -1238
  4. package/.AgentWorkShop/prompts/peer-reply-cross-channel.md +10 -10
  5. package/.output/.AgentWorkShop/prompts/aml-mission-default.md +20 -20
  6. package/.output/.AgentWorkShop/prompts/aml-playbook.md +49 -49
  7. package/.output/.AgentWorkShop/prompts/host-tools.json +1293 -1238
  8. package/.output/.AgentWorkShop/prompts/peer-reply-cross-channel.md +10 -10
  9. package/.output/nitro.json +1 -1
  10. package/.output/public/_nuxt/88GOowgO2.js +1 -0
  11. package/.output/public/_nuxt/{BNT8gYU92.js → BC9wjTJK2.js} +2 -2
  12. package/.output/public/_nuxt/BOt2SP4z.js +1 -0
  13. package/.output/public/_nuxt/BP-NyKVG.js +18 -0
  14. package/.output/public/_nuxt/{HBLJ-wei.js → BXxH0UQE.js} +1 -1
  15. package/.output/public/_nuxt/{zIGh7R49.js → BneN7fbu.js} +1 -1
  16. package/.output/public/_nuxt/BsROmY89.js +1 -0
  17. package/.output/public/_nuxt/{C_OLzD09.js → C4oW1HsE.js} +1 -1
  18. package/.output/public/_nuxt/CFxtLwjp.js +1 -0
  19. package/.output/public/_nuxt/{Cec0Ua3F.js → CS50LB_l.js} +1 -1
  20. package/.output/public/_nuxt/C_iYD-EB.js +1 -0
  21. package/.output/public/_nuxt/{DAe0h2MB.js → ClILjvWH.js} +1 -1
  22. package/.output/public/_nuxt/CssgYAAL2.js +1 -0
  23. package/.output/public/_nuxt/{CY9LbPCI.js → CzOCSGLe.js} +1 -1
  24. package/.output/public/_nuxt/D8qvkfyY.js +1 -0
  25. package/.output/public/_nuxt/DCn7QZ5N.js +2 -0
  26. package/.output/public/_nuxt/DGIuvyRN2.js +1 -0
  27. package/.output/public/_nuxt/{CojCTLKD.js → DGj-WEBg.js} +1 -1
  28. package/.output/public/_nuxt/{DDShH71m.js → DS8qj8EL.js} +1 -1
  29. package/.output/public/_nuxt/DTFCy6h-.js +1 -0
  30. package/.output/public/_nuxt/{DrYV5i68.js → DUjW5Yq5.js} +1 -1
  31. package/.output/public/_nuxt/DZshyNLa.js +1 -0
  32. package/.output/public/_nuxt/{45zuyAso.js → D_OTvQza.js} +1 -1
  33. package/.output/public/_nuxt/DcsCcxp4.js +1 -0
  34. package/.output/public/_nuxt/{DUrecWPx.js → Dihnimlk.js} +2 -2
  35. package/.output/public/_nuxt/Dqw1lpr-.js +1 -0
  36. package/.output/public/_nuxt/{BG8sCcwx.js → Dr9v6C0f.js} +9 -9
  37. package/.output/public/_nuxt/{8NMOXZOV.js → Du9ZJtnj.js} +1 -1
  38. package/.output/public/_nuxt/TownView.f-YOdXRs.css +1 -0
  39. package/.output/public/_nuxt/_id_.CM4bIgKY.css +1 -0
  40. package/.output/public/_nuxt/_id_.bNV69Dtf.css +1 -0
  41. package/.output/public/_nuxt/_wsId_.B4WiqkIS.css +1 -0
  42. package/.output/public/_nuxt/agents.ZD0rVdHE.css +1 -0
  43. package/.output/public/_nuxt/aml.BN8ZEW4h.css +1 -0
  44. package/.output/public/_nuxt/builds/latest.json +1 -1
  45. package/.output/public/_nuxt/builds/meta/f4707884-7cf4-4a31-80d2-e3d72b73745f.json +1 -0
  46. package/.output/public/_nuxt/channel-templates.BOtahzPi.css +1 -0
  47. package/.output/public/_nuxt/daq.B0D3dPAc.css +1 -0
  48. package/.output/public/_nuxt/dcw.8Y7FqCVN.css +1 -0
  49. package/.output/public/_nuxt/default.J32SgqFY.css +1 -0
  50. package/.output/public/_nuxt/entry.bdm0tv6M.css +1 -0
  51. package/.output/public/_nuxt/logs.BpKzmKsh.css +1 -0
  52. package/.output/public/_nuxt/monitor.D9pe7qN6.css +1 -0
  53. package/.output/public/_nuxt/pages.D7aSDlUI.css +1 -0
  54. package/.output/public/_nuxt/permissions.DwTVlFe6.css +1 -0
  55. package/.output/public/_nuxt/plugins.sb4nDGqr.css +1 -0
  56. package/.output/public/_nuxt/{Cbq-mryP.js → qr6R6Ha1.js} +1 -1
  57. package/.output/public/_nuxt/settings.BTgR-NiE.css +1 -0
  58. package/.output/public/_nuxt/teams.CxnxKVVs.css +1 -0
  59. package/.output/public/_nuxt/tokens.BFY7qv4f.css +1 -0
  60. package/.output/public/_nuxt/{town.DKIAhKnx.css → town.BBXZmeoP.css} +1 -1
  61. package/.output/public/_nuxt/users.DLgZ1D0h.css +1 -0
  62. package/.output/public/_nuxt/workshop.CR_QzeAN.css +1 -0
  63. package/.output/public/_nuxt/{BzHEilTt.js → xh3_vYcu.js} +1 -1
  64. package/.output/public/_nuxt/yF0aYMF1.js +4 -0
  65. package/.output/server/chunks/_/entity.mjs.map +1 -1
  66. package/.output/server/chunks/_/nitro.mjs +2244 -1464
  67. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  68. package/.output/server/chunks/build/{TownView-jVazYOjN.mjs → TownView-BuLAsmpR.mjs} +288 -206
  69. package/.output/server/chunks/build/TownView-BuLAsmpR.mjs.map +1 -0
  70. package/.output/server/chunks/build/{_id_-CfVosNg3.mjs → _id_-BU1wfOID.mjs} +138 -138
  71. package/.output/server/chunks/build/{_id_-CfVosNg3.mjs.map → _id_-BU1wfOID.mjs.map} +1 -1
  72. package/.output/server/chunks/build/{_id_-Hwr4rZpr.mjs → _id_-BYsEua57.mjs} +33 -32
  73. package/.output/server/chunks/build/_id_-BYsEua57.mjs.map +1 -0
  74. package/.output/server/chunks/build/{_wsId_-BVg3bB77.mjs → _wsId_-BxlDcJHg.mjs} +293 -259
  75. package/.output/server/chunks/build/{_wsId_-BVg3bB77.mjs.map → _wsId_-BxlDcJHg.mjs.map} +1 -1
  76. package/.output/server/chunks/build/{agents-Bvin73QY.mjs → agents-CLQqJF2y.mjs} +21 -27
  77. package/.output/server/chunks/build/agents-CLQqJF2y.mjs.map +1 -0
  78. package/.output/server/chunks/build/{aml-BCSJCdX7.mjs → aml-_7FdFL2p.mjs} +109 -109
  79. package/.output/server/chunks/build/{aml-BCSJCdX7.mjs.map → aml-_7FdFL2p.mjs.map} +1 -1
  80. package/.output/server/chunks/build/api-error-dul30BYQ.mjs.map +1 -1
  81. package/.output/server/chunks/build/{channel-templates-BTq8570n.mjs → channel-templates-p6SZNjlM.mjs} +19 -19
  82. package/.output/server/chunks/build/{channel-templates-BTq8570n.mjs.map → channel-templates-p6SZNjlM.mjs.map} +1 -1
  83. package/.output/server/chunks/build/{daq-C03Uu5UE.mjs → daq-cgyjKmJu.mjs} +188 -122
  84. package/.output/server/chunks/build/daq-cgyjKmJu.mjs.map +1 -0
  85. package/.output/server/chunks/build/{dcw-6vEYVeje.mjs → dcw-CoTxBlAZ.mjs} +45 -45
  86. package/.output/server/chunks/build/{dcw-6vEYVeje.mjs.map → dcw-CoTxBlAZ.mjs.map} +1 -1
  87. package/.output/server/chunks/build/{default-hseyOqBT.mjs → default-BE4r0FZN.mjs} +158 -79
  88. package/.output/server/chunks/build/{default-hseyOqBT.mjs.map → default-BE4r0FZN.mjs.map} +1 -1
  89. package/.output/server/chunks/build/{logs-B-xhuqln.mjs → logs-BSOeZwwI.mjs} +34 -34
  90. package/.output/server/chunks/build/{logs-B-xhuqln.mjs.map → logs-BSOeZwwI.mjs.map} +1 -1
  91. package/.output/server/chunks/build/{monitor-CyfDt4nR.mjs → monitor-C0okQaXz.mjs} +33 -33
  92. package/.output/server/chunks/build/{monitor-CyfDt4nR.mjs.map → monitor-C0okQaXz.mjs.map} +1 -1
  93. package/.output/server/chunks/build/{pages-BO7yZsXA.mjs → pages-DFxjn9Xa.mjs} +33 -17
  94. package/.output/server/chunks/build/pages-DFxjn9Xa.mjs.map +1 -0
  95. package/.output/server/chunks/build/{permissions-B52oOmaO.mjs → permissions-68SsNjex.mjs} +12 -12
  96. package/.output/server/chunks/build/{permissions-B52oOmaO.mjs.map → permissions-68SsNjex.mjs.map} +1 -1
  97. package/.output/server/chunks/build/{plugins-CUWmMdyt.mjs → plugins-lGlUr1lj.mjs} +17 -17
  98. package/.output/server/chunks/build/{plugins-CUWmMdyt.mjs.map → plugins-lGlUr1lj.mjs.map} +1 -1
  99. package/.output/server/chunks/build/{settings-DoQ2Oq3P.mjs → settings-Ddd1qx2Z.mjs} +50 -47
  100. package/.output/server/chunks/build/settings-Ddd1qx2Z.mjs.map +1 -0
  101. package/.output/server/chunks/build/{teams-2kz3CusY.mjs → teams-MEDLZdMn.mjs} +38 -34
  102. package/.output/server/chunks/build/teams-MEDLZdMn.mjs.map +1 -0
  103. package/.output/server/chunks/build/{tokens-BbWLqtVz.mjs → tokens-C7fTM5C2.mjs} +14 -14
  104. package/.output/server/chunks/build/{tokens-BbWLqtVz.mjs.map → tokens-C7fTM5C2.mjs.map} +1 -1
  105. package/.output/server/chunks/build/{town-BOl6hs9B.mjs → town-qMPql9Se.mjs} +36 -10
  106. package/.output/server/chunks/build/town-qMPql9Se.mjs.map +1 -0
  107. package/.output/server/chunks/build/useDaqStream-CIBaiGAl.mjs +1 -1
  108. package/.output/server/chunks/build/useDcwStream-CBbiYnWe.mjs +1 -1
  109. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs +49 -0
  110. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs.map +1 -0
  111. package/.output/server/chunks/build/{users-fohSmF-J.mjs → users-Cfd5-l2-.mjs} +6 -6
  112. package/.output/server/chunks/build/{users-fohSmF-J.mjs.map → users-Cfd5-l2-.mjs.map} +1 -1
  113. package/.output/server/chunks/build/{workshop-DX5-ldc4.mjs → workshop-BL5bhfs0.mjs} +15 -15
  114. package/.output/server/chunks/build/{workshop-DX5-ldc4.mjs.map → workshop-BL5bhfs0.mjs.map} +1 -1
  115. package/.output/server/chunks/build/{workspaces-BuydxM-3.mjs → workspaces-Bgz5Ekwp.mjs} +18 -3
  116. package/.output/server/chunks/build/workspaces-Bgz5Ekwp.mjs.map +1 -0
  117. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs.map +1 -1
  118. package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
  119. package/.output/server/chunks/routes/api/system/index.post.mjs.map +1 -1
  120. package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
  121. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +6 -2
  122. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
  123. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +2 -1
  124. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs.map +1 -1
  125. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  126. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +3 -3
  127. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
  128. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
  129. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
  130. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +3 -2
  131. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
  132. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -1
  133. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
  134. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +8 -6
  135. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
  136. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +5 -5
  137. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
  138. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +14 -4
  139. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
  140. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +4 -4
  141. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
  142. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +4 -3
  143. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
  144. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +31 -0
  145. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs.map +1 -0
  146. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +28 -0
  147. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs.map +1 -0
  148. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
  149. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +32 -0
  150. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs.map +1 -0
  151. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +34 -0
  152. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs.map +1 -0
  153. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +33 -0
  154. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs.map +1 -0
  155. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +34 -0
  156. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs.map +1 -0
  157. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  158. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  159. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  160. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  161. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  162. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  163. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  164. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +2 -0
  165. package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
  166. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +3 -1
  167. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  168. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  169. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  170. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  171. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  172. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  173. package/.output/server/chunks/routes/renderer.mjs +3 -3
  174. package/.output/server/chunks/virtual/entry.mjs +53 -25
  175. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  176. package/.output/server/package.json +1 -1
  177. package/README-zh.md +204 -40
  178. package/README.md +739 -591
  179. package/app/app.vue +9 -3
  180. package/app/assets/css/main.css +517 -7
  181. package/app/components/AppHeader.vue +98 -24
  182. package/app/components/AppSidebar.vue +118 -11
  183. package/app/components/AwChart.vue +2 -1
  184. package/app/components/workshop/AgentInspectorDrawer.vue +6 -6
  185. package/app/components/workshop/AgentLanesView.vue +52 -1
  186. package/app/components/workshop/AssetLibrary.vue +4 -2
  187. package/app/components/workshop/ChannelSessionList.vue +4 -2
  188. package/app/components/workshop/Composer.vue +96 -0
  189. package/app/components/workshop/DaqNodeRow.vue +19 -0
  190. package/app/components/workshop/DaqTemplateIcon.vue +33 -0
  191. package/app/components/workshop/DeviceTwinPanel.vue +37 -35
  192. package/app/components/workshop/EventBlock.vue +3 -3
  193. package/app/components/workshop/InspectorPanel.vue +47 -11
  194. package/app/components/workshop/LiveAgentBar.vue +34 -0
  195. package/app/components/workshop/TaskBoardView.vue +83 -33
  196. package/app/components/workshop/TranscriptTimeline.vue +56 -0
  197. package/app/components/workshop/blocks/ClusterError.vue +1 -1
  198. package/app/components/workshop/blocks/ClusterRoute.vue +3 -1
  199. package/app/components/workshop/blocks/ClusterStatus.vue +2 -2
  200. package/app/components/workshop/blocks/ClusterStream.vue +8 -2
  201. package/app/components/workshop/town/ModelPreview3D.vue +1 -1
  202. package/app/components/workshop/town/TownView.vue +507 -82
  203. package/app/composables/useResponsive.ts +88 -0
  204. package/app/composables/useRouteMeta.ts +3 -0
  205. package/app/composables/workshop/useDcwStream.ts +1 -1
  206. package/app/composables/workshop/useVisibleInterval.ts +2 -2
  207. package/app/composables/workshop/useWorkshopApi.ts +1 -1
  208. package/app/layouts/default.vue +46 -2
  209. package/app/pages/aml/index.vue +712 -616
  210. package/app/pages/daq/[id].vue +3 -2
  211. package/app/pages/daq/index.vue +209 -9
  212. package/app/pages/dcw/[id].vue +109 -28
  213. package/app/pages/dcw/index.vue +83 -23
  214. package/app/pages/index.vue +35 -1
  215. package/app/pages/logs/index.vue +147 -13
  216. package/app/pages/monitor.vue +56 -12
  217. package/app/pages/permissions/index.vue +34 -0
  218. package/app/pages/plugins/index.vue +35 -4
  219. package/app/pages/settings.vue +90 -21
  220. package/app/pages/tokens.vue +23 -0
  221. package/app/pages/town.vue +50 -5
  222. package/app/pages/users.vue +23 -0
  223. package/app/pages/workshop/agents.vue +92 -2
  224. package/app/pages/workshop/channel-templates.vue +53 -0
  225. package/app/pages/workshop/index.vue +14 -0
  226. package/app/pages/workshop/teams.vue +66 -6
  227. package/app/pages/workshop/w/[wsId].vue +202 -14
  228. package/app/plugins/aw-plugins.client.ts +13 -8
  229. package/app/stores/app.ts +33 -1
  230. package/app/stores/workshop/user.ts +1 -1
  231. package/app/stores/workshop/workspaces.ts +18 -2
  232. package/app/utils/api-error.ts +1 -1
  233. package/cli/commands/build.mjs +8 -1
  234. package/docker-compose.yml +6 -0
  235. package/docs/full-test-plan.md +4 -0
  236. package/docs/plugins.en.md +1 -0
  237. package/docs/plugins.md +1 -0
  238. package/i18n/locales/en.ts +3 -0
  239. package/i18n/locales/zh-CN.ts +3 -0
  240. package/nuxt.config.ts +31 -0
  241. package/package.json +9 -1
  242. package/scripts/_audit/detached-start.mjs +103 -0
  243. package/scripts/_audit/guard-upstream-liveness.mjs +104 -0
  244. package/scripts/_dbg-param-map-e2e.ts +242 -0
  245. package/scripts/_dbg-param-map-rest-smoke.mjs +73 -0
  246. package/scripts/_dbg-param-real-scenario.mjs +153 -0
  247. package/scripts/_dbg-perms-e2e.mjs +10 -3
  248. package/scripts/_dbg-protocol-matrix.mjs +453 -441
  249. package/scripts/_dbg-render-regression.mjs +151 -130
  250. package/scripts/_dbg-town-agents-probe.mjs +60 -0
  251. package/scripts/_dbg-visual-acceptance.mjs +63 -0
  252. package/scripts/api-live-e2e.mjs +40 -8
  253. package/scripts/capture-walkthrough.mjs +232 -0
  254. package/scripts/e2e-agent-team.mjs +5 -3
  255. package/scripts/render-walkthrough-figure.mjs +46 -0
  256. package/scripts/seed-walkthrough-fixture.mjs +143 -0
  257. package/scripts/test-plugin-hardening.mjs +8 -0
  258. package/scripts/three-system-e2e.mjs +6 -6
  259. package/scripts/ui/admin-shots.mjs +46 -0
  260. package/scripts/ui/audit-layout.mjs +301 -0
  261. package/scripts/ui/bump-microfont.mjs +39 -0
  262. package/scripts/ui/lib.mjs +198 -0
  263. package/scripts/ui/linkcheck2.mjs +37 -0
  264. package/scripts/ui/live-render-check.mjs +72 -0
  265. package/scripts/ui/md-lint.mjs +80 -0
  266. package/scripts/ui/perf-audit.mjs +132 -0
  267. package/scripts/ui/readme-assets.mjs +30 -0
  268. package/scripts/ui/readme-shots.mjs +42 -0
  269. package/scripts/ui/record.mjs +225 -0
  270. package/scripts/ui/seed-admin.mjs +68 -0
  271. package/scripts/ui/seed-demo.mjs +83 -0
  272. package/scripts/ui/shot-hero.mjs +25 -0
  273. package/scripts/ui/shots.mjs +75 -0
  274. package/scripts/ui/sim-ui-shot.mjs +16 -0
  275. package/scripts/ui/verify-nav.mjs +51 -0
  276. package/scripts/ui/verify-responsive.mjs +285 -0
  277. package/server/api/system/config-groups/[id].patch.ts +1 -1
  278. package/server/api/system/config-groups/index.post.ts +1 -1
  279. package/server/api/system/settings/events.get.ts +1 -1
  280. package/server/api/system/settings/index.patch.ts +1 -1
  281. package/server/api/workshop/agent-tools/invoke.post.ts +16 -2
  282. package/server/api/workshop/aml/datasets/[id].get.ts +8 -1
  283. package/server/api/workshop/daq/infra/reconnect.post.ts +1 -1
  284. package/server/api/workshop/daq/templates/[key].delete.ts +1 -0
  285. package/server/api/workshop/daq/templates/[key].patch.ts +1 -0
  286. package/server/api/workshop/daq/templates/index.post.ts +1 -0
  287. package/server/api/workshop/dcw/[id]/write.post.ts +10 -2
  288. package/server/api/workshop/dcw/[id].delete.ts +5 -2
  289. package/server/api/workshop/dcw/index.get.ts +2 -0
  290. package/server/api/workshop/dcw/lines/[id].patch.ts +1 -1
  291. package/server/api/workshop/dcw/params/[id]/read.post.ts +17 -0
  292. package/server/api/workshop/dcw/params/[id]/write.post.ts +21 -0
  293. package/server/api/workshop/dcw/params/[id].delete.ts +19 -0
  294. package/server/api/workshop/dcw/params/[id].patch.ts +23 -0
  295. package/server/api/workshop/dcw/params/index.get.ts +27 -0
  296. package/server/api/workshop/dcw/params/index.post.ts +25 -0
  297. package/server/api/workshop/permissions/index.get.ts +3 -1
  298. package/server/plugins/aw-plugins.ts +14 -3
  299. package/server/plugins/dev-stability-guard.ts +3 -1
  300. package/server/plugins/system-config.ts +6 -1
  301. package/server/plugins-builtin/rag-bridge/index.mjs +9 -2
  302. package/server/services/system-config.ts +28 -9
  303. package/server/services/workshop/agents/adapters/one-shot-cli-agent.ts +2 -1
  304. package/server/services/workshop/agents/agent-interface.ts +8 -6
  305. package/server/services/workshop/agents/base-agent.ts +18 -4
  306. package/server/services/workshop/agents/claude-agent.ts +7 -3
  307. package/server/services/workshop/agents/codex-agent.ts +3 -3
  308. package/server/services/workshop/agents/dsh-agent.ts +3 -3
  309. package/server/services/workshop/agents/goose-agent.ts +0 -1
  310. package/server/services/workshop/agents/harness-terminal.ts +14 -1
  311. package/server/services/workshop/agents/hermes-agent.ts +4 -2
  312. package/server/services/workshop/agents/host-tool-bridge.ts +5 -1
  313. package/server/services/workshop/agents/industrial-context.ts +4 -1
  314. package/server/services/workshop/agents/industrial-tools.ts +164 -6
  315. package/server/services/workshop/agents/omp-agent.ts +15 -9
  316. package/server/services/workshop/agents/opencode-agent.ts +47 -21
  317. package/server/services/workshop/agents/qwen-agent.ts +10 -5
  318. package/server/services/workshop/aml/entity.ts +3 -1
  319. package/server/services/workshop/aml/python-runtime.ts +3 -2
  320. package/server/services/workshop/daq/bus/mqtt.adapter.ts +8 -4
  321. package/server/services/workshop/daq/daq-controller.ts +18 -3
  322. package/server/services/workshop/daq/daq-runtime.ts +5 -3
  323. package/server/services/workshop/daq/drivers.ts +63 -8
  324. package/server/services/workshop/daq/host-ports.ts +3 -2
  325. package/server/services/workshop/daq/storage/timescale.adapter.ts +3 -1
  326. package/server/services/workshop/db/channel.repo.ts +4 -0
  327. package/server/services/workshop/db/ops.repo.ts +5 -2
  328. package/server/services/workshop/db/retention.ts +8 -3
  329. package/server/services/workshop/dcw/dcw-controller.ts +143 -16
  330. package/server/services/workshop/dcw/dcw-product.repo.ts +38 -1
  331. package/server/services/workshop/dcw/dcw-runtime.ts +3 -2
  332. package/server/services/workshop/dcw/drivers.ts +5 -2
  333. package/server/services/workshop/dcw/param-conversion.ts +78 -0
  334. package/server/services/workshop/dcw/param-limits.ts +142 -0
  335. package/server/services/workshop/dcw/param-map.repo.ts +305 -0
  336. package/server/services/workshop/dcw/recipe-rollback-manager.ts +13 -7
  337. package/server/services/workshop/runtime/agent-runtime.ts +4 -0
  338. package/server/services/workshop/runtime/manager.ts +9 -2
  339. package/server/services/workshop/settings.ts +4 -2
  340. package/server/types/pg.d.ts +49 -0
  341. package/server/utils/stability-severity.ts +13 -2
  342. package/shared/config/groups.mjs +22 -1
  343. package/shared/config/home.d.mts +28 -0
  344. package/shared/dcw-protocol.ts +136 -0
  345. package/uno.config.ts +12 -1
  346. package/.output/public/_nuxt/BFkgkW8u.js +0 -4
  347. package/.output/public/_nuxt/C5gUkRwn.js +0 -1
  348. package/.output/public/_nuxt/CM12FuB42.js +0 -1
  349. package/.output/public/_nuxt/CZiw7sEV.js +0 -1
  350. package/.output/public/_nuxt/Cc_9VzD42.js +0 -1
  351. package/.output/public/_nuxt/CdPzkOMV.js +0 -1
  352. package/.output/public/_nuxt/D1YDxZpZ.js +0 -1
  353. package/.output/public/_nuxt/D20Yamr4.js +0 -1
  354. package/.output/public/_nuxt/DVsjtsvZ2.js +0 -1
  355. package/.output/public/_nuxt/DmqknNvV.js +0 -18
  356. package/.output/public/_nuxt/DnUuIR83.js +0 -1
  357. package/.output/public/_nuxt/S_fVQwJK.js +0 -1
  358. package/.output/public/_nuxt/TownView.0oLiQgTC.css +0 -1
  359. package/.output/public/_nuxt/_id_.D-SYuyZb.css +0 -1
  360. package/.output/public/_nuxt/_id_.hma_BU6T.css +0 -1
  361. package/.output/public/_nuxt/_wsId_.B12v3PhY.css +0 -1
  362. package/.output/public/_nuxt/agents.BV70ioCv.css +0 -1
  363. package/.output/public/_nuxt/ahgEJu2R.js +0 -1
  364. package/.output/public/_nuxt/aml.COEKNNqK.css +0 -1
  365. package/.output/public/_nuxt/builds/meta/44b66249-54d0-4c8a-9057-9755a32329e2.json +0 -1
  366. package/.output/public/_nuxt/channel-templates.C-M5nKcC.css +0 -1
  367. package/.output/public/_nuxt/daq.B3265ZDn.css +0 -1
  368. package/.output/public/_nuxt/dcw.DLYZqEhT.css +0 -1
  369. package/.output/public/_nuxt/default.DE_vT238.css +0 -1
  370. package/.output/public/_nuxt/entry.BB-Eeh-J.css +0 -1
  371. package/.output/public/_nuxt/logs.CqFyMrJw.css +0 -1
  372. package/.output/public/_nuxt/monitor.B--1dPzs.css +0 -1
  373. package/.output/public/_nuxt/pages.ooEzrMm9.css +0 -1
  374. package/.output/public/_nuxt/permissions.B1pjGChZ.css +0 -1
  375. package/.output/public/_nuxt/plugins.5e5chZ67.css +0 -1
  376. package/.output/public/_nuxt/pz2JDAM7.js +0 -2
  377. package/.output/public/_nuxt/settings.Dm3M0RLy.css +0 -1
  378. package/.output/public/_nuxt/teams.BC75EGnR.css +0 -1
  379. package/.output/public/_nuxt/tokens.xRb1fSPU.css +0 -1
  380. package/.output/public/_nuxt/users.CXnP2E08.css +0 -1
  381. package/.output/public/_nuxt/workshop.Jk5HxWPE.css +0 -1
  382. package/.output/server/chunks/build/TownView-jVazYOjN.mjs.map +0 -1
  383. package/.output/server/chunks/build/_id_-Hwr4rZpr.mjs.map +0 -1
  384. package/.output/server/chunks/build/agents-Bvin73QY.mjs.map +0 -1
  385. package/.output/server/chunks/build/daq-C03Uu5UE.mjs.map +0 -1
  386. package/.output/server/chunks/build/pages-BO7yZsXA.mjs.map +0 -1
  387. package/.output/server/chunks/build/settings-DoQ2Oq3P.mjs.map +0 -1
  388. package/.output/server/chunks/build/teams-2kz3CusY.mjs.map +0 -1
  389. package/.output/server/chunks/build/town-BOl6hs9B.mjs.map +0 -1
  390. package/.output/server/chunks/build/workspaces-BuydxM-3.mjs.map +0 -1
  391. /package/.output/public/_nuxt/{36oeS8_R2.js → 36oeS8_R.js} +0 -0
  392. /package/.output/public/_nuxt/{CYWVXZTS.js → CYWVXZTS2.js} +0 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Canonical walkthrough-figure capture. High-DPI (3x), element/row-accurate crops
3
+ * of the four operational stages on a live AgentWorkShop instance.
4
+ *
5
+ * The shared production instance carries Chinese-named test data, so the four
6
+ * screenshots are taken against the small ENGLISH fixture created by
7
+ * scripts/seed-walkthrough-fixture.mjs (line "Cast-film line A", English DAQ
8
+ * nodes, an English agent team). The UI is forced to the `en` locale (persisted
9
+ * in localStorage under `aw.locale`, applied by app/plugins/locale-restore.client.ts)
10
+ * before any capture, so every UI string is English.
11
+ *
12
+ * Geometry discipline: every crop is ≤470 CSS px wide (12 px UI text must print
13
+ * ≥ ~6.4 pt at the ~88 mm panel width of the 181 mm figure), except panel 2 whose
14
+ * four table columns cannot fit narrower.
15
+ *
16
+ * Usage:
17
+ * NO_PROXY='127.0.0.1,localhost' node scripts/seed-walkthrough-fixture.mjs
18
+ * NO_PROXY='127.0.0.1,localhost' AW_BASE=http://127.0.0.1:3005 node scripts/capture-walkthrough.mjs
19
+ */
20
+ import puppeteer from 'puppeteer-core'
21
+ import fs from 'node:fs'
22
+ import path from 'node:path'
23
+
24
+ const BASE = process.env.AW_BASE ?? 'http://127.0.0.1:3005'
25
+ const OUT = process.env.AW_OUT ?? 'paper/tii/figures/walkthrough'
26
+ fs.mkdirSync(OUT, { recursive: true })
27
+
28
+ const sleep = ms => new Promise(r => setTimeout(r, ms))
29
+ const tok = async (e, p) => {
30
+ const r = await (await fetch(`${BASE}/api/users/login`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email: e, password: p }) })).json()
31
+ if (!r.data?.token) throw new Error(`login failed: ${e} (${JSON.stringify(r).slice(0, 120)})`)
32
+ return r.data.token
33
+ }
34
+ const ADMIN = await tok('admin@awshop.local', 'admin123')
35
+
36
+ const jget = async (u) => {
37
+ const r = await (await fetch(`${BASE}${u}`, { headers: { Authorization: `Bearer ${ADMIN}` } })).json()
38
+ return r.data
39
+ }
40
+
41
+ // ── fixture discovery (fail loudly rather than silently capturing Chinese) ──
42
+ const LINES = (await jget('/api/workshop/dcw/lines')).lines
43
+ const LINE = LINES.find(l => l.name === 'Cast-film line A')
44
+ if (!LINE) throw new Error('English fixture line "Cast-film line A" missing — run scripts/seed-walkthrough-fixture.mjs first')
45
+ const DAQ = await jget('/api/workshop/daq')
46
+ const modbusNode = DAQ.nodes.find(n => n.lineId === LINE.id && n.driver === 'modbus-tcp')
47
+ if (!modbusNode) throw new Error('fixture Modbus-TCP node missing on Cast-film line A')
48
+ // panel 4 uses the real judged optimization records already on the ledger of this node
49
+ const RECORD_LINE = 'ln-af002514'
50
+ const RECORD_NODE = 'dw-322b1978'
51
+ console.log(`fixture line=${LINE.id} modbus=${modbusNode.id} (${modbusNode.name}) records=${RECORD_NODE}`)
52
+
53
+ const browser = await puppeteer.launch({
54
+ executablePath: process.env.AW_CHROME ?? 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
55
+ headless: 'new',
56
+ args: ['--no-sandbox', '--disable-gpu', '--proxy-server=direct://', '--proxy-bypass-list=*'],
57
+ })
58
+ const page = await browser.newPage()
59
+ const errs = []
60
+ page.on('pageerror', e => errs.push(String(e).slice(0, 120)))
61
+ await page.setViewport({ width: 1680, height: 1600, deviceScaleFactor: 3 })
62
+
63
+ const auth = async (t) => { const c = await page.target().createCDPSession(); await c.send('Network.clearBrowserCookies'); await page.setCookie({ name: 'token', value: t, domain: '127.0.0.1', path: '/' }) }
64
+ const goto = async (u, w = 10000) => { await page.goto(`${BASE}${u}`, { waitUntil: 'domcontentloaded', timeout: 90_000 }); await sleep(w) }
65
+
66
+ // content-visibility:auto sections report estimated rects until rendered; force real
67
+ // layout so element-accurate clips do not drift. Also kill CSS transitions/animations
68
+ // so a mid-transition frame (e.g. the hold-interval cell double-painting its value)
69
+ // can never be captured.
70
+ const settle = async () => {
71
+ await page.evaluate(() => {
72
+ let st = document.getElementById('aw-capture-calm')
73
+ if (!st) {
74
+ st = document.createElement('style')
75
+ st.id = 'aw-capture-calm'
76
+ st.textContent = '*,*::before,*::after{transition:none!important;transition-duration:0s!important;animation:none!important;animation-duration:0s!important;animation-delay:0s!important}'
77
+ document.head.appendChild(st)
78
+ }
79
+ for (const e of document.querySelectorAll('*')) {
80
+ const cs = getComputedStyle(e)
81
+ if (cs.contentVisibility && cs.contentVisibility !== 'visible') e.style.contentVisibility = 'visible'
82
+ }
83
+ window.scrollTo(0, document.body.scrollHeight)
84
+ })
85
+ await sleep(700)
86
+ await page.evaluate(() => window.scrollTo(0, 0))
87
+ await sleep(300)
88
+ }
89
+
90
+ // Grow the viewport to the full document height BEFORE measuring, so that the
91
+ // screenshot's captureBeyondViewport expansion cannot re-layout the page and
92
+ // shift elements between measurement and capture.
93
+ const expand = async () => {
94
+ const h = await page.evaluate(() => document.documentElement.scrollHeight)
95
+ await page.setViewport({ width: 1680, height: Math.min(Math.ceil(h) + 40, 14000), deviceScaleFactor: 3 })
96
+ await sleep(1200)
97
+ await settle()
98
+ }
99
+
100
+ const repaint = async () => {
101
+ await page.evaluate(() => new Promise(res => {
102
+ window.scrollTo(0, 0)
103
+ requestAnimationFrame(() => requestAnimationFrame(res))
104
+ }))
105
+ await sleep(120)
106
+ }
107
+
108
+ // Capture only once the pixels stop changing: two consecutive identical captures are
109
+ // required (guards against mid-transition / late-commit frames like double-struck text).
110
+ const shot = async (n, x, y, w, h, tries = 5) => {
111
+ const clip = { x, y, width: w, height: h }
112
+ let prev = null
113
+ let stable = false
114
+ for (let i = 0; i < tries; i++) {
115
+ await repaint()
116
+ const buf = Buffer.from(await page.screenshot({ encoding: 'binary', clip, captureBeyondViewport: true }))
117
+ if (prev && Buffer.compare(prev, buf) === 0) { prev = buf; stable = true; break }
118
+ prev = buf
119
+ await sleep(1000)
120
+ }
121
+ fs.writeFileSync(path.join(OUT, n), prev)
122
+ console.log(` ✓ ${n} ${Math.round(w)}x${Math.round(h)} css @3x ${stable ? 'stable' : 'NOT STABLE (last frame written)'}`)
123
+ }
124
+
125
+ // ── force English UI before any capture ──────────────────────────────────
126
+ await auth(ADMIN)
127
+ await goto('/daq', 4000)
128
+ await page.evaluate(() => localStorage.setItem('aw.locale', 'en'))
129
+ await page.reload({ waitUntil: 'domcontentloaded' })
130
+ await sleep(6000)
131
+ const heads = await page.evaluate(() => [...document.querySelectorAll('.nodes-table thead th')].map(t => t.textContent.trim()))
132
+ if (!heads.some(h => /Sampling/i.test(h))) throw new Error(`locale not English (headers: ${JSON.stringify(heads)})`)
133
+ console.log(`locale : en (headers: ${heads.join(' | ')})`)
134
+
135
+ // ══ ① provision & connect — /daq nodes filtered to the English line ══════
136
+ console.log('\n== ① /daq ==')
137
+ await page.evaluate((ln) => {
138
+ for (const s of document.querySelectorAll('select')) {
139
+ if ([...s.options].some(o => o.value === ln)) { s.value = ln; s.dispatchEvent(new Event('change', { bubbles: true })); break }
140
+ }
141
+ }, LINE.id)
142
+ await sleep(3500)
143
+ await settle()
144
+ await expand()
145
+
146
+ const G = await page.evaluate(() => {
147
+ const tbl = document.querySelector('.nodes-table')
148
+ const rect = tbl.getBoundingClientRect()
149
+ const ths = [...tbl.querySelectorAll('thead th')].map(t => ({ x: Math.round(t.getBoundingClientRect().x - rect.x), text: t.textContent.trim() }))
150
+ const rows = [...tbl.querySelectorAll('tbody tr')].map((tr) => {
151
+ const q = tr.getBoundingClientRect()
152
+ const tds = tr.querySelectorAll('td')
153
+ return { y: Math.round(q.y + window.scrollY), h: q.height, name: (tr.querySelector('b')?.textContent || '').trim(), driver: (tds[6]?.textContent || '').trim() }
154
+ })
155
+ return { x: rect.x, ths, rows }
156
+ })
157
+ console.log(' rows:', G.rows.map(r => `${r.name}[${r.driver}]`).join(', '))
158
+ if (!G.rows.some(r => r.driver.includes('modbus'))) throw new Error('no Modbus-TCP row visible on filtered line')
159
+ // columns: 4 Sampling · 5 WS Publish · 6 Driver · 7 Line (indices are locale-stable).
160
+ // Keep the crop ≤470 css px: 12 px UI text must print ≥ ~6.4 pt at the 88 mm panel width.
161
+ const mbIdx = G.rows.findIndex(r => r.driver.includes('modbus'))
162
+ const mkIdx = mbIdx > 0 ? mbIdx - 1 : 0
163
+ const x0 = G.x + G.ths[4].x
164
+ const x1 = G.x + G.ths[8].x
165
+ const yS = G.rows[mkIdx].y
166
+ const yE = G.rows[mbIdx].y + G.rows[mbIdx].h
167
+ console.log(` pair: ${G.rows[mkIdx].name}[${G.rows[mkIdx].driver}] + ${G.rows[mbIdx].name}[${G.rows[mbIdx].driver}]`)
168
+ await shot('p1-driver.png', x0 - 2, yS, Math.min(x1 - x0 + 4, 470), yE - yS)
169
+
170
+ // ══ ② bind node → line / device — /dcw/{English line} ═══════════════════
171
+ console.log('\n== ② /dcw/' + LINE.id + ' ==')
172
+ await goto(`/dcw/${LINE.id}`, 9000)
173
+ await settle()
174
+ await expand()
175
+ const D = await page.evaluate(() => {
176
+ const t = document.querySelector('.aw-tile.table-card table')
177
+ const rect = t.getBoundingClientRect()
178
+ const ths = [...t.querySelectorAll('thead th')].map(x => ({ x: Math.round(x.getBoundingClientRect().x - rect.x), text: x.textContent.trim() }))
179
+ return { x: rect.x, y: rect.y + window.scrollY, h: rect.height, ths }
180
+ })
181
+ console.log(' cols:', D.ths.map(c => c.text).join(' | '))
182
+ // columns: 5 Setpoint · 6 Process Range · 7 Hold Interval · 8 Bound Device
183
+ const c0 = D.x + D.ths[5].x
184
+ const c1 = D.x + D.ths[9].x
185
+ await shot('p2-binding.png', c0 - 6, D.y, (c1 - c0) + 12, D.h)
186
+
187
+ // ══ ④ governed closed loop — ledger optimization records (real, judged) ══
188
+ console.log('\n== ④ /dcw/' + RECORD_LINE + ' ledger ==')
189
+ await goto(`/dcw/${RECORD_LINE}`, 9000)
190
+ await page.evaluate((nid) => {
191
+ const s = document.querySelector('.ledger-card select.inp')
192
+ if (!s) return
193
+ s.value = nid
194
+ s.dispatchEvent(new Event('change', { bubbles: true }))
195
+ }, RECORD_NODE)
196
+ await sleep(3500)
197
+ await settle()
198
+ await expand()
199
+ const L = await page.evaluate(() => {
200
+ const card = document.querySelector('.ledger-card')
201
+ const col = [...card.querySelectorAll('.ledger-col')].find(c => c.querySelector('li.ledger-rec')) || [...card.querySelectorAll('.ledger-col')].pop()
202
+ const recs = [...col.querySelectorAll('li.ledger-rec')]
203
+ const r = col.getBoundingClientRect()
204
+ const last = recs[recs.length - 1].getBoundingClientRect()
205
+ return { x: r.x, y: r.y + window.scrollY, w: r.width, h: last.bottom - r.top, texts: recs.map(li => li.textContent.replace(/\s+/g, ' ').trim()) }
206
+ })
207
+ console.log(' records:', JSON.stringify(L.texts))
208
+ // tight: header + the real records, without the empty box below them
209
+ await shot('p4-records.png', L.x - 5, L.y - 5, Math.min(L.w + 14, 470), L.h + 14)
210
+
211
+ // ══ ③ compose & deploy the agent team — /workshop/teams ═════════════════
212
+ // Desktop viewport: one card in the multi-column grid (~343 px wide), which keeps the
213
+ // crop ≤470 css px so member text prints ≥ ~6 pt at the 88 mm panel width.
214
+ console.log('\n== ③ /workshop/teams ==')
215
+ await page.setViewport({ width: 1680, height: 1600, deviceScaleFactor: 3 })
216
+ await goto('/workshop/teams', 9000)
217
+ await settle()
218
+ await expand()
219
+ const cards = await page.evaluate(() => [...document.querySelectorAll('.grid .card')].map(e => {
220
+ const r = e.getBoundingClientRect()
221
+ const members = e.querySelectorAll('.member')
222
+ const last = members[members.length - 1]?.getBoundingClientRect()
223
+ return { x: Math.round(r.x), y: Math.round(r.y + window.scrollY), w: Math.round(r.width), h: Math.round(r.height), memberH: last ? Math.round(last.bottom - r.top) : Math.round(r.height), t: e.textContent.replace(/\s+/g, ' ').slice(0, 40) }
224
+ }))
225
+ console.log(' cards:', JSON.stringify(cards))
226
+ const tgt = cards.find(c => c.t.includes('Cast-film control team'))
227
+ if (!tgt) throw new Error('English team card not found on /workshop/teams')
228
+ // crop head + member rows only (excludes the Add-Member button) to keep the figure compact
229
+ await shot('p3-team.png', tgt.x - 5, tgt.y - 5, Math.min(tgt.w + 10, 470), tgt.memberH + 8)
230
+
231
+ console.log('\npageerrors:', errs.length ? errs.join(' | ') : 'none')
232
+ await browser.close()
@@ -7,7 +7,9 @@
7
7
  * 5. 成员移除 / team 更新 / 删除
8
8
  * 运行: node scripts/e2e-agent-team.mjs [--base http://127.0.0.1:3000]
9
9
  */
10
- const BASE = (process.argv.find(a => a.startsWith('--base='))?.slice(7) ?? 'http://127.0.0.1:3000') + '/api/workshop'
10
+ const BASE = (process.argv.find(a => a.startsWith('--base='))?.slice(7) ?? 'http://127.0.0.1:3000') + '/api/workshop'
11
+ // 注册走平台 origin 的 /api/users/register(不在 /api/workshop 下;注册现要求 email+password)
12
+ const ORIGIN = BASE.slice(0, BASE.indexOf('/api'))
11
13
 
12
14
  let pass = 0
13
15
  let fail = 0
@@ -21,9 +23,9 @@ function check(name, ok, detail = '') {
21
23
  }
22
24
 
23
25
  // 用户级隔离:注册测试用户;管理面 API 全程携带用户 token
24
- const __user = await fetch(BASE + '/users/register', {
26
+ const __user = await fetch(ORIGIN + '/api/users/register', {
25
27
  method: 'POST', headers: { 'content-type': 'application/json' },
26
- body: JSON.stringify({ name: 'e2e-' + Math.random().toString(36).slice(2, 10) }),
28
+ body: JSON.stringify({ name: 'e2e-' + Math.random().toString(36).slice(2, 10), email: `e2e-team-${Date.now()}@test.local`, password: 'Passw0rd!123' }),
27
29
  }).then(r => r.json()).catch(() => null)
28
30
  const __userToken = __user?.data?.token
29
31
  if (!__userToken) {
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Render the walkthrough figure HTML to (a) an exact-size PDF via headless Chrome
3
+ * --print-to-pdf and (b) a high-resolution PNG for inspection/archival.
4
+ *
5
+ * Usage: node scripts/render-walkthrough-figure.mjs
6
+ */
7
+ import { execFileSync } from 'node:child_process'
8
+ import fs from 'node:fs'
9
+ import path from 'node:path'
10
+ import puppeteer from 'puppeteer-core'
11
+
12
+ const CHROME = process.env.AW_CHROME ?? 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
13
+ const DIR = path.resolve('paper/tii/figures/walkthrough')
14
+ const SRC = path.join(DIR, 'fig-walkthrough.html')
15
+ if (!fs.existsSync(SRC)) throw new Error('missing ' + SRC)
16
+
17
+ // ── (a) exact-size PDF ────────────────────────────────────────────────────
18
+ const pdfUrl = 'file:///' + SRC.replace(/\\/g, '/')
19
+ const outPdf = path.resolve('paper/tii/figures/pdf/fig-walkthrough.pdf')
20
+ fs.mkdirSync(path.dirname(outPdf), { recursive: true })
21
+ execFileSync(CHROME, [
22
+ '--headless=new', '--disable-gpu', '--no-pdf-header-footer',
23
+ `--print-to-pdf=${outPdf}`, pdfUrl,
24
+ ], { stdio: 'ignore' })
25
+ const info = execFileSync('pdfinfo', [outPdf], { encoding: 'utf8' })
26
+ console.log('PDF :', outPdf)
27
+ console.log(' ', info.split('\n').filter(l => /Page size|Pages/.test(l)).join(' | ').trim())
28
+
29
+ // ── (b) high-resolution PNG (overall + per-panel) ─────────────────────────
30
+ const browser = await puppeteer.launch({ executablePath: CHROME, headless: 'new', args: ['--no-sandbox', '--disable-gpu', '--allow-file-access-from-files'] })
31
+ const page = await browser.newPage()
32
+ // 181 mm wide at 96 dpi/css == 684 css px; height is a minimum — fullPage grows to content
33
+ await page.setViewport({ width: 684, height: 200, deviceScaleFactor: 8 })
34
+ await page.goto(pdfUrl, { waitUntil: 'networkidle0' })
35
+ await page.evaluate(() => document.fonts?.ready)
36
+ await new Promise(r => setTimeout(r, 500))
37
+ await page.screenshot({ path: path.join(DIR, 'fig-walkthrough.png'), fullPage: true })
38
+ const png = fs.statSync(path.join(DIR, 'fig-walkthrough.png'))
39
+ console.log('PNG :', path.join(DIR, 'fig-walkthrough.png'), `${(png.size / 1024).toFixed(0)} KB`)
40
+
41
+ // medium-res variant for quick review
42
+ await page.setViewport({ width: 684, height: 200, deviceScaleFactor: 2 })
43
+ await page.screenshot({ path: path.join(DIR, '_preview.png'), fullPage: true })
44
+ console.log('PREV :', path.join(DIR, '_preview.png'))
45
+
46
+ await browser.close()
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Purpose-built ENGLISH-locale fixture for the IEEE TII Figure 2 walkthrough.
3
+ *
4
+ * The shared production instance is full of Chinese-named test data; we must NOT
5
+ * rename or delete anything. Instead this script creates a small additive fixture
6
+ * with English entity names via the platform's own REST API, so the four
7
+ * walkthrough screenshots contain English strings only:
8
+ *
9
+ * - line "Cast-film line A"
10
+ * - DAQ nodes mock + a real Modbus-TCP node on the PLC simulator, one line
11
+ * - device "Die-head heater" twin, bound by a DCW node with a 150-200 C window
12
+ * - agents English lead + workers on the `omp` harness
13
+ * - team "Cast-film control team" (lead + 2 workers)
14
+ *
15
+ * Idempotent: re-running reuses rows with the same names. Prints a JSON summary.
16
+ *
17
+ * Usage: NO_PROXY='127.0.0.1,localhost' node scripts/seed-walkthrough-fixture.mjs
18
+ */
19
+ const BASE = process.env.AW_BASE ?? 'http://127.0.0.1:3005'
20
+
21
+ const login = async (e, p) =>
22
+ (await (await fetch(`${BASE}/api/users/login`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email: e, password: p }) })).json()).data.token
23
+
24
+ const T = await login('admin@awshop.local', 'admin123')
25
+
26
+ const api = async (method, path, body) => {
27
+ const r = await fetch(`${BASE}${path}`, {
28
+ method,
29
+ headers: { Authorization: `Bearer ${T}`, ...(body ? { 'content-type': 'application/json' } : {}) },
30
+ body: body ? JSON.stringify(body) : undefined,
31
+ })
32
+ const j = await r.json().catch(() => ({}))
33
+ if (!r.ok || j.code !== 0) throw new Error(`${method} ${path} -> ${r.status} ${JSON.stringify(j).slice(0, 200)}`)
34
+ return j.data
35
+ }
36
+ const get = p => api('GET', p)
37
+ const post = (p, b) => api('POST', p, b)
38
+
39
+ // ── 1. production line ────────────────────────────────────────────────────
40
+ const LINE_NAME = 'Cast-film line A'
41
+ const lines = (await get('/api/workshop/dcw/lines')).lines
42
+ let line = lines.find(l => l.name === LINE_NAME)
43
+ if (!line) line = (await post('/api/workshop/dcw/lines', { name: LINE_NAME, color: '#f4c542' })).line
44
+ console.log(`line : ${line.id} ${line.name}`)
45
+
46
+ // ── 2. DAQ nodes on that line (mock + real Modbus-TCP share one loop) ─────
47
+ const daq = await get('/api/workshop/daq')
48
+ const haveNode = n => daq.nodes.find(x => x.name === n)
49
+ const mkNode = async (spec) => {
50
+ const existing = haveNode(spec.name)
51
+ if (existing) return existing
52
+ return (await post('/api/workshop/daq', { enabled: true, intervalMs: 1000, lineId: line.id, ...spec })).node
53
+ }
54
+
55
+ const nTemp = await mkNode({
56
+ name: 'Melt temperature', templateRef: 'daq-temp-tc', driver: 'mock',
57
+ unit: '\u00B0C', decimals: 1, min: 150, max: 200, warnLow: 155, warnHigh: 195,
58
+ })
59
+ const nSpeed = await mkNode({
60
+ name: 'Line speed', templateRef: 'daq-line-encoder', driver: 'mock',
61
+ unit: 'm/min', decimals: 0, min: 280, max: 360, warnLow: 290, warnHigh: 350,
62
+ })
63
+ const nPress = await mkNode({
64
+ name: 'Melt pressure', templateRef: 'daq-pressure-tx', driver: 'mock',
65
+ unit: 'MPa', decimals: 2, min: 0.6, max: 1.2, warnLow: 0.65, warnHigh: 1.15,
66
+ })
67
+ // real Modbus-TCP against the PLC simulator's "extruder" slave (melt-temp @ 40001)
68
+ const nModbus = await mkNode({
69
+ name: 'Die-head temperature', templateRef: 'daq-temp-tc', driver: 'modbus-tcp',
70
+ unit: '\u00B0C', decimals: 2, min: 0, max: 400, warnLow: 150, warnHigh: 260,
71
+ driverConfig: { host: '127.0.0.1', port: 16040, unitId: 1, register: 40001, dataType: 'float32', byteOrder: 'big' },
72
+ })
73
+ console.log(`daq : temp=${nTemp.id} speed=${nSpeed.id} pressure=${nPress.id} modbus=${nModbus.id}`)
74
+
75
+ // ── 3. device twin + DCW control node with a recipe window ────────────────
76
+ const twins = (await get('/api/workshop/device-twins')).twins
77
+ let twin = twins.find(t => t.name === 'Die-head heater')
78
+ if (!twin) twin = (await post('/api/workshop/device-twins', { name: 'Die-head heater', kind: 'device', controls: ['setpoint'] })).twin
79
+ console.log(`twin : ${twin.id} ${twin.name}`)
80
+
81
+ const dcw = await get('/api/workshop/dcw')
82
+ let dcwNode = dcw.nodes.find(n => n.name === 'Die-head setpoint')
83
+ if (!dcwNode) {
84
+ dcwNode = (await post('/api/workshop/dcw', {
85
+ name: 'Die-head setpoint', templateRef: 'dcw-temp-sp', driver: 'mock',
86
+ unit: '\u00B0C', decimals: 1, min: 150, max: 200,
87
+ holdIntervalMs: 5000, readIntervalMs: 5000, enabled: true,
88
+ lineId: line.id, deviceIds: [twin.id],
89
+ })).node
90
+ }
91
+ console.log(`dcw : ${dcwNode.id} ${dcwNode.name} bound=${twin.id} window=${dcwNode.min}-${dcwNode.max}`)
92
+
93
+ // ── 4. English agents + team (one lead, harness-backed workers) ───────────
94
+ const teams0 = await get('/api/workshop/teams')
95
+ let team = teams0.find(t => t.name === 'Cast-film control team')
96
+ if (!team) team = await post('/api/workshop/teams', { name: 'Cast-film control team', description: 'Cast-film process lead plus DAQ and modelling workers.', visibility: 'public' })
97
+
98
+ const teamId = team.id
99
+ const existingTeam = (await get('/api/workshop/teams')).find(t => t.id === teamId)
100
+ const memberNames = new Set((existingTeam?.members ?? []).map(m => m.name))
101
+
102
+ const AGENTS = [
103
+ { name: 'Cast-film process lead', harness: 'omp', role: 'lead' },
104
+ { name: 'DAQ engineer', harness: 'omp', role: 'worker' },
105
+ { name: 'Model trainer', harness: 'omp', role: 'worker' },
106
+ ]
107
+ for (const a of AGENTS) {
108
+ if (memberNames.has(a.name)) continue
109
+ const agent = await post('/api/workshop/agents', { name: a.name, harness: a.harness, visibility: 'public' })
110
+ await post(`/api/workshop/teams/${teamId}/members`, { agentId: agent.id, role: a.role })
111
+ }
112
+ const finalTeam = (await get('/api/workshop/teams')).find(t => t.id === teamId)
113
+ console.log(`team : ${teamId} ${finalTeam.name} members=${(finalTeam.members ?? []).map(m => `${m.role}:${m.name}:${m.harness}`).join(', ')}`)
114
+
115
+ // ── 5. start the line so DAQ acquisition is genuinely live ────────────────
116
+ // DAQ sampling is gated on an active per-line batch (recipe run). Without a run
117
+ // the nodes report `offline` and the panel-1 claim "share one acquisition loop"
118
+ // would be untrue. Create a product + recipe carrying one setpoint param and
119
+ // start the line; idempotent via the line's active-run flag.
120
+ const lineStates = (await get('/api/workshop/dcw/lines')).states
121
+ const alreadyRunning = lineStates.find(s => s.lineId === line.id && s.active)
122
+ if (alreadyRunning) {
123
+ console.log(`run : already active ${alreadyRunning.runId}`)
124
+ }
125
+ else {
126
+ const dcwState = await get('/api/workshop/dcw')
127
+ let product = (dcwState.products ?? []).find(p => p.name === 'Cast-film roll')
128
+ if (!product) product = (await post('/api/workshop/dcw/products', { name: 'Cast-film roll', lineId: line.id })).product
129
+ let recipe = (dcwState.recipes ?? []).find(r => r.name === 'Cast-film recipe' && r.lineId === line.id)
130
+ if (!recipe) {
131
+ recipe = (await post('/api/workshop/dcw/recipes', {
132
+ productId: product.id,
133
+ name: 'Cast-film recipe',
134
+ description: 'Cast-film line A baseline recipe.',
135
+ params: [{ nodeId: dcwNode.id, value: 178, min: 150, max: 200 }],
136
+ daqWindows: [{ nodeId: nTemp.id, min: 150, max: 200 }],
137
+ })).recipe
138
+ }
139
+ await post(`/api/workshop/dcw/lines/${line.id}/start`, { recipeId: recipe.id })
140
+ console.log(`run : started with recipe ${recipe.id} (${recipe.name})`)
141
+ }
142
+
143
+ console.log('\nFIXTURE ' + JSON.stringify({ lineId: line.id, lineName: line.name, modbusNodeId: nModbus.id, dcwNodeId: dcwNode.id, twinId: twin.id, teamId }))
@@ -60,6 +60,14 @@ console.log('\n━━━ 3. 稳定性护栏的严重性判定(哪类异常不该
60
60
  check('undici UND_ERR_CONNECT_TIMEOUT → upstream', classifyFatalCandidate(err('UND_ERR_CONNECT_TIMEOUT')) === 'upstream')
61
61
  check('无 code 但 message 带 ECONNREFUSED → upstream',
62
62
  classifyFatalCandidate(new Error('connect ECONNREFUSED 127.0.0.1:1502')) === 'upstream')
63
+ // 实测事故 2:工业驱动库(Modbus/OPC UA 客户端)超时时只给可读 message、不带 errno code,
64
+ // 旧实现据此判 fatal → 生产实例运行中 exit 1(平台带着数采/数控一起挂掉)。
65
+ check('无 code,message "TCP Connection Timed Out" → upstream',
66
+ classifyFatalCandidate(new Error('TCP Connection Timed Out')) === 'upstream')
67
+ check('无 code,message "connection timed out" → upstream',
68
+ classifyFatalCandidate(new Error('connect error: connection timed out')) === 'upstream')
69
+ check('无 code,message "socket hang up" → upstream',
70
+ classifyFatalCandidate(new Error('socket hang up')) === 'upstream')
63
71
 
64
72
  // 其余既有分级不得回退
65
73
  check('ECONNRESET(客户端硬断)→ socket', classifyFatalCandidate(err('ECONNRESET')) === 'socket')
@@ -378,16 +378,16 @@ let channelB
378
378
 
379
379
  // KB 回环:kb_index 入库独特自然语句 → kb_search 命中(嵌入/分词对自然语句才可靠);kb_store 沉淀经验
380
380
  const marker = `三系统验证密语${Date.now().toString(36)}:青花瓷泵站三十七号叶片于黄昏完成校准`
381
- const idx = await invoke(toolInvoker, 'kb_index', {
381
+ const idx = await invoke(toolInvoker, 'kb_index', { // rag 负载下事件循环停顿可达 60s+,放宽超时
382
382
  title: `三系统集成验证 ${Date.now().toString(36)}`,
383
383
  content: `# 三系统集成验证\n\n${marker}。\n\n本文由 three-system-e2e 经 rag-bridge 插件写入,验证 文档写盘 → 向量索引 → kb_search 检索 全链路。\n`,
384
384
  tags: ['e2e'],
385
- })
385
+ }, 120000)
386
386
  ok(resultText(idx).includes('已入库'), 'kb_index 文档入库成功', resultText(idx).slice(0, 80))
387
387
  let hit = ''
388
- for (let i = 0; i < 10; i++) { // 首次检索可能触发 BGE-M3 模型加载,放宽到 10×3s
388
+ for (let i = 0; i < 20; i++) { // 首次检索可能触发 BGE-M3 加载/异步索引落盘,放宽到 20×3s
389
389
  await sleep(3000)
390
- const s = await invoke(toolInvoker, 'kb_search', { query: marker })
390
+ const s = await invoke(toolInvoker, 'kb_search', { query: marker }, 120000)
391
391
  hit = resultText(s)
392
392
  if (hit.includes(marker)) break
393
393
  }
@@ -400,7 +400,7 @@ let channelB
400
400
  solution: '先查产线 LineRun 是否活动、节点 publishIntervalMs 是否在节拍上,再缩窗重试。',
401
401
  key_lessons: ['空窗先查打标窗口', 'bucket 5s 可对齐多节点'],
402
402
  tags: ['e2e', 'daq'],
403
- })
403
+ }, 120000)
404
404
  ok(resultText(store).includes('已沉淀'), 'kb_store 经验沉淀成功', resultText(store).slice(0, 80))
405
405
 
406
406
  // 跨通道:分析组长 → 控制组长(require_reply;用频道 ID 定向,避免跨账号同名频道歧义)
@@ -628,7 +628,7 @@ let runId = ''
628
628
  return (envelopeData(members) ?? []).find(m => m?.role === 'lead') ?? leadA
629
629
  }
630
630
  let gone = false
631
- for (let i = 0; i < 20 && !gone; i++) {
631
+ for (let i = 0; i < 40 && !gone; i++) { // 共享实例 agent 运行时重建慢,60s 窗
632
632
  await sleep(1500)
633
633
  const fl = await freshLead()
634
634
  const h = await raw('GET', `${BASE}/api/plugins/diag-bridge/health`, { token: userToken })
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 以 **admin 账号** 登录并给数采 / 数控 / 数字孪生出图。
3
+ * 与 lib.mjs 的视觉走查账号(visual)区分:admin 是文档里写的管理员账号,
4
+ * 能看见全量节点与全部产线;演示工作区由 scripts/ui/seed-admin.mjs 准备。
5
+ */
6
+ import { launch, openPage, gotoReady } from './lib.mjs'
7
+ import fs from 'node:fs'
8
+
9
+ const BASE = process.env.AW_BASE ?? 'http://127.0.0.1:3021'
10
+ const OUT = process.env.AW_OUT ?? '.e2e-shots/admin'
11
+ fs.mkdirSync(OUT, { recursive: true })
12
+
13
+ const loginRes = await fetch(BASE + '/api/users/login', {
14
+ method: 'POST',
15
+ headers: { 'content-type': 'application/json' },
16
+ body: JSON.stringify({ email: 'admin@awshop.local', password: 'admin123' }),
17
+ })
18
+ const login = await loginRes.json()
19
+ if (login.code !== 0) throw new Error('admin 登录失败: ' + JSON.stringify(login).slice(0, 200))
20
+ const token = login.data.token
21
+ console.log('登录成功:', login.data.user.name, '(' + login.data.user.role + ')')
22
+
23
+ const browser = await launch()
24
+ const routes = [
25
+ { path: '/', name: '01-dashboard', wait: 9000 },
26
+ { path: '/daq', name: '02-daq', wait: 12000 },
27
+ { path: '/dcw', name: '03-dcw', wait: 9000 },
28
+ { path: '/town', name: '04-town', wait: 16000 },
29
+ { path: '/monitor', name: '05-monitor', wait: 7000 },
30
+ ]
31
+ for (const r of routes) {
32
+ const page = await openPage(browser, { token, dark: true, width: 1440, height: 900, deviceScaleFactor: 2 })
33
+ const errs = []
34
+ page.on('pageerror', e => errs.push(String(e.message).slice(0, 120)))
35
+ await gotoReady(page, r.path, { wait: r.wait })
36
+ const file = OUT + '/' + r.name + '.png'
37
+ await page.screenshot({ path: file })
38
+ const info = await page.evaluate(() => ({
39
+ nodes: document.querySelectorAll('*').length,
40
+ text: document.body.innerText.replace(/\s+/g, ' ').slice(0, 120),
41
+ }))
42
+ console.log(' ok ' + r.name.padEnd(16) + ' dom=' + String(info.nodes).padStart(6) + ' errs=' + errs.length)
43
+ await page.close()
44
+ }
45
+ await browser.close()
46
+ console.log('->', OUT)