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,556 @@
1
+ /**
2
+ * diag-bridge —— industrial-deep-diagnostic 深度诊断服务桥接插件。
3
+ *
4
+ * 把诊断服务(http://127.0.0.1:3210)接入 AgentWorkShop:导出 DAQ 时序快照 CSV →
5
+ * 上传并发起深度诊断 → 轮询状态 → 完成后报告自动入知识库(文档/索引/经验三步)。
6
+ * 工具对 lead/worker 全体 agent 生效;3210 不可达时一律 isError 文本,绝不抛异常。
7
+ */
8
+ const MIN = 60 * 1000
9
+ const DEFAULT_BASE = 'http://127.0.0.1:3210'
10
+ const SNAPSHOT_BUCKET_MS = 5000 // 快照降采样桶宽
11
+ const SNAPSHOT_LIMIT = 10000 // 与 ctx.daq.query limit 一致(截断断言阈值)
12
+ const UPLOAD_FOLDER = 'aw-snapshots'
13
+ const AUTO_COOLDOWN_MS = 30 * MIN // 自动诊断同产线冷却
14
+
15
+ /** 每产线「启动中」互斥(进程内同步集合,堵住 kv 检查与远端落库之间的并发窗口) */
16
+ const startingLines = new Set()
17
+
18
+ // ── 基础工具 ──────────────────────────────────────────────────────────────
19
+
20
+ /** 诊断服务 base(kv diag.base_url;只允许 http/https 且 host 为 127.0.0.1/localhost) */
21
+ function baseOf(ctx) {
22
+ const raw = String(ctx.config?.get?.('plugins.diag.base_url') || ctx.kv.get('diag.base_url') || DEFAULT_BASE).trim()
23
+ try {
24
+ const u = new URL(raw)
25
+ const okProto = u.protocol === 'http:' || u.protocol === 'https:'
26
+ const okHost = u.hostname === '127.0.0.1' || u.hostname === 'localhost'
27
+ if (!okProto || !okHost) return null
28
+ return raw.replace(/\/+$/, '')
29
+ }
30
+ catch {
31
+ return null
32
+ }
33
+ }
34
+
35
+ const runKey = id => `run:${id}`
36
+
37
+ /** kv 中全部 run 记录 → [{ id, meta }] */
38
+ function kvRuns(ctx) {
39
+ const out = []
40
+ for (const [k, v] of Object.entries(ctx.kv.all())) {
41
+ if (k.startsWith('run:') && v && typeof v === 'object') out.push({ id: k.slice(4), meta: v })
42
+ }
43
+ return out
44
+ }
45
+
46
+ /** 该产线是否有运行中的诊断 */
47
+ function runningOfLine(ctx, line) {
48
+ return kvRuns(ctx).find(r => r.meta?.status === 'running' && r.meta?.line === line) ?? null
49
+ }
50
+
51
+ /** 短 JSON 摘要(错误信息用) */
52
+ function short(body) {
53
+ try {
54
+ return JSON.stringify(body).slice(0, 200)
55
+ }
56
+ catch {
57
+ return String(body)
58
+ }
59
+ }
60
+
61
+ /** JSON GET:断言 HTTP ok 且 body.success===true,返回 body */
62
+ async function jget(ctx, url, timeoutMs = 8000) {
63
+ const res = await ctx.http.get(url, { timeoutMs })
64
+ const body = await res.json().catch(() => null)
65
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${short(body)}`)
66
+ if (!body || body.success !== true) throw new Error(`success!=true ${short(body)}`)
67
+ return body
68
+ }
69
+
70
+ /** JSON POST:断言 HTTP ok 且 body.success===true,返回 body */
71
+ async function jpost(ctx, url, body, timeoutMs = 15000) {
72
+ const res = await ctx.http.post(url, body, { timeoutMs })
73
+ const out = await res.json().catch(() => null)
74
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${short(out)}`)
75
+ if (!out || out.success !== true) throw new Error(`success!=true ${short(out)}`)
76
+ return out
77
+ }
78
+
79
+ /** 解析 auto_rules(kv 存 JSON 字符串 {nodeId:{op:'gt'|'lt',value}}) */
80
+ function parseAutoRules(raw) {
81
+ if (!raw) return {}
82
+ try {
83
+ const obj = typeof raw === 'string' ? JSON.parse(raw) : raw
84
+ return obj && typeof obj === 'object' ? obj : {}
85
+ }
86
+ catch {
87
+ return {}
88
+ }
89
+ }
90
+
91
+ /** CSV 单元格转义(含逗号/引号/换行时加引号) */
92
+ function csvCell(v) {
93
+ const s = String(v)
94
+ return /[",\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s
95
+ }
96
+
97
+ /** 数值格式化(保留 6 位小数,去尾零;非有限值 → 空) */
98
+ function fmtNum(v) {
99
+ if (typeof v !== 'number' || !Number.isFinite(v)) return ''
100
+ return String(Math.round(v * 1e6) / 1e6)
101
+ }
102
+
103
+ /** 快照文件名(ASCII 安全,避免 multipart filename 编码问题) */
104
+ function safeName(line, toMs) {
105
+ const s = String(line).replace(/[^A-Za-z0-9._-]+/g, '_').replace(/^_+|_+$/g, '').slice(0, 40) || 'line'
106
+ return `snap-${s}-${toMs}.csv`
107
+ }
108
+
109
+ // ── 快照导出器 ───────────────────────────────────────────────────────────
110
+
111
+ /**
112
+ * 导出产线时窗快照:daq 节点过滤 → 时序查询 → 时间戳 pivot → CSV → multipart 上传。
113
+ * 成功返回 { ok:true, csvPath, rows, nodes, fromMs, toMs };失败返回 { ok:false, error }。
114
+ */
115
+ async function snapshotCore(ctx, line, fromMs, toMs) {
116
+ if (!ctx.daq || typeof ctx.daq.nodes !== 'function' || typeof ctx.daq.query !== 'function') {
117
+ return { ok: false, error: '平台 ctx.daq 扩展未就绪(需宿主提供 daq.nodes / daq.query)。' }
118
+ }
119
+ // 1) 产线节点过滤(节点产线归属字段为 lineId,daq-node.repo snapshot 同构)
120
+ const all = await ctx.daq.nodes()
121
+ const lineNodes = (Array.isArray(all) ? all : []).filter(n => n && n.lineId === line)
122
+ if (!lineNodes.length) return { ok: false, error: `产线 ${line} 下无数采节点。` }
123
+
124
+ // 2) 时序查询(bucket 点含 {at,avg,min,max,cnt},raw 点含 {at,value});
125
+ // 打标查询空窗(LineRun 未开跑/空闲段样本无 line_id)时降级为按节点查询
126
+ let map = await ctx.daq.query({
127
+ lineId: line,
128
+ nodeIds: lineNodes.map(n => n.id),
129
+ fromMs,
130
+ toMs,
131
+ bucketMs: SNAPSHOT_BUCKET_MS,
132
+ limit: SNAPSHOT_LIMIT,
133
+ })
134
+ if (!(map instanceof Map) || map.size === 0) {
135
+ map = await ctx.daq.query({
136
+ nodeIds: lineNodes.map(n => n.id),
137
+ fromMs,
138
+ toMs,
139
+ bucketMs: SNAPSHOT_BUCKET_MS,
140
+ limit: SNAPSHOT_LIMIT,
141
+ })
142
+ }
143
+
144
+ // 3) pivot:收集全部时间戳排序去重;行=时间戳,列=每节点(bucket 取 avg,raw 取 value)
145
+ const tsSet = new Set()
146
+ const perNode = new Map() // nodeId → Map(at → value)
147
+ for (const [nodeId, points] of (map instanceof Map ? map : [])) {
148
+ if (!Array.isArray(points)) continue
149
+ const m = new Map()
150
+ for (const p of points) {
151
+ if (!p || typeof p.at !== 'number') continue
152
+ const v = typeof p.avg === 'number' ? p.avg : (typeof p.value === 'number' ? p.value : null)
153
+ if (v == null) continue
154
+ m.set(p.at, v)
155
+ tsSet.add(p.at)
156
+ }
157
+ if (m.size) perNode.set(nodeId, m)
158
+ }
159
+ const stamps = [...tsSet].sort((a, b) => a - b)
160
+ if (!stamps.length) return { ok: false, error: `产线 ${line} 在该时窗内无数采样本,请调整时间窗口。` }
161
+ if (stamps.length >= SNAPSHOT_LIMIT) {
162
+ return { ok: false, error: `唯一时间戳数(${stamps.length})≥ 上限 ${SNAPSHOT_LIMIT},数据可能被 limit 截断,请缩小时间窗口后重试。` }
163
+ }
164
+
165
+ // 4) 组 CSV(timestamp 用平台本地时区 ISO;缺值留空)
166
+ const cols = lineNodes.map(n => n.id)
167
+ const rowsCsv = ['timestamp,' + cols.map(csvCell).join(',')]
168
+ for (const ts of stamps) {
169
+ const row = [new Date(ts).toISOString()]
170
+ for (const id of cols) row.push(fmtNum(perNode.get(id)?.get(ts)))
171
+ rowsCsv.push(row.map(csvCell).join(','))
172
+ }
173
+ const csv = rowsCsv.join('\r\n')
174
+
175
+ // 5) 原生 fetch + AbortController(60s)multipart 上传(ctx.http 仅 JSON,传文件必须原生)
176
+ const base = baseOf(ctx)
177
+ if (!base) return { ok: false, error: 'diag.base_url 非法(仅允许 http/https 且 host 为 127.0.0.1/localhost)。' }
178
+ const ac = new AbortController()
179
+ const timer = setTimeout(() => ac.abort(), 60000)
180
+ try {
181
+ const fd = new FormData()
182
+ fd.append('folder', UPLOAD_FOLDER)
183
+ fd.append('files', new Blob([csv], { type: 'text/csv' }), safeName(line, toMs))
184
+ const res = await fetch(`${base}/api/files/data/upload`, { method: 'POST', body: fd, signal: ac.signal })
185
+ const body = await res.json().catch(() => null)
186
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${short(body)}`)
187
+ if (!body || body.success !== true) throw new Error(`success!=true ${short(body)}`)
188
+ const csvPath = String(body.data?.[0]?.path ?? '')
189
+ if (!csvPath) throw new Error('上传响应缺少 data[0].path')
190
+ return { ok: true, csvPath, rows: stamps.length, nodes: lineNodes.length, fromMs, toMs }
191
+ }
192
+ catch (err) {
193
+ return { ok: false, error: `快照上传失败: ${err?.message ?? err}` }
194
+ }
195
+ finally {
196
+ clearTimeout(timer)
197
+ }
198
+ }
199
+
200
+ // ── 发起诊断(快照 → start → execute → kv 登记;异步,绝不等待) ────────────
201
+
202
+ async function startDiagnosis(ctx, { line, fromMs, toMs, question, scene, source }) {
203
+ const base = baseOf(ctx)
204
+ if (!base) return { ok: false, error: 'diag.base_url 非法(仅允许 http/https 且 host 为 127.0.0.1/localhost)。' }
205
+ if (startingLines.has(line)) return { ok: false, error: `产线 ${line} 已有诊断正在启动,请稍后再试。` }
206
+ const existing = runningOfLine(ctx, line)
207
+ if (existing) return { ok: false, error: `产线 ${line} 已有运行中的诊断(run_id=${existing.id}),请稍后用 diag_status 查询。` }
208
+ startingLines.add(line)
209
+ try {
210
+ const snap = await snapshotCore(ctx, line, fromMs, toMs)
211
+ if (!snap.ok) return { ok: false, error: snap.error }
212
+ const q = question || `${line} 产线该时窗数据深度根因诊断`
213
+ const sceneName = scene || `${line}_diag`
214
+ const started = await jpost(ctx, `${base}/api/diagnosis/start`, {
215
+ dataPath: snap.csvPath,
216
+ sceneName,
217
+ userQuestion: q,
218
+ harness: String(ctx.kv.get('diag.harness') || 'omp'), // 缺省落 claude 引擎会因无 key 失败,必须显式
219
+ enhancement: 'off',
220
+ reportLanguage: 'zh',
221
+ maxTurns: Number(ctx.kv.get('diag.max_turns')) || 220, // 修复循环会加转数;150 不够走完全管线
222
+ timeoutMinutes: Number(ctx.kv.get('diag.max_minutes')) || 40,
223
+ })
224
+ const runId = String(started.data?.runId ?? '')
225
+ const name = String(started.data?.name ?? '')
226
+ if (!runId) return { ok: false, error: `start 响应缺少 data.runId: ${short(started)}` }
227
+ await jpost(ctx, `${base}/api/diagnosis/execute/${encodeURIComponent(runId)}`, {})
228
+ ctx.kv.set(runKey(runId), {
229
+ line, fromMs, toMs, question: q, scene: sceneName,
230
+ status: 'running', createdAt: Date.now(), source, csvPath: snap.csvPath, name,
231
+ })
232
+ return { ok: true, runId, name, csvPath: snap.csvPath, rows: snap.rows, nodes: snap.nodes }
233
+ }
234
+ catch (err) {
235
+ return { ok: false, error: `发起诊断失败: ${err?.message ?? err}` }
236
+ }
237
+ finally {
238
+ startingLines.delete(line)
239
+ }
240
+ }
241
+
242
+ // ── 入库管线(web 建文档 → backend 索引 → backend 经验;每步断言 success) ───
243
+
244
+ async function ingestCompleted(ctx, runId, meta, st) {
245
+ try {
246
+ // kv 按插件命名空间隔离:rag-bridge 建的库不在本插件 kv 里,需自行从 catalog 幂等解析
247
+ const webBase = String(ctx.config?.get?.('plugins.kb.web_url') || ctx.kv.get('kb.web_url') || 'http://127.0.0.1:6789').replace(/\/+$/, '')
248
+ let kbId = String(ctx.kv.get('kb.id') || '').trim()
249
+ if (!kbId) {
250
+ const cat = await ctx.http.get(`${webBase}/api/kb/catalog`, { timeoutMs: 15000 })
251
+ .then(r => r.json()).catch(() => null)
252
+ const hit = (Array.isArray(cat?.knowledgeBases) ? cat.knowledgeBases : [])
253
+ .find(kb => kb?.name === 'aw-industrial')
254
+ if (hit?.kbId) {
255
+ ctx.kv.set('kb.id', String(hit.kbId))
256
+ kbId = String(hit.kbId)
257
+ }
258
+ }
259
+ if (!kbId) {
260
+ ctx.logger.warn(`诊断 ${runId} 已完成但找不到知识库 aw-industrial(rag-bridge 未初始化?),跳过入库`)
261
+ return
262
+ }
263
+ const base = baseOf(ctx)
264
+ const runName = String(st.name || meta.name || '')
265
+ if (!base || !runName) throw new Error(`缺少诊断服务 base 或 run name(${runName})`)
266
+
267
+ // 1) 报告全文。报告端点按「目录名」索引(时间戳_scene),而 status.name 是显示名
268
+ // (scene_runId)——优先用 report_path 反推目录名,缺失时回退显示名。
269
+ const rp = String(st.report_path || meta.reportPath || '')
270
+ const repDir = rp.split(/[\\/]/).filter(Boolean).slice(-2, -1)[0] || runName
271
+ const rep = await jget(ctx, `${base}/api/files/workspace/report/${encodeURIComponent(repDir)}`, 10000)
272
+ const content = String(rep.data?.content ?? '')
273
+ if (!content) throw new Error('报告内容为空')
274
+
275
+ const apiBase = String(ctx.config?.get?.('plugins.kb.base_url') || ctx.kv.get('kb.base_url') || 'http://127.0.0.1:8770').replace(/\/+$/, '')
276
+
277
+ // 2) web 建文档(响应 {success, document:{path,…}},path 供索引用)
278
+ const doc = await jpost(ctx, `${webBase}/api/kb/documents/create`, { kbId, name: `${runName}.md`, content }, 15000)
279
+ const docPath = String(doc.document?.path ?? '')
280
+ if (!docPath) throw new Error(`documents/create 响应缺少 document.path: ${short(doc)}`)
281
+
282
+ // 3) backend 向量/图谱索引
283
+ await jpost(ctx, `${apiBase}/api/v1/search/index-document`, {
284
+ kb_id: kbId,
285
+ doc_path: docPath,
286
+ content,
287
+ tags: [meta.line, '诊断', 'source:diag-bridge'].filter(Boolean),
288
+ }, 30000)
289
+
290
+ // 4) backend 经验沉淀
291
+ const q = String(meta.question || '')
292
+ await jpost(ctx, `${apiBase}/api/v1/experience/${encodeURIComponent(kbId)}`, {
293
+ title: `诊断:${q ? q.slice(0, 50) : runName}`,
294
+ category: 'troubleshooting',
295
+ problem: q,
296
+ solution: content.slice(0, 800),
297
+ result: 'success',
298
+ tags: [meta.line, meta.scene].filter(Boolean),
299
+ }, 30000)
300
+
301
+ ctx.kv.set(runKey(runId), { ...ctx.kv.get(runKey(runId)), stored: true, storedAt: Date.now() })
302
+ ctx.logger.info(`诊断 ${runId}(产线 ${meta.line})报告已入库: ${docPath}`)
303
+ }
304
+ catch (err) {
305
+ ctx.logger.warn(`诊断 ${runId} 入库失败(不重试): ${err?.message ?? err}`)
306
+ }
307
+ }
308
+
309
+ // ── 轮询器:15s 扫描 kv 中 running 的 run → 更新状态 → 完成则入库 ──────────
310
+
311
+ async function sweepOnce(ctx) {
312
+ // running:常规轮询;completed 未入库:30 分钟内重试入库(入库管线曾失败时自愈)
313
+ const running = kvRuns(ctx).filter(r =>
314
+ r.meta?.status === 'running'
315
+ || (r.meta?.status === 'completed' && r.meta?.stored !== true
316
+ && Date.now() - (r.meta?.completedAt ?? 0) < 120 * MIN))
317
+ if (!running.length) return
318
+ const base = baseOf(ctx)
319
+ if (!base) {
320
+ ctx.logger.warn('diag.base_url 非法,本轮跳过诊断轮询')
321
+ return
322
+ }
323
+ for (const { id, meta } of running) {
324
+ try {
325
+ const st = (await jget(ctx, `${base}/api/diagnosis/status/${encodeURIComponent(id)}`, 8000)).data ?? {}
326
+ const status = st.engineStatus || st.status || meta.status
327
+ if (status === 'completed') {
328
+ ctx.kv.set(runKey(id), {
329
+ ...meta,
330
+ status: 'completed',
331
+ completedAt: meta.completedAt ?? Date.now(), // 重试路径不续期,保证重试窗口会收敛
332
+ name: st.name ?? meta.name,
333
+ score: st.score ?? null,
334
+ verdict: st.judge_verdict ?? null,
335
+ reportPath: st.report_path ?? null,
336
+ })
337
+ // 入库为独立异步管线,失败仅 warn,不影响轮询(未入库的下轮重试)
338
+ if (ctx.kv.get(runKey(id))?.stored !== true) {
339
+ ingestCompleted(ctx, id, ctx.kv.get(runKey(id)), st).catch(() => {})
340
+ }
341
+ }
342
+ else if (status === 'failed' || status === 'stopped') {
343
+ ctx.kv.set(runKey(id), {
344
+ ...meta,
345
+ status,
346
+ completedAt: Date.now(),
347
+ name: st.name ?? meta.name,
348
+ error: st.error_message ?? null,
349
+ })
350
+ ctx.logger.warn(`诊断 ${id}(产线 ${meta.line})结束: ${status}${st.error_message ? `(${st.error_message})` : ''}`)
351
+ }
352
+ else if (status !== meta.status) {
353
+ ctx.kv.set(runKey(id), { ...meta, status, name: st.name ?? meta.name })
354
+ }
355
+ }
356
+ catch (err) {
357
+ ctx.logger.warn(`轮询诊断 ${id} 失败(下轮继续): ${err?.message ?? err}`)
358
+ }
359
+ }
360
+ }
361
+
362
+ // ── 插件入口 ─────────────────────────────────────────────────────────────
363
+
364
+ export default {
365
+ name: 'diag-bridge',
366
+ version: '1.0.0',
367
+ description: '深度诊断桥接:导出 DAQ 时序快照 CSV,发起 industrial-deep-diagnostic 深度诊断并跟踪状态,完成后报告自动入知识库。',
368
+ auth: 'user',
369
+ setup(ctx) {
370
+ // 轮询器(15s)+ setup 重水化:恢复对 kv 中 running run 的跟踪(热重载安全)
371
+ const sweep = () => sweepOnce(ctx).catch(err => ctx.logger.warn(`诊断轮询异常(继续): ${err?.message ?? err}`))
372
+ ctx.timer.setInterval(sweep, 15000)
373
+ sweep()
374
+
375
+ // 自动诊断(默认关):daq:sample 命中规则 → 冷却 30min → 同管线发起(source:'auto')
376
+ ctx.hooks.on('daq:sample', (s) => {
377
+ try {
378
+ if (ctx.kv.get('auto_diag_enabled') !== 'true') return
379
+ if (!s || typeof s.value !== 'number' || !s.nodeId || !s.lineId) return
380
+ const rule = parseAutoRules(ctx.kv.get('auto_rules'))[s.nodeId]
381
+ if (!rule || typeof rule?.value !== 'number' || !['gt', 'lt'].includes(rule.op)) return
382
+ const hit = rule.op === 'lt' ? s.value < rule.value : s.value > rule.value
383
+ if (!hit) return
384
+ const line = s.lineId
385
+ const last = Number(ctx.kv.get(`cooldown:${line}`)) || 0
386
+ if (Date.now() - last < AUTO_COOLDOWN_MS) return
387
+ const now = Date.now()
388
+ ctx.kv.set(`cooldown:${line}`, now) // 先占冷却,防同窗连发
389
+ startDiagnosis(ctx, {
390
+ line,
391
+ fromMs: now - 60 * MIN,
392
+ toMs: now,
393
+ question: `${line} 产线该时窗数据深度根因诊断(自动触发:节点 ${s.nodeId} 采样值 ${s.value} ${rule.op === 'lt' ? '<' : '>'} ${rule.value})`,
394
+ scene: `${line}_auto`,
395
+ source: 'auto',
396
+ }).then((r) => {
397
+ if (r.ok) ctx.logger.warn(`自动诊断已发起:产线 ${line} runId=${r.runId}(节点 ${s.nodeId}=${s.value} 越限)`)
398
+ else ctx.logger.warn(`自动诊断发起失败(产线 ${line}): ${r.error}`)
399
+ }).catch(() => {})
400
+ }
401
+ catch { /* 钩子内绝不抛 */ }
402
+ })
403
+
404
+ // 工具 ×2
405
+ ctx.omp.registerTool({
406
+ name: 'diag_run',
407
+ label: '深度诊断',
408
+ description: '导出产线指定时窗的 DAQ 快照 CSV 并发起深度根因诊断(异步)。返回 runId 后需数分钟,请稍后用 diag_status 查询进度与结论。',
409
+ parameters: {
410
+ type: 'object',
411
+ properties: {
412
+ line: { type: 'string', description: '产线 id(必填)' },
413
+ from_ms: { type: 'number', description: '窗口起点(epoch 毫秒;缺省 now-60min)' },
414
+ to_ms: { type: 'number', description: '窗口终点(epoch 毫秒;缺省 now)' },
415
+ question: { type: 'string', description: '诊断问题(缺省为该产线时窗数据深度根因诊断)' },
416
+ scene: { type: 'string', description: '场景名(缺省 <line>_diag)' },
417
+ },
418
+ required: ['line'],
419
+ },
420
+ roles: ['lead', 'worker'],
421
+ handler: async (args) => {
422
+ try {
423
+ const line = String(args.line ?? '').trim()
424
+ if (!line) return { text: 'line 必填(产线 id)。', isError: true }
425
+ const toMs = Number(args.to_ms) > 0 ? Number(args.to_ms) : Date.now()
426
+ const fromMs = Number(args.from_ms) > 0 ? Number(args.from_ms) : toMs - 60 * MIN
427
+ if (fromMs >= toMs) return { text: 'from_ms 必须小于 to_ms。', isError: true }
428
+ const r = await startDiagnosis(ctx, {
429
+ line, fromMs, toMs,
430
+ question: args.question ? String(args.question) : '',
431
+ scene: args.scene ? String(args.scene) : '',
432
+ source: 'agent',
433
+ })
434
+ if (!r.ok) return { text: r.error, isError: true }
435
+ return {
436
+ text: `已发起深度诊断 runId=${r.runId}(产线 ${line},窗口 ${new Date(fromMs).toISOString()} ~ ${new Date(toMs).toISOString()},快照 ${r.rows} 行 × ${r.nodes} 节点 → ${r.csvPath})。诊断需数分钟,稍后用 diag_status 查询(run_id=${r.runId});完成后报告自动入知识库。`,
437
+ }
438
+ }
439
+ catch (err) {
440
+ return { text: `diag_run 异常: ${err?.message ?? err}`, isError: true }
441
+ }
442
+ },
443
+ })
444
+
445
+ ctx.omp.registerTool({
446
+ name: 'diag_status',
447
+ label: '诊断状态',
448
+ description: '查询深度诊断进度:传 run_id 看单条实时状态(完成时含评分/结论/报告路径),不传看最近 5 条概要。',
449
+ parameters: {
450
+ type: 'object',
451
+ properties: {
452
+ run_id: { type: 'string', description: '诊断 runId(缺省列最近 5 条概要)' },
453
+ },
454
+ },
455
+ roles: ['lead', 'worker'],
456
+ handler: async (args) => {
457
+ try {
458
+ const id = String(args.run_id ?? '').trim()
459
+ if (!id) {
460
+ const runs = kvRuns(ctx)
461
+ .sort((a, b) => (b.meta?.createdAt ?? 0) - (a.meta?.createdAt ?? 0))
462
+ .slice(0, 5)
463
+ if (!runs.length) return { text: '暂无诊断记录。用 diag_run 发起一次深度诊断。' }
464
+ const lines = runs.map(({ id: rid, meta }) =>
465
+ `- ${rid} | ${meta.line} | ${meta.status}${meta.stored ? '(已入库)' : ''} | ${meta.source ?? 'agent'} | ${meta.createdAt ? new Date(meta.createdAt).toISOString() : '?'} | ${meta.question ?? ''}`)
466
+ return { text: `最近 ${runs.length} 条诊断:\n${lines.join('\n')}` }
467
+ }
468
+ const meta = ctx.kv.get(runKey(id))
469
+ const base = baseOf(ctx)
470
+ let st = null
471
+ if (base) {
472
+ try {
473
+ st = (await jget(ctx, `${base}/api/diagnosis/status/${encodeURIComponent(id)}`, 8000)).data ?? null
474
+ }
475
+ catch { /* 3210 不可达时回退 kv 元数据 */ }
476
+ }
477
+ if (!st && !meta) return { text: `诊断 ${id} 不存在或诊断服务不可达。`, isError: true }
478
+ const status = st?.engineStatus || st?.status || meta?.status || 'unknown'
479
+ const parts = [
480
+ `run_id=${id}`,
481
+ `name=${st?.name ?? meta?.name ?? '?'}`,
482
+ `产线=${meta?.line ?? st?.scene_name ?? '?'}`,
483
+ `状态=${status}`,
484
+ `来源=${meta?.source ?? '?'}`,
485
+ ]
486
+ if (meta?.fromMs && meta?.toMs) parts.push(`窗口=${new Date(meta.fromMs).toISOString()} ~ ${new Date(meta.toMs).toISOString()}`)
487
+ if (meta?.question) parts.push(`问题=${meta.question}`)
488
+ if (status === 'completed') {
489
+ parts.push(`评分=${st?.score ?? meta?.score ?? '-'}`)
490
+ parts.push(`结论=${st?.judge_verdict ?? meta?.verdict ?? '-'}`)
491
+ parts.push(`report_path=${st?.report_path ?? meta?.reportPath ?? '-'}`)
492
+ parts.push(`入库=${meta?.stored ? '是' : meta && st ? '否/进行中' : '?'}`)
493
+ }
494
+ if (status === 'failed' || status === 'stopped') parts.push(`错误=${st?.error_message ?? meta?.error ?? '-'}`)
495
+ if (!st) parts.push('(诊断服务不可达,以上为本地记录)')
496
+ return { text: parts.join('\n') }
497
+ }
498
+ catch (err) {
499
+ return { text: `diag_status 异常: ${err?.message ?? err}`, isError: true }
500
+ }
501
+ },
502
+ })
503
+
504
+ // 路由 ×3(挂 /api/plugins/diag-bridge/*)
505
+ ctx.route('GET', '/health', async () => {
506
+ const runs = kvRuns(ctx)
507
+ const byStatus = {}
508
+ for (const { meta } of runs) byStatus[meta?.status ?? 'unknown'] = (byStatus[meta?.status ?? 'unknown'] ?? 0) + 1
509
+ const base = baseOf(ctx)
510
+ let remote
511
+ if (base) {
512
+ try {
513
+ // /api/health 响应无 success 字段,单独取(不套 jget 断言)
514
+ const res = await ctx.http.get(`${base}/api/health`, { timeoutMs: 5000 })
515
+ const body = await res.json().catch(() => null)
516
+ remote = res.ok && body
517
+ ? { status: body.status ?? 'ok', activeRuns: body.checks?.activeRuns ?? null }
518
+ : { status: `HTTP ${res.status}`, activeRuns: null }
519
+ }
520
+ catch (err) {
521
+ remote = { status: 'unreachable', error: String(err?.message ?? err) }
522
+ }
523
+ }
524
+ else {
525
+ remote = { status: 'bad_base_url' }
526
+ }
527
+ return { plugin: ctx.name, base: base ?? String(ctx.kv.get('diag.base_url') || DEFAULT_BASE), remote, runs: { total: runs.length, byStatus } }
528
+ })
529
+
530
+ ctx.route('GET', '/runs', () => ({
531
+ success: true,
532
+ runs: kvRuns(ctx)
533
+ .sort((a, b) => (b.meta?.createdAt ?? 0) - (a.meta?.createdAt ?? 0))
534
+ .map(({ id, meta }) => ({ runId: id, ...meta })),
535
+ }))
536
+
537
+ ctx.route('POST', '/snapshot', async (event) => {
538
+ try {
539
+ const b = event?.awBody ?? {}
540
+ const line = String(b.line ?? '').trim()
541
+ if (!line) return { success: false, error: 'line 必填(产线 id)' }
542
+ const toMs = Number(b.to_ms) > 0 ? Number(b.to_ms) : Date.now()
543
+ const fromMs = Number(b.from_ms) > 0 ? Number(b.from_ms) : toMs - 60 * MIN
544
+ if (fromMs >= toMs) return { success: false, error: 'from_ms 必须小于 to_ms' }
545
+ const snap = await snapshotCore(ctx, line, fromMs, toMs)
546
+ if (!snap.ok) return { success: false, error: snap.error }
547
+ return { success: true, csvPath: snap.csvPath, rows: snap.rows, nodes: snap.nodes, fromMs: snap.fromMs, toMs: snap.toMs }
548
+ }
549
+ catch (err) {
550
+ return { success: false, error: String(err?.message ?? err) }
551
+ }
552
+ })
553
+
554
+ ctx.logger.info('diag-bridge 就绪:工具 diag_run/diag_status + 路由 health/runs/snapshot,轮询 15s 已启动')
555
+ },
556
+ }