agentworkshop 0.7.23 → 0.7.27

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 (344) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/0jKrzLuM.js +19 -0
  3. package/.output/public/_nuxt/2jaJHWIJ.js +1 -0
  4. package/.output/public/_nuxt/{Cor9siSf.js → 6PZPfFcO.js} +1 -1
  5. package/.output/public/_nuxt/B7gZokg82.js +209 -0
  6. package/.output/public/_nuxt/B8kt898d.js +1 -0
  7. package/.output/public/_nuxt/{B-xskWta.js → BCJFMBQ6.js} +1 -1
  8. package/.output/public/_nuxt/BFGpEo8S.js +1 -0
  9. package/.output/public/_nuxt/BG4zduPf.js +14 -0
  10. package/.output/public/_nuxt/{DNxVTfhe.js → BGhOrgle.js} +1 -1
  11. package/.output/public/_nuxt/{n3vMFfrv.js → BHcpzI2n.js} +3 -3
  12. package/.output/public/_nuxt/{CEHmSufQ.js → BTLEvDxM.js} +1 -1
  13. package/.output/public/_nuxt/{CYBq3kS7.js → BWyR3awA.js} +1 -1
  14. package/.output/public/_nuxt/Bc89zKq2.js +1 -0
  15. package/.output/public/_nuxt/BetmGSO4.js +1 -0
  16. package/.output/public/_nuxt/{DAR70Lf5.js → BgCrZKv_2.js} +1 -1
  17. package/.output/public/_nuxt/BowTbasd.js +1 -0
  18. package/.output/public/_nuxt/BvtknqSC2.js +1 -0
  19. package/.output/public/_nuxt/CJviSvm-.js +1 -0
  20. package/.output/public/_nuxt/CTfqWGdy.js +1 -0
  21. package/.output/public/_nuxt/Cb3SnTM8.js +1 -0
  22. package/.output/public/_nuxt/Chc5pfAA.js +1 -0
  23. package/.output/public/_nuxt/CmHzfVc5.js +3 -0
  24. package/.output/public/_nuxt/Cn3J3NXR.js +23 -0
  25. package/.output/public/_nuxt/CobSUzQv.js +2 -0
  26. package/.output/public/_nuxt/{kZV5TQvh2.js → CucID8qg2.js} +1 -1
  27. package/.output/public/_nuxt/{CfVAr2nf.js → Cz9gD2Yo.js} +1 -1
  28. package/.output/public/_nuxt/{E88a-JCG.js → DGAOugLt.js} +1 -1
  29. package/.output/public/_nuxt/DHbTyoAV.js +1 -0
  30. package/.output/public/_nuxt/{BxtpDtzC.js → DNQF_TXX.js} +1 -1
  31. package/.output/public/_nuxt/DfLUN8kY.js +1 -0
  32. package/.output/public/_nuxt/DjU9Dx5Y.js +1 -0
  33. package/.output/public/_nuxt/DnziMlcX.js +1 -0
  34. package/.output/public/_nuxt/{BBwMH_hG.js → DoAlYsiF.js} +1 -1
  35. package/.output/public/_nuxt/{DA4lxCWC2.js → DosOJEmZ2.js} +2 -2
  36. package/.output/public/_nuxt/{DWcEk1ur2.js → DvgKXPgu2.js} +1 -1
  37. package/.output/public/_nuxt/{ed5qX-x5.js → Q_SJDSgx.js} +1 -1
  38. package/.output/public/_nuxt/{TownView.zu2rU5nS.css → TownView.CtskuMXS.css} +1 -1
  39. package/.output/public/_nuxt/XY2z78rj.js +1 -0
  40. package/.output/public/_nuxt/_id_.DdbYeLqn.css +1 -0
  41. package/.output/public/_nuxt/bFnZa2yd.js +1 -0
  42. package/.output/public/_nuxt/builds/latest.json +1 -1
  43. package/.output/public/_nuxt/builds/meta/f7a8e33d-5422-45ac-895d-27168f97e3ad.json +1 -0
  44. package/.output/public/_nuxt/daq.DGV9QS8d.css +1 -0
  45. package/.output/public/_nuxt/entry.BN02X8iR.css +1 -0
  46. package/.output/public/_nuxt/monitor.B--1dPzs.css +1 -0
  47. package/.output/public/_nuxt/permissions.B1pjGChZ.css +1 -0
  48. package/.output/public/_nuxt/plugins.DpCuwaJt.css +1 -0
  49. package/.output/public/_nuxt/rkVgzg62.js +1 -0
  50. package/.output/public/_nuxt/settings.W6qrYAui.css +1 -0
  51. package/.output/public/_nuxt/teams.BBXVkyKq.css +1 -0
  52. package/.output/public/_nuxt/tokens.xRb1fSPU.css +1 -0
  53. package/.output/public/_nuxt/users.DuAt_Zwf.css +1 -0
  54. package/.output/public/_nuxt/workshop.BJg84pOK.css +1 -0
  55. package/.output/public/assets/game/character/yangyang-walk.glb +0 -0
  56. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  57. package/.output/server/chunks/_/nitro.mjs +1073 -925
  58. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  59. package/.output/server/chunks/build/{OmpTerminalPanel-Ban3yJZ4.mjs → OmpTerminalPanel-Cw_Vw9oO.mjs} +3 -3
  60. package/.output/server/chunks/build/{OmpTerminalPanel-Ban3yJZ4.mjs.map → OmpTerminalPanel-Cw_Vw9oO.mjs.map} +1 -1
  61. package/.output/server/chunks/build/{TownView-DxeQe1Bl.mjs → TownView-ftIylqiD.mjs} +178 -151
  62. package/.output/server/chunks/build/{TownView-DxeQe1Bl.mjs.map → TownView-ftIylqiD.mjs.map} +1 -1
  63. package/.output/server/chunks/build/{_id_-DQDqj-cZ.mjs → _id_-3Axz2-gV.mjs} +35 -35
  64. package/.output/server/chunks/build/{_id_-DQDqj-cZ.mjs.map → _id_-3Axz2-gV.mjs.map} +1 -1
  65. package/.output/server/chunks/build/{_id_-DY6v6sqB.mjs → _id_-CahfkmEt.mjs} +5 -5
  66. package/.output/server/chunks/build/{_id_-DY6v6sqB.mjs.map → _id_-CahfkmEt.mjs.map} +1 -1
  67. package/.output/server/chunks/build/{_wsId_-C2O5zZsI.mjs → _wsId_-BymlQhzS.mjs} +13 -15
  68. package/.output/server/chunks/build/{_wsId_-C2O5zZsI.mjs.map → _wsId_-BymlQhzS.mjs.map} +1 -1
  69. package/.output/server/chunks/build/{agents--6bzGtES.mjs → agents-DuMiSWKp.mjs} +7 -9
  70. package/.output/server/chunks/build/agents-DuMiSWKp.mjs.map +1 -0
  71. package/.output/server/chunks/build/button-DEcZFcqN.mjs +1 -1
  72. package/.output/server/chunks/build/{card-CCPQoKlh.mjs → card-Dipvaykh.mjs} +4 -4
  73. package/.output/server/chunks/build/{card-CCPQoKlh.mjs.map → card-Dipvaykh.mjs.map} +1 -1
  74. package/.output/server/chunks/build/{channel-templates-C1Bb-U75.mjs → channel-templates-BStqJ-of.mjs} +5 -7
  75. package/.output/server/chunks/build/channel-templates-BStqJ-of.mjs.map +1 -0
  76. package/.output/server/chunks/build/{checkbox-Dv1kjaUZ.mjs → checkbox-C1gABOca.mjs} +5 -5
  77. package/.output/server/chunks/build/{checkbox-Dv1kjaUZ.mjs.map → checkbox-C1gABOca.mjs.map} +1 -1
  78. package/.output/server/chunks/build/{daq-B-3xCp_2.mjs → daq-ChYCABz1.mjs} +312 -426
  79. package/.output/server/chunks/build/daq-ChYCABz1.mjs.map +1 -0
  80. package/.output/server/chunks/build/{dcw-BL2dhuz7.mjs → dcw-CcQNGggh.mjs} +3 -3
  81. package/.output/server/chunks/build/{dcw-BL2dhuz7.mjs.map → dcw-CcQNGggh.mjs.map} +1 -1
  82. package/.output/server/chunks/build/{default-DdV642BY.mjs → default-95-zOTPt.mjs} +3 -4
  83. package/.output/server/chunks/build/{default-DdV642BY.mjs.map → default-95-zOTPt.mjs.map} +1 -1
  84. package/.output/server/chunks/build/dropdown-vhn1NPFs.mjs +1 -1
  85. package/.output/server/chunks/build/{input-number-CZ3ZrCsy.mjs → input-number-Bd55elNN.mjs} +3 -3
  86. package/.output/server/chunks/build/{input-number-CZ3ZrCsy.mjs.map → input-number-Bd55elNN.mjs.map} +1 -1
  87. package/.output/server/chunks/build/{input-DxDqeyQW.mjs → input-sf_BT6o6.mjs} +553 -5
  88. package/.output/server/chunks/build/input-sf_BT6o6.mjs.map +1 -0
  89. package/.output/server/chunks/build/{logs-Dto_umFY.mjs → logs-D-2UyGtE.mjs} +3 -3
  90. package/.output/server/chunks/build/{logs-Dto_umFY.mjs.map → logs-D-2UyGtE.mjs.map} +1 -1
  91. package/.output/server/chunks/build/menu-WCrlpYVh.mjs +2 -2
  92. package/.output/server/chunks/build/modal-yvUquPj5.mjs +2 -2
  93. package/.output/server/chunks/build/{monitor-miqq9xHB.mjs → monitor-mfG5jBtz.mjs} +70 -192
  94. package/.output/server/chunks/build/monitor-mfG5jBtz.mjs.map +1 -0
  95. package/.output/server/chunks/build/{pages-D9tOoJsf.mjs → pages-Dfosfchr.mjs} +5 -6
  96. package/.output/server/chunks/build/pages-Dfosfchr.mjs.map +1 -0
  97. package/.output/server/chunks/build/{permissions-CxEgXic0.mjs → permissions-B-hhZuzm.mjs} +288 -194
  98. package/.output/server/chunks/build/permissions-B-hhZuzm.mjs.map +1 -0
  99. package/.output/server/chunks/build/{plugins-wLIKHcIE.mjs → plugins-DZR0T4Mh.mjs} +17 -17
  100. package/.output/server/chunks/build/{plugins-wLIKHcIE.mjs.map → plugins-DZR0T4Mh.mjs.map} +1 -1
  101. package/.output/server/chunks/build/popconfirm-CRaHcz5O.mjs +1 -1
  102. package/.output/server/chunks/build/{segmented-ChmQZwz6.mjs → segmented-LPPREMtZ.mjs} +336 -5
  103. package/.output/server/chunks/build/{segmented-ChmQZwz6.mjs.map → segmented-LPPREMtZ.mjs.map} +1 -1
  104. package/.output/server/chunks/build/{settings-BPBll_7K.mjs → settings-BajN9TQW.mjs} +254 -27
  105. package/.output/server/chunks/build/settings-BajN9TQW.mjs.map +1 -0
  106. package/.output/server/chunks/build/space-CCBYAkXt.mjs +1 -1
  107. package/.output/server/chunks/build/switch-CelRXpcy.mjs +1 -1
  108. package/.output/server/chunks/build/{table-BtksyDlQ.mjs → table-Bf1r2JjE.mjs} +5 -5
  109. package/.output/server/chunks/build/{table-BtksyDlQ.mjs.map → table-Bf1r2JjE.mjs.map} +1 -1
  110. package/.output/server/chunks/build/{tabs-DQv-_-R6.mjs → tabs-BM3tAh_J.mjs} +2 -2
  111. package/.output/server/chunks/build/{tabs-DQv-_-R6.mjs.map → tabs-BM3tAh_J.mjs.map} +1 -1
  112. package/.output/server/chunks/build/{tag-A0tZ2Ouq.mjs → tag-NO9jEqKy.mjs} +3 -3
  113. package/.output/server/chunks/build/{tag-A0tZ2Ouq.mjs.map → tag-NO9jEqKy.mjs.map} +1 -1
  114. package/.output/server/chunks/build/{teams-DD8ZXTKL.mjs → teams-t2SkRlJP.mjs} +349 -51
  115. package/.output/server/chunks/build/teams-t2SkRlJP.mjs.map +1 -0
  116. package/.output/server/chunks/build/{tokens-Dxnuw96_.mjs → tokens-DiCojbN8.mjs} +296 -200
  117. package/.output/server/chunks/build/tokens-DiCojbN8.mjs.map +1 -0
  118. package/.output/server/chunks/build/{town-Dsh0jlwZ.mjs → town-C7QM8DYK.mjs} +5 -5
  119. package/.output/server/chunks/build/{town-Dsh0jlwZ.mjs.map → town-C7QM8DYK.mjs.map} +1 -1
  120. package/.output/server/chunks/build/{useDaqStream-DkRL3tEW.mjs → useDaqStream-BeA2X8KR.mjs} +26 -11
  121. package/.output/server/chunks/build/useDaqStream-BeA2X8KR.mjs.map +1 -0
  122. package/.output/server/chunks/build/{useDcwStream-DyB2ufQI.mjs → useDcwStream-BJW_MitY.mjs} +14 -6
  123. package/.output/server/chunks/build/useDcwStream-BJW_MitY.mjs.map +1 -0
  124. package/.output/server/chunks/build/{useDeviceTwins-ZbT86L9O.mjs → useDeviceTwins-Dwz_EY_i.mjs} +2 -2
  125. package/.output/server/chunks/build/{useDeviceTwins-ZbT86L9O.mjs.map → useDeviceTwins-Dwz_EY_i.mjs.map} +1 -1
  126. package/.output/server/chunks/build/{useOpsLog-8HCYFb6n.mjs → useOpsLog-Dm8QEb1I.mjs} +2 -2
  127. package/.output/server/chunks/build/{useOpsLog-8HCYFb6n.mjs.map → useOpsLog-Dm8QEb1I.mjs.map} +1 -1
  128. package/.output/server/chunks/build/{useWorkshopApi-D2gq06N2.mjs → useWorkshopApi-B-L3MmIX.mjs} +9 -2
  129. package/.output/server/chunks/build/{useWorkshopApi-D2gq06N2.mjs.map → useWorkshopApi-B-L3MmIX.mjs.map} +1 -1
  130. package/.output/server/chunks/build/{users-D6RNylrW.mjs → users-B9SAdEtH.mjs} +12 -13
  131. package/.output/server/chunks/build/users-B9SAdEtH.mjs.map +1 -0
  132. package/.output/server/chunks/build/{workshop-CTcYDq2i.mjs → workshop-81xhz368.mjs} +21 -22
  133. package/.output/server/chunks/build/workshop-81xhz368.mjs.map +1 -0
  134. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +14 -2
  135. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
  136. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  137. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +40 -0
  138. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs.map +1 -0
  139. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +21 -9
  140. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
  141. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +33 -0
  142. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs.map +1 -0
  143. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +1 -1
  144. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +15 -1
  145. package/.output/server/chunks/routes/api/workshop/channels.post.mjs.map +1 -1
  146. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +1 -1
  147. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +1 -1
  148. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +1 -1
  149. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +1 -1
  150. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
  151. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +1 -1
  152. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +1 -1
  153. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +1 -1
  154. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +1 -1
  155. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +1 -1
  156. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +1 -1
  157. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +1 -1
  158. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
  159. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
  160. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
  161. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +1 -1
  162. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
  163. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
  164. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +1 -1
  165. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +1 -1
  166. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
  167. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
  168. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
  169. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +1 -1
  170. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
  171. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +1 -1
  172. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
  173. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
  174. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
  175. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +1 -1
  176. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
  177. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +1 -1
  178. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
  179. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
  180. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
  181. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +1 -1
  182. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
  183. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
  184. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
  185. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
  186. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
  187. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +1 -1
  188. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +1 -1
  189. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
  190. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
  191. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
  192. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +1 -1
  193. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
  194. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +1 -1
  195. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +1 -1
  196. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
  197. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
  198. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  199. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  200. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +1 -1
  201. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +1 -1
  202. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  204. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  205. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  206. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  207. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +1 -1
  210. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +1 -1
  211. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +1 -1
  212. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
  213. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +1 -1
  214. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  215. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  216. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  217. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  218. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  219. package/.output/server/chunks/routes/renderer.mjs +3 -3
  220. package/.output/server/chunks/virtual/entry.mjs +381 -438
  221. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  222. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  223. package/.output/server/package.json +1 -1
  224. package/app/app.vue +7 -0
  225. package/app/assets/css/main.css +12 -1
  226. package/app/components/workshop/DaqNodeRow.vue +398 -0
  227. package/app/components/workshop/town/ModelPreview3D.vue +26 -4
  228. package/app/components/workshop/town/TownScene3D.ts +60 -12
  229. package/app/components/workshop/town/TownView.vue +4 -3
  230. package/app/composables/workshop/useCharacterAssets.ts +1 -0
  231. package/app/composables/workshop/useDaqStream.ts +24 -5
  232. package/app/composables/workshop/useDcwStream.ts +13 -4
  233. package/app/composables/workshop/useWorkshopApi.ts +294 -259
  234. package/app/pages/daq/[id].vue +27 -3
  235. package/app/pages/daq/index.vue +8 -355
  236. package/app/pages/monitor.vue +56 -68
  237. package/app/pages/permissions/index.vue +86 -82
  238. package/app/pages/plugins/index.vue +12 -7
  239. package/app/pages/settings.vue +253 -2
  240. package/app/pages/tokens.vue +94 -96
  241. package/app/pages/users.vue +10 -18
  242. package/app/pages/workshop/index.vue +34 -5
  243. package/app/pages/workshop/teams.vue +212 -2
  244. package/i18n/dicts/_en.json +361 -1
  245. package/i18n/dicts/plugins.json +10 -0
  246. package/i18n/dicts/settings.json +1 -0
  247. package/i18n/dicts/teamPlugins.json +10 -0
  248. package/i18n/locales/en.ts +1861 -1901
  249. package/i18n/locales/zh-CN.ts +1789 -1830
  250. package/package.json +149 -148
  251. package/public/assets/game/character/yangyang-walk.glb +0 -0
  252. package/scripts/_dbg-cpu-profile.mjs +53 -0
  253. package/scripts/_dbg-logs-ui-e2e.py +3 -2
  254. package/scripts/_dbg-render-perf.mjs +142 -0
  255. package/scripts/_dbg-render-regression.mjs +130 -0
  256. package/scripts/_dbg-ui-survey.py +52 -0
  257. package/scripts/i18n-merge.mjs +152 -30
  258. package/scripts/production-closed-loop-e2e.mjs +254 -0
  259. package/scripts/team-plugins-api-smoke.mjs +149 -0
  260. package/scripts/three-system-e2e.mjs +448 -0
  261. package/server/api/plugins/[name]/[...path].ts +46 -31
  262. package/server/api/workshop/channels/[id]/plugins/index.get.ts +35 -0
  263. package/server/api/workshop/channels/[id]/plugins/index.put.ts +39 -0
  264. package/server/api/workshop/channels.post.ts +17 -0
  265. package/server/data/dcw-lines.json +14 -0
  266. package/server/data/dcw-products.json +14 -0
  267. package/server/data/dcw-recipes.json +23 -1
  268. package/server/data/dcw-rollback.json +585 -10
  269. package/server/data/dcw-runs.json +27 -27
  270. package/server/data/dcw-writes.json +96 -0
  271. package/server/data/dcws.json +394 -366
  272. package/server/data/scene-layouts.json +66 -0
  273. package/server/plugins/aw-plugins.ts +35 -27
  274. package/server/plugins-builtin/diag-bridge/index.mjs +556 -0
  275. package/server/plugins-builtin/rag-bridge/index.mjs +364 -0
  276. package/server/services/workshop/agents/host-tool-bridge.ts +659 -642
  277. package/server/services/workshop/agents/omp-agent.ts +1178 -1178
  278. package/server/services/workshop/agents/plugin-tools.ts +10 -1
  279. package/server/services/workshop/db/channel-plugins.repo.ts +65 -0
  280. package/server/services/workshop/plugins/host.mjs +52 -4
  281. package/server/services/workshop/runtime/manager.ts +2976 -2968
  282. package/shared/config/schema.json +4 -0
  283. package/.output/public/_nuxt/BJbhwS5o.js +0 -1
  284. package/.output/public/_nuxt/BUcmySDa2.js +0 -209
  285. package/.output/public/_nuxt/BWC4HQHQ.js +0 -1
  286. package/.output/public/_nuxt/BbZAzXjZ2.js +0 -1
  287. package/.output/public/_nuxt/BgOhoDTI.js +0 -1
  288. package/.output/public/_nuxt/Bo8t5fkJ.js +0 -1
  289. package/.output/public/_nuxt/BuiGDfMB.js +0 -1
  290. package/.output/public/_nuxt/BxPPAkGA.js +0 -3
  291. package/.output/public/_nuxt/C53drffV.js +0 -1
  292. package/.output/public/_nuxt/CcwJ2mrD2.js +0 -1
  293. package/.output/public/_nuxt/Cr9DkD1d.js +0 -1
  294. package/.output/public/_nuxt/DTYBfjRY.js +0 -1
  295. package/.output/public/_nuxt/DVoWWlUW.js +0 -1
  296. package/.output/public/_nuxt/Dc32T41C.js +0 -1
  297. package/.output/public/_nuxt/Dhqra7NB.js +0 -1
  298. package/.output/public/_nuxt/DlRO_q5L.js +0 -1
  299. package/.output/public/_nuxt/DsUUYP292.js +0 -1
  300. package/.output/public/_nuxt/Dsdy4Ua-.js +0 -1
  301. package/.output/public/_nuxt/DtzZqC0z.js +0 -1
  302. package/.output/public/_nuxt/Ko9mMsJj.js +0 -14
  303. package/.output/public/_nuxt/RzXYI9FM.js +0 -23
  304. package/.output/public/_nuxt/UtviM1bg.js +0 -1
  305. package/.output/public/_nuxt/_id_.C-YXjn8Q.css +0 -1
  306. package/.output/public/_nuxt/bAFueD6a.js +0 -1
  307. package/.output/public/_nuxt/builds/meta/1adc96e0-8bbd-4a79-ac7e-b6952556fef8.json +0 -1
  308. package/.output/public/_nuxt/daq.3OKj58HH.css +0 -1
  309. package/.output/public/_nuxt/dbi5bHkY.js +0 -2
  310. package/.output/public/_nuxt/eHYnGew0.js +0 -19
  311. package/.output/public/_nuxt/entry.OR_psZHp.css +0 -1
  312. package/.output/public/_nuxt/jyQyulh-.js +0 -1
  313. package/.output/public/_nuxt/monitor.CmwpEUCI.css +0 -1
  314. package/.output/public/_nuxt/permissions.DTRtZeTw.css +0 -1
  315. package/.output/public/_nuxt/plugins.BcSEwwGb.css +0 -1
  316. package/.output/public/_nuxt/settings.BqMF2nfj.css +0 -1
  317. package/.output/public/_nuxt/teams.DN0pAGGu.css +0 -1
  318. package/.output/public/_nuxt/tokens.BVXU1jOK.css +0 -1
  319. package/.output/public/_nuxt/users.D8lcLE62.css +0 -1
  320. package/.output/public/_nuxt/workshop.CbymC2LY.css +0 -1
  321. package/.output/public/_nuxt/zVkqCZ78.js +0 -1
  322. package/.output/server/chunks/build/Col-biaNnEPf.mjs +0 -338
  323. package/.output/server/chunks/build/Col-biaNnEPf.mjs.map +0 -1
  324. package/.output/server/chunks/build/agents--6bzGtES.mjs.map +0 -1
  325. package/.output/server/chunks/build/channel-templates-C1Bb-U75.mjs.map +0 -1
  326. package/.output/server/chunks/build/daq-B-3xCp_2.mjs.map +0 -1
  327. package/.output/server/chunks/build/hasIn-vQ9LWt-J.mjs +0 -554
  328. package/.output/server/chunks/build/hasIn-vQ9LWt-J.mjs.map +0 -1
  329. package/.output/server/chunks/build/input-DxDqeyQW.mjs.map +0 -1
  330. package/.output/server/chunks/build/monitor-miqq9xHB.mjs.map +0 -1
  331. package/.output/server/chunks/build/pages-D9tOoJsf.mjs.map +0 -1
  332. package/.output/server/chunks/build/permissions-CxEgXic0.mjs.map +0 -1
  333. package/.output/server/chunks/build/settings-BPBll_7K.mjs.map +0 -1
  334. package/.output/server/chunks/build/teams-DD8ZXTKL.mjs.map +0 -1
  335. package/.output/server/chunks/build/tokens-Dxnuw96_.mjs.map +0 -1
  336. package/.output/server/chunks/build/useDaqStream-DkRL3tEW.mjs.map +0 -1
  337. package/.output/server/chunks/build/useDcwStream-DyB2ufQI.mjs.map +0 -1
  338. package/.output/server/chunks/build/useSiteConfig-DJe_KMVr.mjs +0 -27
  339. package/.output/server/chunks/build/useSiteConfig-DJe_KMVr.mjs.map +0 -1
  340. package/.output/server/chunks/build/users-D6RNylrW.mjs.map +0 -1
  341. package/.output/server/chunks/build/workshop-CTcYDq2i.mjs.map +0 -1
  342. /package/.output/public/_nuxt/{CNs_Ozdc.js → CNs_Ozdc2.js} +0 -0
  343. /package/.output/public/_nuxt/{Cno6kYiO.js → Cno6kYiO2.js} +0 -0
  344. /package/.output/public/_nuxt/{ORt9oDIy2.js → ORt9oDIy.js} +0 -0
@@ -0,0 +1,52 @@
1
+ # 全站 UI 普查:登录后逐页截图,供美化前诊断(BASE/OUT/THEME 可参)
2
+ import os
3
+ import sys
4
+ from playwright.sync_api import sync_playwright
5
+
6
+ BASE = os.environ.get('BASE', 'http://127.0.0.1:3000')
7
+ OUT = os.environ.get('OUT', '.e2e-shots/survey')
8
+ PAGES = ['/', '/workshop', '/daq', '/dcw', '/logs', '/users', '/permissions', '/plugins', '/monitor', '/settings', '/tokens', '/town']
9
+
10
+ os.makedirs(OUT, exist_ok=True)
11
+ with sync_playwright() as p:
12
+ b = p.chromium.launch(headless=True)
13
+ pg = b.new_page(viewport={'width': 1600, 'height': 1000})
14
+ pg.set_default_timeout(30000)
15
+ pg.goto(BASE + '/workshop', wait_until='domcontentloaded', timeout=90000)
16
+ try:
17
+ pg.wait_for_selector('input[placeholder="邮箱 / 用户名"]', timeout=20000)
18
+ except Exception:
19
+ pg.goto(BASE + '/workshop', wait_until='domcontentloaded', timeout=60000)
20
+ pg.wait_for_selector('input[placeholder="邮箱 / 用户名"]', timeout=60000)
21
+ for attempt in range(3):
22
+ pg.wait_for_timeout(2500 + attempt * 2000)
23
+ pg.fill('input[placeholder="邮箱 / 用户名"]', 'admin')
24
+ pg.fill('.ant-input-password input', 'admin123')
25
+ try:
26
+ with pg.expect_response(lambda r: '/api/users/login' in r.url, timeout=15000):
27
+ pg.locator('.ant-input-password input').first.press('Enter')
28
+ except Exception:
29
+ pass
30
+ inp = pg.locator('input[placeholder="邮箱 / 用户名"]')
31
+ if inp.count() == 0 or not inp.first.is_visible():
32
+ break
33
+ print('logged in, theme:', pg.evaluate('document.documentElement.className'))
34
+
35
+ # 主题:dark 需要时点主题钮(runtime 插件可能按服务端设置强制 light)
36
+ want = os.environ.get('THEME', 'dark')
37
+ is_dark = 'dark' in (pg.evaluate('document.documentElement.className') or '')
38
+ if (want == 'dark') != is_dark:
39
+ btn = pg.locator('button.icon-btn', has=pg.locator('.i-tabler-sun-high, .i-tabler-moon-stars')).first
40
+ if btn.count():
41
+ btn.click()
42
+ pg.wait_for_timeout(1200)
43
+ print('toggled theme →', pg.evaluate('document.documentElement.className'))
44
+
45
+ for path in PAGES:
46
+ pg.goto(BASE + path, wait_until='domcontentloaded', timeout=60000)
47
+ pg.wait_for_timeout(3200)
48
+ name = path.strip('/').replace('/', '-') or 'home'
49
+ pg.screenshot(path=f'{OUT}/{name}.png')
50
+ print('shot', path)
51
+ b.close()
52
+ print('done →', OUT)
@@ -1,67 +1,189 @@
1
1
  /**
2
2
  * 合并器:把 i18n/dicts/<ns>.json(zh)+ i18n/dicts/_en.json(zh→en)
3
3
  * 注入 i18n/locales/zh-CN.ts 与 en.ts。
4
- * - ns 已存在 → 在其块首插入缺词条;否则新建 ns 块
5
- * - vue-i18n 特殊字符({}@$|)转义为字面量插值
4
+ * - dict 中的点号键('src.user'、'runtime.daq.x')展开为嵌套对象输出,
5
+ * 与 vue-i18n 的路径解析语义一致(resolveValue 按 '.' 分段逐层下钻)
6
+ * - ns 已存在 → 解析块内叶子路径,补插缺失键(整块重建,保持既有条目)
7
+ * - vue-i18n 特殊字符({}@$|)转义为字面量插值;{pN} 占位符保持原样
6
8
  * - en 缺失 → 回退 zh(报告计数)
9
+ * - 键风格:合法标识符用裸键,其余用单引号(项目 eslint singlequote 风格)
7
10
  */
8
11
  import fs from 'node:fs'
9
12
  import path from 'node:path'
10
13
 
11
14
  const esc = v => v
12
- // 保护 vue-i18n 占位符 {pN},其余 { } @ | $ 转义为字面量插值
13
- .replace(/\{(?!p\d+\})/g, '{\'{\'}')
14
- .replace(/([@$|])/g, '{\'$1\'}')
15
+ .replace(/\{(?!p\d+\})/g, `{'{'}`)
16
+ .replace(/([@$|])/g, `{'$1'}`)
15
17
  const enMap = JSON.parse(fs.readFileSync('i18n/dicts/_en.json', 'utf-8'))
16
18
  let miss = 0
19
+ const norm = s => s.replace(/\s+/g, ' ').trim()
17
20
 
18
- function buildEntries(ns, dict, isEn) {
19
- const out = []
21
+ function valueFor(zh, isEn) {
22
+ if (!isEn) return zh
23
+ const hit = enMap[norm(zh)] ?? enMap[zh]
24
+ if (hit == null) {
25
+ miss++
26
+ return zh
27
+ }
28
+ return hit
29
+ }
30
+
31
+ function quoteKey(k) {
32
+ return /^[A-Za-z0-9_$]+$/.test(k) ? k : `'${k.replace(/\\/g, '\\\\').replace(/'/g, '\\\'')}'`
33
+ }
34
+ function quoteVal(v) {
35
+ return `'${esc(v).replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/\r?\n/g, '\\n')}'`
36
+ }
37
+
38
+ // dict → 树:点号键展开为嵌套分组
39
+ function toTree(dict, isEn) {
40
+ const root = { entries: [], groups: new Map() }
20
41
  for (const [k, zh] of Object.entries(dict)) {
21
- let v = zh
22
- if (isEn) {
23
- const normalized = s => s.replace(/\s+/g, ' ').trim()
24
- const hit = enMap[normalized(zh)] ?? enMap[zh]
25
- if (hit == null) {
26
- miss++
27
- v = zh
42
+ const v = valueFor(zh, isEn)
43
+ const segs = k.split('.')
44
+ let node = root
45
+ for (let i = 0; i < segs.length - 1; i++) {
46
+ let g = node.groups.get(segs[i])
47
+ if (!g) {
48
+ g = { entries: [], groups: new Map() }
49
+ node.groups.set(segs[i], g)
28
50
  }
29
- else v = hit
51
+ node = g
52
+ }
53
+ // 同名键不重复插入;值在建树时统一引用化,emit 阶段只写原始字面量
54
+ if (!node.entries.some(e => e[0] === segs[segs.length - 1])) {
55
+ node.entries.push([segs[segs.length - 1], quoteVal(v)])
30
56
  }
31
- const keyLit = /^[A-Za-z0-9_$]+$/.test(k) ? k : JSON.stringify(k)
32
- out.push(` ${keyLit}: '${esc(v).replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/\r?\n/g, '\\n')}',`)
33
57
  }
58
+ return root
59
+ }
60
+
61
+ function emitTree(tree, indent) {
62
+ const pad = ' '.repeat(indent)
63
+ const lines = []
64
+ for (const [k, v] of tree.entries) lines.push(`${pad}${quoteKey(k)}: ${v},`)
65
+ for (const [k, g] of tree.groups) {
66
+ lines.push(`${pad}${quoteKey(k)}: {`)
67
+ lines.push(...emitTree(g, indent + 2))
68
+ lines.push(`${pad}},`)
69
+ }
70
+ return lines
71
+ }
72
+
73
+ // 解析既有 ns 块 → 有序树(值为已引用的原始字面量,保持原样)
74
+ // 返回 { tree, hadDottedEntry }:块内还存在扁平点号键时标记需重建
75
+ function parseBlockTree(lines) {
76
+ const mk = () => ({ entries: [], groups: new Map() })
77
+ const root = mk()
78
+ const stack = [{ indent: 0, node: root }]
79
+ let hadDottedEntry = false
80
+ for (const raw of lines) {
81
+ const indent = (raw.match(/^ */) || [''])[0].length - 4
82
+ const ln = raw.trim()
83
+ const closeM = ln.match(/^\},?$/)
84
+ if (closeM) {
85
+ while (stack.length > 1 && indent <= stack[stack.length - 1].indent) stack.pop()
86
+ continue
87
+ }
88
+ const openM = ln.match(/^(?:"([^"]+)"|'([^']+)'|([\w$]+)): \{$/)
89
+ const entryM = ln.match(/^(?:"([^"]+)"|'([^']+)'|([\w$]+)): (.*)$/)
90
+ if (openM) {
91
+ const name = openM[1] ?? openM[2] ?? openM[3]
92
+ let g = stack[stack.length - 1].node.groups.get(name)
93
+ if (!g) {
94
+ g = mk()
95
+ stack[stack.length - 1].node.groups.set(name, g)
96
+ }
97
+ stack.push({ indent, node: g })
98
+ }
99
+ else if (entryM) {
100
+ const name = entryM[1] ?? entryM[2] ?? entryM[3]
101
+ // 去掉行尾逗号,保留已引用的字面量原样
102
+ const val = entryM[4].replace(/,\s*$/, '')
103
+ const node = stack[stack.length - 1].node
104
+ if (name.includes('.')) {
105
+ // 旧版扁平点号键:展开为嵌套,记为重建信号
106
+ hadDottedEntry = true
107
+ const segs = name.split('.')
108
+ let cur = node
109
+ for (let i = 0; i < segs.length - 1; i++) {
110
+ let g = cur.groups.get(segs[i])
111
+ if (!g) {
112
+ g = mk()
113
+ cur.groups.set(segs[i], g)
114
+ }
115
+ cur = g
116
+ }
117
+ if (!cur.entries.some(e => e[0] === segs[segs.length - 1])) cur.entries.push([segs[segs.length - 1], val])
118
+ }
119
+ else {
120
+ if (!node.entries.some(e => e[0] === name)) node.entries.push([name, val])
121
+ }
122
+ }
123
+ }
124
+ return { tree: root, hadDottedEntry }
125
+ }
126
+
127
+ // 树的全部叶子路径
128
+ function treeLeaves(tree, prefix = '') {
129
+ const out = new Set()
130
+ for (const [k] of tree.entries) out.add(prefix ? `${prefix}.${k}` : k)
131
+ for (const [k, g] of tree.groups) for (const p of treeLeaves(g, prefix ? `${prefix}.${k}` : k)) out.add(p)
34
132
  return out
35
133
  }
36
134
 
135
+ // 合并 dict 树缺失叶子到既有树(两侧值均为已引用化字面量)
136
+ function mergeTree(existing, dictTree) {
137
+ let added = 0
138
+ for (const [k, v] of dictTree.entries) {
139
+ if (!existing.entries.some(e => e[0] === k)) {
140
+ existing.entries.push([k, v])
141
+ added++
142
+ }
143
+ }
144
+ for (const [k, g] of dictTree.groups) {
145
+ let sub = existing.groups.get(k)
146
+ if (!sub) {
147
+ sub = { entries: [], groups: new Map() }
148
+ existing.groups.set(k, sub)
149
+ }
150
+ added += mergeTree(sub, g)
151
+ }
152
+ return added
153
+ }
154
+
37
155
  for (const [localeFile, isEn] of [['i18n/locales/zh-CN.ts', false], ['i18n/locales/en.ts', true]]) {
38
156
  let src = fs.readFileSync(localeFile, 'utf-8')
39
157
  let insertedTotal = 0
40
158
  for (const f of fs.readdirSync('i18n/dicts').filter(x => x.endsWith('.json') && !x.startsWith('_'))) {
41
159
  const ns = f.replace('.json', '')
42
160
  const dict = JSON.parse(fs.readFileSync(path.join('i18n/dicts', f), 'utf-8'))
43
- const entries = buildEntries(ns, dict, isEn)
44
- if (entries.length === 0) continue
45
- const nsRe = new RegExp(`^ ${ns}: \\{`, 'm')
161
+ if (Object.keys(dict).length === 0) continue
162
+ const dictTree = toTree(dict, isEn)
163
+ const nsRe = new RegExp(`^ (?:${JSON.stringify(ns)}|'${ns}'|${ns}): \\{`, 'm')
46
164
  const m = src.match(nsRe)
47
165
  if (m) {
48
- // 已有 ns:块首插入尚不存在的键
166
+ // 已有 ns:解析块 → 检查叶子 → 有缺失或存在旧扁平点号键时整块重建
49
167
  const start = m.index + m[0].length
50
168
  const end = src.indexOf('\n },', start)
51
- const block = src.slice(start, end)
52
- // 键可能带引号(点号等非 \w 键由 emitter JSON.stringify 加引号)
53
- const fresh = entries.filter(e => !block.includes(e.match(/ {4}"?([\w.]+)"?:/)[1] + ':'))
54
- if (fresh.length) {
55
- src = src.slice(0, start) + '\n' + fresh.join('\n') + src.slice(start)
56
- insertedTotal += fresh.length
169
+ const blockLines = src.slice(start, end).split('\n').filter(l => l.trim() !== '')
170
+ const { tree: existingTree, hadDottedEntry } = parseBlockTree(blockLines)
171
+ const existingLeaves = treeLeaves(existingTree)
172
+ const wantLeaves = treeLeaves(dictTree)
173
+ const missing = [...wantLeaves].filter(l => !existingLeaves.has(l)).length
174
+ if (missing > 0 || hadDottedEntry) {
175
+ const added = mergeTree(existingTree, dictTree, isEn)
176
+ const rebuilt = [''].concat(emitTree(existingTree, 4))
177
+ src = src.slice(0, start) + rebuilt.join('\n') + src.slice(end)
178
+ insertedTotal += added
57
179
  }
58
180
  }
59
181
  else {
60
- // 新 ns:插到文件末尾闭合前
182
+ // 新 ns:插到文件末尾闭合前(ns 名非合法标识符时加引号,如 team-plugins)
61
183
  const tail = src.lastIndexOf('}')
62
- const block = ` ${ns}: {\n${entries.join('\n')}\n },\n`
184
+ const block = ` ${quoteKey(ns)}: {\n${emitTree(dictTree, 4).join('\n')}\n },\n`
63
185
  src = src.slice(0, tail) + block + src.slice(tail)
64
- insertedTotal += entries.length
186
+ insertedTotal += treeLeaves(dictTree).size
65
187
  }
66
188
  }
67
189
  fs.writeFileSync(localeFile, src)
@@ -0,0 +1,254 @@
1
+ /**
2
+ * 生产环境增强闭环 e2e — 数采/数控 × 自动诊断 × 知识沉淀(AgentWorkShop 3001 生产实例)
3
+ *
4
+ * 场景(对应「闭环控制增强」验收):
5
+ * A 生产就绪 3001 生产实例 + 两桥接插件启用 + 外部服务(KB/诊断/RAG)健康
6
+ * B 数采+绑定 产线节点可见、daq 绑定、daq_query/快照导出取到实时数据
7
+ * C 事件自动诊断 kv 配置越限规则 → daq:sample 命中 → 插件自动发起深度诊断(source=auto)
8
+ * → 关闭开关(避免持续触发);在跑诊断由轮询器继续跟踪
9
+ * D 知识辅助决策 kb_search 历史经验 → dcw_control 优化设定(HITL 批准)→
10
+ * dcw_judge 落 keep 判定 → kb_store 优化方案入库 → kb_search 复核
11
+ * E 沉淀验证 rag-bridge /experience 与 two-stage 检索确认知识可查
12
+ *
13
+ * 运行:AW_BASE=http://localhost:3001 node scripts/production-closed-loop-e2e.mjs
14
+ * 前置:scripts/three-system-e2e.mjs 已跑过(演示账号/团队/绑定/授权已就绪)。
15
+ */
16
+ import { DatabaseSync } from 'node:sqlite'
17
+ import { readFileSync, writeFileSync, renameSync } from 'node:fs'
18
+ import { fileURLToPath } from 'node:url'
19
+ import { dirname, join, resolve } from 'node:path'
20
+
21
+ const __dirname = dirname(fileURLToPath(import.meta.url))
22
+ const ROOT = resolve(__dirname, '..')
23
+ const BASE = process.env.AW_BASE ?? 'http://localhost:3001'
24
+ const KB = process.env.KB_BASE ?? 'http://127.0.0.1:8770'
25
+ const DIAG = process.env.DIAG_BASE ?? 'http://127.0.0.1:3210'
26
+ const LINE = process.env.E2E_LINE ?? 'ln-af002514'
27
+ const DCW_NODE = process.env.E2E_DCW_NODE ?? 'dw-e92bb0e7'
28
+
29
+ let pass = 0
30
+ let fail = 0
31
+ const failures = []
32
+ function ok(cond, label, detail = '') {
33
+ if (cond) {
34
+ pass++
35
+ console.log(` ✔ ${label}${detail ? ` —— ${detail}` : ''}`)
36
+ }
37
+ else {
38
+ fail++
39
+ failures.push(label)
40
+ console.error(` ✘ ${label}${detail ? ` —— ${detail}` : ''}`)
41
+ }
42
+ }
43
+ const sleep = ms => new Promise(r => setTimeout(r, ms))
44
+
45
+ async function raw(method, url, { body, token, agent, timeoutMs = 20000 } = {}) {
46
+ const headers = {}
47
+ if (body !== undefined) headers['content-type'] = 'application/json'
48
+ if (token) headers.authorization = `Bearer ${token}`
49
+ if (agent) headers['x-aw-agent-token'] = agent.token
50
+ const res = await fetch(url, { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined, signal: AbortSignal.timeout(timeoutMs) })
51
+ return { status: res.status, json: await res.json().catch(() => null) }
52
+ }
53
+ const api = (method, path, opts = {}) => raw(method, `${BASE}${path}`, opts)
54
+ const resultText = r => String(r?.json?.data?.result?.text ?? '')
55
+ const invoke = (agent, tool, args, timeoutMs = 60000) => api('POST', '/api/workshop/agent-tools/invoke', { agent, timeoutMs, body: { agentId: agent.id, tool, args } })
56
+
57
+ // ── 0. 演示账号/团队(复用 three-system-e2e 的持久化状态)─────────────────
58
+ const tokenFile = join(ROOT, '.AgentWorkShop', 'data', '.three-system-e2e-token.json')
59
+ const saved = JSON.parse(readFileSync(tokenFile, 'utf8'))
60
+ const userToken = process.env.AW_E2E_TOKEN ?? saved.token
61
+ const userId = saved.uid ?? ''
62
+ ok(Boolean(userToken), '复用演示账号 token')
63
+ // 夹具:确保产线 operate 授权(users.sqlite 直插,测试专用)
64
+ {
65
+ const db = new DatabaseSync(join(ROOT, '.AgentWorkShop', 'data', 'users.sqlite'))
66
+ db.exec('PRAGMA busy_timeout=4000')
67
+ const row = userId ? { id: userId } : db.prepare('SELECT id FROM users ORDER BY created_at DESC LIMIT 1').get()
68
+ if (row?.id) {
69
+ db.prepare(`INSERT OR REPLACE INTO user_line_grants (user_id, line_id, mode, granted_by, granted_at) VALUES (?, ?, 'operate', 'production-e2e', ?)`).run(row.id, LINE, new Date().toISOString())
70
+ console.log(` · 产线授权夹具就绪(user=${row.id})`)
71
+ }
72
+ db.close()
73
+ }
74
+ const chsRaw = await api('GET', '/api/workshop/channels', { token: userToken }).catch(() => null)
75
+ const chs = Array.isArray(chsRaw?.json?.data) ? chsRaw.json.data : []
76
+ const chA = chs.find(c => c?.name?.startsWith('产线数据分析组'))
77
+ const chB = chs.find(c => c?.name?.startsWith('闭环控制组'))
78
+ const membersOf = async id => (await api('GET', `/api/workshop/channels/${id}/agents`, { token: userToken })).json?.data ?? []
79
+ const mA = await membersOf(chA.id)
80
+ const mB = await membersOf(chB.id)
81
+ const execA = mA.find(m => m?.name === '数据分析执行器')
82
+ const execB = mB.find(m => m?.name === '控制执行器')
83
+ ok(Boolean(execA?.token && execB?.token), '两个 omp 执行器就绪', `${execA?.name} / ${execB?.name}`)
84
+
85
+ // ══ Stage A:生产就绪 ══════════════════════════════════════════════════════
86
+ console.log('\n── Stage A 生产就绪(3001)──')
87
+ {
88
+ const gate = await raw('GET', `${BASE}/api/workshop/plugins`)
89
+ ok(gate.status === 401, '生产实例存活(无 token 401 信封)', `status=${gate.status}`)
90
+ const plugs = await api('GET', '/api/workshop/plugins', { token: userToken })
91
+ const list = plugs.json?.plugins ?? plugs.json?.data?.plugins ?? []
92
+ const on = n => list.find(p => p?.name === n)?.enabled === true
93
+ ok(on('rag-bridge') && on('diag-bridge'), '两桥接插件在生产实例启用', `count=${list.length}`)
94
+ const ragH = await api('GET', '/api/plugins/rag-bridge/health', { token: userToken })
95
+ ok(ragH.status === 200 && ragH.json?.outbound === true, 'rag-bridge 健康', `kb=${ragH.json?.kb?.id?.slice(0, 8)}`)
96
+ const diagH = await api('GET', '/api/plugins/diag-bridge/health', { token: userToken })
97
+ ok(diagH.status === 200 && diagH.json?.remote?.status === 'ok', 'diag-bridge 健康', `activeRuns=${diagH.json?.remote?.activeRuns}`)
98
+ const kbH = await raw('GET', `${KB}/api/v1/health`)
99
+ const dgH = await raw('GET', `${DIAG}/api/health`)
100
+ ok(kbH.json?.status === 'healthy' && dgH.json?.status === 'ok', 'KB 8770 / 诊断 3210 外部服务健康')
101
+ }
102
+
103
+ // ══ Stage B:数采 + 绑定 ════════════════════════════════════════════════════
104
+ console.log('\n── Stage B 数采与绑定 ──')
105
+ let freshNode = ''
106
+ {
107
+ const daq = await api('GET', '/api/workshop/daq', { token: userToken })
108
+ const nodes = (daq.json?.data?.nodes ?? daq.json?.nodes ?? []).filter(n => n?.lineId === LINE)
109
+ ok(nodes.length > 0, `产线 ${LINE} 数采节点可见`, `count=${nodes.length}`)
110
+ // 选最近有样本的节点(逐节点探 60min 窗)
111
+ let bestAt = 0
112
+ for (const n of nodes.slice(0, 12)) {
113
+ const s = await api('GET', `/api/workshop/daq/${n.id}/samples?last_minutes=60&limit=1`, { token: userToken }).catch(() => null)
114
+ const at = s?.json?.data?.points?.[0]?.at ?? 0
115
+ if (at > bestAt) {
116
+ bestAt = at
117
+ freshNode = n.id
118
+ }
119
+ }
120
+ ok(Boolean(freshNode), '定位最近在采样的节点', `${freshNode} (lastAt=${bestAt ? new Date(bestAt).toISOString() : 'n/a'})`)
121
+
122
+ const bind = await api('POST', '/api/workshop/agent-tools/bindings', {
123
+ token: userToken,
124
+ body: { agentId: execA.id, nodeId: freshNode, kind: 'daq', mode: 'auto' },
125
+ })
126
+ ok(bind.status === 200, '分析执行器绑定数采节点(daq)', bind.status === 200 ? 'ok' : JSON.stringify(bind.json).slice(0, 120))
127
+
128
+ const snap = await api('POST', '/api/plugins/diag-bridge/snapshot', {
129
+ token: userToken,
130
+ body: { line: LINE, from_ms: Date.now() - 24 * 60 * 60_000, to_ms: Date.now() },
131
+ })
132
+ ok(snap.json?.success === true && snap.json?.rows > 0, '生产实例导出 DAQ 宽表快照', `rows=${snap.json?.rows} nodes=${snap.json?.nodes}`)
133
+ }
134
+
135
+ // ══ Stage C:事件自动诊断(daq:sample → 自动 diag_run)══════════════════════
136
+ console.log('\n── Stage C 事件驱动自动诊断 ──')
137
+ let autoRunId = ''
138
+ {
139
+ const kvPath = join(ROOT, '.AgentWorkShop', 'data', 'plugins', 'diag-bridge', 'kv.json')
140
+ const statePath = join(process.env.USERPROFILE ?? process.env.HOME ?? '', '.AgentWorkShop', 'plugins-state.json')
141
+ const touchReload = () => {
142
+ const st = JSON.parse(readFileSync(statePath, 'utf8'))
143
+ st.updatedAt = new Date().toISOString()
144
+ writeFileSync(`${statePath}.tmp`, JSON.stringify(st, null, 2))
145
+ renameSync(`${statePath}.tmp`, statePath)
146
+ }
147
+ const kv = JSON.parse(readFileSync(kvPath, 'utf8'))
148
+ kv.auto_diag_enabled = 'true'
149
+ kv.auto_rules = JSON.stringify({ [freshNode]: { op: 'gt', value: 0 } }) // 阈值 0 → 下一拍样本必命中(确定性触发)
150
+ writeFileSync(kvPath, JSON.stringify(kv, null, 2))
151
+ touchReload()
152
+ console.log(' · 已启用 auto_diag(规则:节点 ' + freshNode + ' > 0)并触发热重载')
153
+
154
+ for (let i = 0; i < 24 && !autoRunId; i++) {
155
+ await sleep(5000)
156
+ const runs = await api('GET', '/api/plugins/diag-bridge/runs', { token: userToken })
157
+ const hit = (runs.json?.runs ?? []).find(x => x.source === 'auto' && x.status === 'running' && !x.runId?.startsWith('f2ce66b4'))
158
+ if (hit) autoRunId = hit.runId
159
+ }
160
+ ok(Boolean(autoRunId), 'daq:sample 越限命中 → 插件自动发起深度诊断(source=auto)', `runId=${autoRunId}`)
161
+
162
+ // 关闭开关(避免持续触发);在跑诊断由轮询器重水化继续跟踪
163
+ const kv2 = JSON.parse(readFileSync(kvPath, 'utf8'))
164
+ kv2.auto_diag_enabled = 'false'
165
+ writeFileSync(kvPath, JSON.stringify(kv2, null, 2))
166
+ touchReload()
167
+ console.log(' · auto_diag 已关闭(冷却+去重仍在,防重复触发)')
168
+ const runs2 = await api('GET', '/api/plugins/diag-bridge/runs', { token: userToken })
169
+ const still = (runs2.json?.runs ?? []).find(x => x.runId === autoRunId)
170
+ ok(still?.status === 'running' || still?.status === 'completed', '热重载后轮询器重水化,自动诊断仍被跟踪', still?.status)
171
+ }
172
+
173
+ // ══ Stage D:知识辅助决策 + 优化闭环 + 方案入库 ═════════════════════════════
174
+ console.log('\n── Stage D 知识辅助决策与优化闭环 ──')
175
+ {
176
+ const hist = await invoke(execA, 'kb_search', { query: '压力设定器 优化 经验 判定 keep' })
177
+ ok(resultText(hist).startsWith('检索到'), '知识辅助:检索到历史经验/文档', resultText(hist).split('\n')[0].slice(0, 80))
178
+
179
+ const dcwView = await api('GET', '/api/workshop/dcw', { token: userToken })
180
+ const node = (dcwView.json?.data?.nodes ?? []).find(n => n?.id === DCW_NODE)
181
+ ok(Boolean(node), '数控节点可见', `value=${node?.value} range=${node?.min}~${node?.max}`)
182
+ const span = Number(node?.max) - Number(node?.min)
183
+ const step = span > 0 ? Math.min(span * 0.03, 1) : 0.05
184
+ let target = Number(node?.value) + step
185
+ if (target > Number(node?.max) - span * 0.05) target = Number(node?.value) - step
186
+
187
+ // 发起写控(manual → HITL 挂起),脚本扮演人类在待办出现后批准
188
+ const pendingInvoke = invoke(execB, 'dcw_control', {
189
+ node_id: DCW_NODE,
190
+ value: Number(target.toFixed(4)),
191
+ hypothesis: `依据知识库历史经验(${resultText(hist).split('\n')[1]?.slice(0, 60) ?? '历史经验'})与数采趋势,优化设定至 ${target.toFixed(4)}`,
192
+ }, 300000)
193
+ let approved = false
194
+ let pendRaw = '[]'
195
+ for (let i = 0; i < 30 && !approved; i++) {
196
+ await sleep(2000)
197
+ const pend = await api('GET', '/api/workshop/hitl/pending', { token: userToken })
198
+ const pd = pend?.json?.data
199
+ const arr = Array.isArray(pd) ? pd : (pd?.items ?? pd?.pending ?? [])
200
+ pendRaw = JSON.stringify(arr)
201
+ const item = arr.find(x => x?.kind === 'dcw-approval' && x?.agentId === execB.id)
202
+ if (item?.id) {
203
+ const resp = await api('POST', '/api/workshop/hitl/respond', {
204
+ token: userToken,
205
+ body: { kind: 'dcw-approval', id: item.id, confirmed: true, comment: 'production-e2e 批准' },
206
+ })
207
+ approved = resp.status === 200
208
+ }
209
+ }
210
+ const w = await pendingInvoke
211
+ const wText = resultText(w)
212
+ ok(approved, 'HITL 待办出现并经 respond 批准', approved ? 'ok' : `pending=${pendRaw.slice(0, 160)}`)
213
+ ok(wText.includes('下发成功'), '优化设定经 HITL 批准并写回成功', wText.split('\n')[0].slice(0, 110))
214
+ const recordId = (wText.match(/优化记录 (\S+) 已开窗/) ?? [])[1] ?? ''
215
+
216
+ if (recordId) {
217
+ const j = await invoke(execB, 'dcw_judge', {
218
+ record_id: recordId,
219
+ verdict: 'keep',
220
+ reason: `写入后 ${freshNode} 数采回读与设定一致、无越配方告警,判定 keep(production-e2e)`,
221
+ })
222
+ ok(resultText(j).includes('keep') || !resultText(j).includes('失败'), 'dcw_judge 落 keep 判定(经验固化)', resultText(j).split('\n')[0].slice(0, 100))
223
+
224
+ const store = await invoke(execA, 'kb_store', {
225
+ title: `优化方案:压力设定器 ${node?.value}→${target.toFixed(4)}(判定 keep)`,
226
+ category: 'optimization',
227
+ problem: '压力设定偏离经验最优区,需要在不触发越限的前提下上调设定',
228
+ solution: `按配方窗口内 ${step.toFixed(4)} 步进上调;写入后观察 ${freshNode} 回读稳定,dcw_judge=keep(记录 ${recordId}),可标 lastGood`,
229
+ key_lessons: ['小步进+回读确认再判定', 'keep 判定须引用数采证据'],
230
+ tags: [LINE, '闭环优化', `record:${recordId}`, 'production-e2e'],
231
+ })
232
+ ok(resultText(store).includes('已沉淀'), '优化方案写入知识库(经验沉淀)', resultText(store).slice(0, 90))
233
+ }
234
+
235
+ const s2 = await invoke(execA, 'kb_search', { query: `压力设定器 优化方案 keep ${LINE}` })
236
+ ok(resultText(s2).startsWith('检索到'), 'kb_search 复核:优化方案可检索', resultText(s2).split('\n')[1]?.slice(0, 100) ?? resultText(s2).slice(0, 100))
237
+ }
238
+
239
+ // ══ Stage E:沉淀验证 ══════════════════════════════════════════════════════
240
+ console.log('\n── Stage E 知识沉淀验证 ──')
241
+ {
242
+ const exp = await api('GET', '/api/plugins/rag-bridge/experience?limit=50', { token: userToken })
243
+ const count = exp.json?.count ?? 0
244
+ const hasOpt = JSON.stringify(exp.json?.experiences ?? []).includes('optimization')
245
+ ok(count > 0, '经验库可读', `count=${count}`)
246
+ ok(hasOpt, '经验库含 optimization 类目(优化方案在册)')
247
+
248
+ const s3 = await api('GET', `/api/plugins/rag-bridge/search?q=${encodeURIComponent('闭环优化 设定 判定')}&top_k=3`, { token: userToken })
249
+ ok(s3.json?.success === true && (s3.json?.results?.length ?? 0) > 0, 'two-stage 检索命中闭环优化知识', `results=${s3.json?.results?.length}`)
250
+ }
251
+
252
+ console.log(`\n══ 生产增强闭环结果:${pass} 通过 / ${fail} 失败 ══`)
253
+ if (failures.length) for (const f of failures) console.error(` - ${f}`)
254
+ process.exit(fail > 0 ? 1 : 0)