agentworkshop 0.7.27 → 0.7.34

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 (1033) hide show
  1. package/.AgentWorkShop/prompts/aml-mission-default.md +20 -0
  2. package/.AgentWorkShop/prompts/aml-playbook.md +49 -0
  3. package/.AgentWorkShop/prompts/host-tools.json +314 -0
  4. package/.output/.AgentWorkShop/prompts/aml-mission-default.md +20 -0
  5. package/.output/.AgentWorkShop/prompts/aml-playbook.md +49 -0
  6. package/.output/.AgentWorkShop/prompts/host-tools.json +314 -0
  7. package/.output/.AgentWorkShop/schema.json +120 -0
  8. package/.output/nitro.json +1 -1
  9. package/.output/public/_nuxt/{BTLEvDxM.js → 4bHdIqEg.js} +8 -8
  10. package/.output/public/_nuxt/B9nXmjSB.js +19 -0
  11. package/.output/public/_nuxt/BASN8nZ0.js +1 -0
  12. package/.output/public/_nuxt/{DNQF_TXX.js → BBBtwOpo.js} +1 -1
  13. package/.output/public/_nuxt/{DoAlYsiF.js → BBwMH_hG.js} +1 -1
  14. package/.output/public/_nuxt/BWSE6hR6.js +1 -0
  15. package/.output/public/_nuxt/BZv4RFYN.js +1 -0
  16. package/.output/public/_nuxt/{BgCrZKv_2.js → Bc0AmjfT.js} +1 -1
  17. package/.output/public/_nuxt/BcmbLh2z2.js +1 -0
  18. package/.output/public/_nuxt/BgTB6h_q.js +2 -0
  19. package/.output/public/_nuxt/BkLJA9J5.js +1 -0
  20. package/.output/public/_nuxt/{XY2z78rj.js → BuCHayqN.js} +1 -1
  21. package/.output/public/_nuxt/{0jKrzLuM.js → BuvcLKh1.js} +1 -1
  22. package/.output/public/_nuxt/C-mDhyEd.js +1 -0
  23. package/.output/public/_nuxt/{DosOJEmZ2.js → C77oC8yC2.js} +1 -1
  24. package/.output/public/_nuxt/CQvmN-Mi.js +1 -0
  25. package/.output/public/_nuxt/CUDrOuW7.js +1 -0
  26. package/.output/public/_nuxt/{DjU9Dx5Y.js → CZcC-gpk.js} +1 -1
  27. package/.output/public/_nuxt/{Cz9gD2Yo.js → CbzsPO5H.js} +1 -1
  28. package/.output/public/_nuxt/CdSOrh2c.js +1 -0
  29. package/.output/public/_nuxt/Cgx818r-.js +1 -0
  30. package/.output/public/_nuxt/Cjm7VogC.js +1 -0
  31. package/.output/public/_nuxt/Cm5mDxzH.js +1 -0
  32. package/.output/public/_nuxt/Cp6z0RN7.js +1 -0
  33. package/.output/public/_nuxt/Ct-WOVr4.js +1 -0
  34. package/.output/public/_nuxt/CwqIxJGj.js +2 -0
  35. package/.output/public/_nuxt/{BGhOrgle.js → D0fhp-Ga.js} +2 -2
  36. package/.output/public/_nuxt/DIaTPH1M.js +1 -0
  37. package/.output/public/_nuxt/DLljr7g0.js +1 -0
  38. package/.output/public/_nuxt/DTYBfjRY.js +1 -0
  39. package/.output/public/_nuxt/DYKVPzN-.js +1 -0
  40. package/.output/public/_nuxt/DZzGarBE2.js +13 -0
  41. package/.output/public/_nuxt/DaMCzQhv.js +1 -0
  42. package/.output/public/_nuxt/DoMxCWN52.js +4 -0
  43. package/.output/public/_nuxt/{CucID8qg2.js → DoTdlVVe2.js} +1 -1
  44. package/.output/public/_nuxt/DsVcWfyR.js +1 -0
  45. package/.output/public/_nuxt/{BCJFMBQ6.js → DzuC31-i.js} +2 -2
  46. package/.output/public/_nuxt/FQri3dV3.js +1 -0
  47. package/.output/public/_nuxt/Lp7Ll94I.js +1 -0
  48. package/.output/public/_nuxt/PluginSlot.DmjNbrcX.css +1 -0
  49. package/.output/public/_nuxt/_id_.hRYo-EAB.css +1 -0
  50. package/.output/public/_nuxt/_wsId_.gXMEOYgX.css +1 -0
  51. package/.output/public/_nuxt/agents.BV70ioCv.css +1 -0
  52. package/.output/public/_nuxt/aml.WU_bh87J.css +1 -0
  53. package/.output/public/_nuxt/builds/latest.json +1 -1
  54. package/.output/public/_nuxt/builds/meta/adc365b6-f636-4a2b-9527-79819c1e874b.json +1 -0
  55. package/.output/public/_nuxt/daq.Bb6l44-O.css +1 -0
  56. package/.output/public/_nuxt/default.jNT73_hq.css +1 -0
  57. package/.output/public/_nuxt/ekuGmQ7R.js +1 -0
  58. package/.output/public/_nuxt/entry.jFrFAWuA.css +1 -0
  59. package/.output/public/_nuxt/pMoIO6rr.js +14 -0
  60. package/.output/public/_nuxt/pages.Cc8GX9T1.css +1 -0
  61. package/.output/public/_nuxt/plugins.wIPyfPn-.css +1 -0
  62. package/.output/public/_nuxt/settings.BCm4NZIc.css +1 -0
  63. package/.output/public/_nuxt/teams.BC75EGnR.css +1 -0
  64. package/.output/server/chunks/_/binding-authz.mjs +23 -0
  65. package/.output/server/chunks/_/binding-authz.mjs.map +1 -0
  66. package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
  67. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  68. package/.output/server/chunks/_/nitro.mjs +15929 -9198
  69. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  70. package/.output/server/chunks/_/scene-layout.repo.mjs +3 -3
  71. package/.output/server/chunks/_/scene-layout.repo.mjs.map +1 -1
  72. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs +207 -0
  73. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs.map +1 -0
  74. package/.output/server/chunks/build/{OmpTerminalPanel-Cw_Vw9oO.mjs → OmpTerminalPanel-Cu_s4i0A.mjs} +2 -2
  75. package/.output/server/chunks/build/{OmpTerminalPanel-Cw_Vw9oO.mjs.map → OmpTerminalPanel-Cu_s4i0A.mjs.map} +1 -1
  76. package/.output/server/chunks/build/{alert-qJnjyRcP.mjs → PluginSlot-CcR4Ys3T.mjs} +140 -4
  77. package/.output/server/chunks/build/PluginSlot-CcR4Ys3T.mjs.map +1 -0
  78. package/.output/server/chunks/build/{TownView-ftIylqiD.mjs → TownView-BdHnAilw.mjs} +5 -5
  79. package/.output/server/chunks/build/{TownView-ftIylqiD.mjs.map → TownView-BdHnAilw.mjs.map} +1 -1
  80. package/.output/server/chunks/build/{_id_-CahfkmEt.mjs → _id_-Cb845FHR.mjs} +7 -5
  81. package/.output/server/chunks/build/_id_-Cb845FHR.mjs.map +1 -0
  82. package/.output/server/chunks/build/{_id_-3Axz2-gV.mjs → _id_-fadFPl2i.mjs} +50 -35
  83. package/.output/server/chunks/build/_id_-fadFPl2i.mjs.map +1 -0
  84. package/.output/server/chunks/build/{_wsId_-BymlQhzS.mjs → _wsId_-CTZswnm5.mjs} +181 -22
  85. package/.output/server/chunks/build/{_wsId_-BymlQhzS.mjs.map → _wsId_-CTZswnm5.mjs.map} +1 -1
  86. package/.output/server/chunks/build/{agents-DuMiSWKp.mjs → agents-Bvin73QY.mjs} +82 -32
  87. package/.output/server/chunks/build/agents-Bvin73QY.mjs.map +1 -0
  88. package/.output/server/chunks/build/aml-uBNIppIf.mjs +508 -0
  89. package/.output/server/chunks/build/aml-uBNIppIf.mjs.map +1 -0
  90. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs +81 -0
  91. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs.map +1 -0
  92. package/.output/server/chunks/build/{channel-templates-BStqJ-of.mjs → channel-templates-BTq8570n.mjs} +6 -5
  93. package/.output/server/chunks/build/channel-templates-BTq8570n.mjs.map +1 -0
  94. package/.output/server/chunks/build/{checkbox-C1gABOca.mjs → checkbox-8fB-wI-T.mjs} +2 -2
  95. package/.output/server/chunks/build/{checkbox-C1gABOca.mjs.map → checkbox-8fB-wI-T.mjs.map} +1 -1
  96. package/.output/server/chunks/build/{daq-ChYCABz1.mjs → daq-BvihjQyW.mjs} +111 -109
  97. package/.output/server/chunks/build/daq-BvihjQyW.mjs.map +1 -0
  98. package/.output/server/chunks/build/{dcw-CcQNGggh.mjs → dcw-Ks2vJ4PF.mjs} +5 -3
  99. package/.output/server/chunks/build/dcw-Ks2vJ4PF.mjs.map +1 -0
  100. package/.output/server/chunks/build/{default-95-zOTPt.mjs → default-GgHt4O2R.mjs} +164 -101
  101. package/.output/server/chunks/build/{default-95-zOTPt.mjs.map → default-GgHt4O2R.mjs.map} +1 -1
  102. package/.output/server/chunks/build/{input-number-Bd55elNN.mjs → input-number-DzpyYB99.mjs} +2 -2
  103. package/.output/server/chunks/build/{input-number-Bd55elNN.mjs.map → input-number-DzpyYB99.mjs.map} +1 -1
  104. package/.output/server/chunks/build/{logs-D-2UyGtE.mjs → logs-CYBhkQwh.mjs} +5 -3
  105. package/.output/server/chunks/build/logs-CYBhkQwh.mjs.map +1 -0
  106. package/.output/server/chunks/build/{monitor-mfG5jBtz.mjs → monitor-CyfDt4nR.mjs} +7 -6
  107. package/.output/server/chunks/build/{monitor-mfG5jBtz.mjs.map → monitor-CyfDt4nR.mjs.map} +1 -1
  108. package/.output/server/chunks/build/{pages-Dfosfchr.mjs → pages-C-6BRtv8.mjs} +57 -47
  109. package/.output/server/chunks/build/pages-C-6BRtv8.mjs.map +1 -0
  110. package/.output/server/chunks/build/{permissions-B-hhZuzm.mjs → permissions-B52oOmaO.mjs} +6 -5
  111. package/.output/server/chunks/build/permissions-B52oOmaO.mjs.map +1 -0
  112. package/.output/server/chunks/build/{plugins-DZR0T4Mh.mjs → plugins-dZRegC7m.mjs} +22 -18
  113. package/.output/server/chunks/build/plugins-dZRegC7m.mjs.map +1 -0
  114. package/.output/server/chunks/build/{segmented-LPPREMtZ.mjs → segmented-3TrWo0lS.mjs} +3 -3
  115. package/.output/server/chunks/build/{segmented-LPPREMtZ.mjs.map → segmented-3TrWo0lS.mjs.map} +1 -1
  116. package/.output/server/chunks/build/{settings-BajN9TQW.mjs → settings-CgDLkP3s.mjs} +437 -62
  117. package/.output/server/chunks/build/settings-CgDLkP3s.mjs.map +1 -0
  118. package/.output/server/chunks/build/{table-Bf1r2JjE.mjs → table-BjSWwmic.mjs} +4 -4
  119. package/.output/server/chunks/build/{table-Bf1r2JjE.mjs.map → table-BjSWwmic.mjs.map} +1 -1
  120. package/.output/server/chunks/build/{tag-NO9jEqKy.mjs → tag-DNE9vXc0.mjs} +3 -131
  121. package/.output/server/chunks/build/tag-DNE9vXc0.mjs.map +1 -0
  122. package/.output/server/chunks/build/{teams-t2SkRlJP.mjs → teams-2kz3CusY.mjs} +31 -30
  123. package/.output/server/chunks/build/teams-2kz3CusY.mjs.map +1 -0
  124. package/.output/server/chunks/build/{tokens-DiCojbN8.mjs → tokens-BbWLqtVz.mjs} +6 -5
  125. package/.output/server/chunks/build/tokens-BbWLqtVz.mjs.map +1 -0
  126. package/.output/server/chunks/build/town-BUqRobze.mjs +1 -0
  127. package/.output/server/chunks/build/town-BUqRobze.mjs.map +1 -1
  128. package/.output/server/chunks/build/{town-C7QM8DYK.mjs → town-DJ-V5G9U.mjs} +7 -5
  129. package/.output/server/chunks/build/town-DJ-V5G9U.mjs.map +1 -0
  130. package/.output/server/chunks/build/{useDaqStream-BeA2X8KR.mjs → useDaqStream-CIBaiGAl.mjs} +4 -3
  131. package/.output/server/chunks/build/useDaqStream-CIBaiGAl.mjs.map +1 -0
  132. package/.output/server/chunks/build/{useDcwStream-BJW_MitY.mjs → useDcwStream-CBbiYnWe.mjs} +4 -80
  133. package/.output/server/chunks/build/useDcwStream-CBbiYnWe.mjs.map +1 -0
  134. package/.output/server/chunks/build/{useDeviceTwins-Dwz_EY_i.mjs → useDeviceTwins-Yko6nNPF.mjs} +2 -2
  135. package/.output/server/chunks/build/{useDeviceTwins-Dwz_EY_i.mjs.map → useDeviceTwins-Yko6nNPF.mjs.map} +1 -1
  136. package/.output/server/chunks/build/{useOpsLog-Dm8QEb1I.mjs → useOpsLog-CO_VWh7t.mjs} +2 -2
  137. package/.output/server/chunks/build/{useOpsLog-Dm8QEb1I.mjs.map → useOpsLog-CO_VWh7t.mjs.map} +1 -1
  138. package/.output/server/chunks/build/{useWorkshopApi-B-L3MmIX.mjs → useWorkshopApi-NyjL0L3j.mjs} +4 -2
  139. package/.output/server/chunks/build/{useWorkshopApi-B-L3MmIX.mjs.map → useWorkshopApi-NyjL0L3j.mjs.map} +1 -1
  140. package/.output/server/chunks/build/{users-B9SAdEtH.mjs → users-4nzxTjFT.mjs} +6 -5
  141. package/.output/server/chunks/build/users-4nzxTjFT.mjs.map +1 -0
  142. package/.output/server/chunks/build/workshop-81xhz368.mjs +1 -0
  143. package/.output/server/chunks/build/workshop-81xhz368.mjs.map +1 -1
  144. package/.output/server/chunks/routes/api/health.get.mjs +1 -0
  145. package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
  146. package/.output/server/chunks/routes/api/index.get.mjs +1 -1
  147. package/.output/server/chunks/routes/api/index.post.mjs +1 -1
  148. package/.output/server/chunks/routes/api/metrics.mjs +1 -0
  149. package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
  150. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -0
  151. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
  152. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +1 -0
  153. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs.map +1 -1
  154. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs +26 -0
  155. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs.map +1 -0
  156. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +2 -1
  157. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs.map +1 -1
  158. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +32 -0
  159. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs.map +1 -0
  160. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +36 -0
  161. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs.map +1 -0
  162. package/.output/server/chunks/routes/api/system/config.get.mjs +1 -0
  163. package/.output/server/chunks/routes/api/system/config.get.mjs.map +1 -1
  164. package/.output/server/chunks/routes/api/system/index.get.mjs +7 -2
  165. package/.output/server/chunks/routes/api/system/index.get.mjs.map +1 -1
  166. package/.output/server/chunks/routes/api/system/index.patch.mjs +2 -1
  167. package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
  168. package/.output/server/chunks/routes/api/system/index.post.mjs +36 -0
  169. package/.output/server/chunks/routes/api/system/index.post.mjs.map +1 -0
  170. package/.output/server/chunks/routes/api/system/index2.get.mjs +28 -0
  171. package/.output/server/chunks/routes/api/system/index2.get.mjs.map +1 -0
  172. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +2 -1
  173. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs.map +1 -1
  174. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +2 -1
  175. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs.map +1 -1
  176. package/.output/server/chunks/routes/api/system/monitor.get.mjs +1 -0
  177. package/.output/server/chunks/routes/api/system/monitor.get.mjs.map +1 -1
  178. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +8 -5
  179. package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
  180. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +2 -1
  181. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
  182. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +2 -1
  183. package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
  184. package/.output/server/chunks/routes/api/users/_id_.get.mjs +2 -1
  185. package/.output/server/chunks/routes/api/users/_id_.get.mjs.map +1 -1
  186. package/.output/server/chunks/routes/api/users/_id_.put.mjs +1 -1
  187. package/.output/server/chunks/routes/api/users/index.get.mjs +2 -1
  188. package/.output/server/chunks/routes/api/users/index.get.mjs.map +1 -1
  189. package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
  190. package/.output/server/chunks/routes/api/users/login.post.mjs +1 -1
  191. package/.output/server/chunks/routes/api/users/logout.post.mjs +2 -1
  192. package/.output/server/chunks/routes/api/users/logout.post.mjs.map +1 -1
  193. package/.output/server/chunks/routes/api/users/me.get.mjs +2 -1
  194. package/.output/server/chunks/routes/api/users/me.get.mjs.map +1 -1
  195. package/.output/server/chunks/routes/api/users/register.post.mjs +1 -1
  196. package/.output/server/chunks/routes/api/users/setup-status.get.mjs +2 -1
  197. package/.output/server/chunks/routes/api/users/setup-status.get.mjs.map +1 -1
  198. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +2 -1
  199. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs.map +1 -1
  200. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +2 -1
  201. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs.map +1 -1
  202. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/_...path_.mjs +2 -1
  204. package/.output/server/chunks/routes/api/workshop/_...path_.mjs.map +1 -1
  205. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +2 -1
  206. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs.map +1 -1
  207. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +2 -1
  210. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs.map +1 -1
  211. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +5 -2
  212. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs.map +1 -1
  213. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +9 -3
  214. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs.map +1 -1
  215. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +2 -1
  216. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs.map +1 -1
  217. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +2 -1
  218. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
  219. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +23 -3
  220. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs.map +1 -1
  221. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +21 -3
  222. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
  223. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +2 -1
  224. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs.map +1 -1
  225. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +2 -1
  226. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs.map +1 -1
  227. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +2 -1
  228. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs.map +1 -1
  229. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
  231. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +75 -0
  232. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs.map +1 -0
  233. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +35 -0
  234. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs.map +1 -0
  235. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +35 -0
  236. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs.map +1 -0
  237. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +46 -0
  238. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs.map +1 -0
  239. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs +47 -0
  240. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs.map +1 -0
  241. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +48 -0
  242. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs.map +1 -0
  243. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +41 -0
  244. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs.map +1 -0
  245. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +62 -0
  246. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs.map +1 -0
  247. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +35 -0
  248. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs.map +1 -0
  249. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +36 -0
  250. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs.map +1 -0
  251. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +34 -0
  252. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs.map +1 -0
  253. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +38 -0
  254. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs.map +1 -0
  255. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +37 -0
  256. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs.map +1 -0
  257. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +42 -0
  258. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs.map +1 -0
  259. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +2 -1
  260. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs.map +1 -1
  261. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +2 -1
  262. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs.map +1 -1
  263. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +2 -1
  264. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs.map +1 -1
  265. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +2 -1
  266. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs.map +1 -1
  267. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +2 -1
  268. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs.map +1 -1
  269. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -0
  270. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs.map +1 -1
  271. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +2 -1
  272. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs.map +1 -1
  273. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +2 -1
  274. package/.output/server/chunks/routes/api/workshop/audit.get.mjs.map +1 -1
  275. package/.output/server/chunks/routes/api/workshop/caller.mjs +2 -1
  276. package/.output/server/chunks/routes/api/workshop/caller.mjs.map +1 -1
  277. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +2 -2
  278. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +2 -1
  279. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs.map +1 -1
  280. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +2 -1
  281. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs.map +1 -1
  282. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
  283. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
  284. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -1
  285. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs.map +1 -1
  286. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +2 -1
  287. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs.map +1 -1
  288. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
  289. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +2 -1
  290. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs.map +1 -1
  291. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
  292. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +2 -1
  293. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs.map +1 -1
  294. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +2 -1
  295. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs.map +1 -1
  296. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +2 -1
  297. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs.map +1 -1
  298. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +2 -1
  299. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs.map +1 -1
  300. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +2 -1
  301. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs.map +1 -1
  302. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +2 -1
  303. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs.map +1 -1
  304. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
  305. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +2 -1
  306. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs.map +1 -1
  307. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
  308. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +2 -1
  309. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs.map +1 -1
  310. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +2 -1
  311. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs.map +1 -1
  312. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
  313. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +1 -1
  314. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  315. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +2 -1
  316. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
  317. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  318. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -0
  319. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs.map +1 -1
  320. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +2 -1
  321. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs.map +1 -1
  322. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +2 -1
  323. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs.map +1 -1
  324. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -1
  325. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs.map +1 -1
  326. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +1 -0
  327. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs.map +1 -1
  328. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -1
  329. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs.map +1 -1
  330. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
  331. package/.output/server/chunks/routes/api/workshop/channels.get.mjs +1 -0
  332. package/.output/server/chunks/routes/api/workshop/channels.get.mjs.map +1 -1
  333. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +4 -4
  334. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +2 -1
  335. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs.map +1 -1
  336. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +2 -1
  337. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs.map +1 -1
  338. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +2 -1
  339. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs.map +1 -1
  340. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +2 -1
  341. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs.map +1 -1
  342. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +2 -1
  343. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
  344. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -1
  345. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs.map +1 -1
  346. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +3 -1
  347. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs.map +1 -1
  348. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +2 -1
  349. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
  350. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +2 -1
  351. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs.map +1 -1
  352. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -1
  353. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs.map +1 -1
  354. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +2 -1
  355. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs.map +1 -1
  356. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -1
  357. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
  358. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -1
  359. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs.map +1 -1
  360. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -1
  361. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs.map +1 -1
  362. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -1
  363. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
  364. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -1
  365. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
  366. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -1
  367. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs.map +1 -1
  368. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +2 -1
  369. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs.map +1 -1
  370. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +2 -1
  371. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs.map +1 -1
  372. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -1
  373. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs.map +1 -1
  374. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +2 -1
  375. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs.map +1 -1
  376. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +2 -1
  377. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs.map +1 -1
  378. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +2 -1
  379. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
  380. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -1
  381. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
  382. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +7 -2
  383. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs.map +1 -1
  384. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -1
  385. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs.map +1 -1
  386. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -1
  387. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs.map +1 -1
  388. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +2 -1
  389. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs.map +1 -1
  390. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +2 -1
  391. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs.map +1 -1
  392. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +2 -1
  393. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
  394. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -1
  395. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs.map +1 -1
  396. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -1
  397. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
  398. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -1
  399. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
  400. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -1
  401. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
  402. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +2 -1
  403. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
  404. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -1
  405. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs.map +1 -1
  406. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +2 -1
  407. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
  408. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +2 -1
  409. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs.map +1 -1
  410. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +2 -1
  411. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs.map +1 -1
  412. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -1
  413. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs.map +1 -1
  414. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -1
  415. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
  416. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -1
  417. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs.map +1 -1
  418. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -1
  419. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs.map +1 -1
  420. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -1
  421. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs.map +1 -1
  422. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -1
  423. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs.map +1 -1
  424. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -1
  425. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs.map +1 -1
  426. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -1
  427. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs.map +1 -1
  428. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -1
  429. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs.map +1 -1
  430. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -1
  431. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs.map +1 -1
  432. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +2 -1
  433. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs.map +1 -1
  434. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -1
  435. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs.map +1 -1
  436. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +2 -1
  437. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs.map +1 -1
  438. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -1
  439. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs.map +1 -1
  440. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +2 -1
  441. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs.map +1 -1
  442. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -1
  443. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs.map +1 -1
  444. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +2 -1
  445. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs.map +1 -1
  446. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -1
  447. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs.map +1 -1
  448. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -1
  449. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs.map +1 -1
  450. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -1
  451. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs.map +1 -1
  452. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -1
  453. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs.map +1 -1
  454. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +2 -1
  455. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs.map +1 -1
  456. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +2 -1
  457. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs.map +1 -1
  458. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -1
  459. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs.map +1 -1
  460. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -1
  461. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs.map +1 -1
  462. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +2 -1
  463. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs.map +1 -1
  464. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +32 -1
  465. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs.map +1 -1
  466. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +2 -1
  467. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs.map +1 -1
  468. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +2 -1
  469. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -1
  470. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +3 -2
  471. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -1
  472. package/.output/server/chunks/routes/api/workshop/index.get.mjs +1 -0
  473. package/.output/server/chunks/routes/api/workshop/index.get.mjs.map +1 -1
  474. package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
  475. package/.output/server/chunks/routes/api/workshop/index.put.mjs +2 -1
  476. package/.output/server/chunks/routes/api/workshop/index.put.mjs.map +1 -1
  477. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +12 -6
  478. package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
  479. package/.output/server/chunks/routes/api/workshop/index11.get.mjs +4 -2
  480. package/.output/server/chunks/routes/api/workshop/index11.get.mjs.map +1 -1
  481. package/.output/server/chunks/routes/api/workshop/index12.get.mjs +28 -0
  482. package/.output/server/chunks/routes/api/workshop/index12.get.mjs.map +1 -0
  483. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +17 -11
  484. package/.output/server/chunks/routes/api/workshop/index2.get.mjs.map +1 -1
  485. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
  486. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +11 -4
  487. package/.output/server/chunks/routes/api/workshop/index3.get.mjs.map +1 -1
  488. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +2 -1
  489. package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
  490. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +5 -27
  491. package/.output/server/chunks/routes/api/workshop/index4.get.mjs.map +1 -1
  492. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -1
  493. package/.output/server/chunks/routes/api/workshop/index4.post.mjs.map +1 -1
  494. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +24 -18
  495. package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
  496. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -1
  497. package/.output/server/chunks/routes/api/workshop/index5.post.mjs.map +1 -1
  498. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +23 -5
  499. package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
  500. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -1
  501. package/.output/server/chunks/routes/api/workshop/index6.post.mjs.map +1 -1
  502. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +4 -17
  503. package/.output/server/chunks/routes/api/workshop/index7.get.mjs.map +1 -1
  504. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +8 -3
  505. package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
  506. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +20 -21
  507. package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
  508. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
  509. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +24 -11
  510. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  511. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +1 -0
  512. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs.map +1 -1
  513. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +1 -0
  514. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs.map +1 -1
  515. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +2 -1
  516. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs.map +1 -1
  517. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +2 -1
  518. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs.map +1 -1
  519. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +2 -1
  520. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs.map +1 -1
  521. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +2 -1
  522. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs.map +1 -1
  523. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +1 -0
  524. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs.map +1 -1
  525. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +2 -1
  526. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs.map +1 -1
  527. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +2 -1
  528. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs.map +1 -1
  529. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +1 -0
  530. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs.map +1 -1
  531. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
  532. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
  533. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +2 -1
  534. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs.map +1 -1
  535. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
  536. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +2 -1
  537. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs.map +1 -1
  538. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +2 -1
  539. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs.map +1 -1
  540. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +1 -0
  541. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs.map +1 -1
  542. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
  543. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +2 -1
  544. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs.map +1 -1
  545. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
  546. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +44 -0
  547. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs.map +1 -0
  548. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +47 -0
  549. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs.map +1 -0
  550. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +2 -1
  551. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs.map +1 -1
  552. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +2 -1
  553. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs.map +1 -1
  554. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +2 -1
  555. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs.map +1 -1
  556. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
  557. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +2 -0
  558. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs.map +1 -1
  559. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +1 -1
  560. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
  561. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +1 -0
  562. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs.map +1 -1
  563. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +1 -0
  564. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs.map +1 -1
  565. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +1 -0
  566. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs.map +1 -1
  567. package/.output/server/chunks/routes/renderer.mjs +2 -2
  568. package/.output/server/chunks/virtual/entry.mjs +601 -36
  569. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  570. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  571. package/.output/server/index.mjs +1 -0
  572. package/.output/server/node_modules/@anthropic-ai/claude-agent-sdk/package.json +84 -0
  573. package/.output/server/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs +225 -0
  574. package/.output/server/package.json +2 -1
  575. package/README-zh.md +507 -478
  576. package/README.md +517 -486
  577. package/app/app.vue +17 -2
  578. package/app/assets/css/main.css +421 -30
  579. package/app/components/AppHeader.vue +17 -0
  580. package/app/components/AppSidebar.vue +162 -63
  581. package/app/components/AwChart.vue +57 -54
  582. package/app/components/workshop/ChannelSessionList.vue +802 -703
  583. package/app/components/workshop/DaqNodeRow.vue +156 -0
  584. package/app/components/workshop/PluginSlot.vue +120 -0
  585. package/app/composables/workshop/useAmlStream.ts +136 -0
  586. package/app/composables/workshop/useDaqStream.ts +8 -1
  587. package/app/composables/workshop/usePluginPanels.ts +72 -0
  588. package/app/composables/workshop/useWorkshopApi.ts +7 -0
  589. package/app/pages/aml/index.vue +1949 -0
  590. package/app/pages/daq/[id].vue +60 -2
  591. package/app/pages/daq/index.vue +7 -148
  592. package/app/pages/index.vue +235 -213
  593. package/app/pages/plugins/index.vue +280 -274
  594. package/app/pages/settings.vue +555 -78
  595. package/app/pages/workshop/agents.vue +23 -1
  596. package/app/pages/workshop/teams.vue +2 -2
  597. package/app/plugins/aw-plugins.client.ts +95 -6
  598. package/app/plugins/runtime-config.client.ts +4 -14
  599. package/app/plugins/theme.client.ts +13 -3
  600. package/app/stores/app.ts +9 -2
  601. package/app/stores/runtime-config.ts +113 -7
  602. package/cli/aw.mjs +16 -3
  603. package/cli/commands/build.mjs +8 -8
  604. package/cli/commands/dev.mjs +5 -13
  605. package/cli/commands/init.mjs +1 -1
  606. package/cli/commands/start.mjs +10 -17
  607. package/cli/core/args.mjs +85 -4
  608. package/cli/core/child-lifecycle.mjs +136 -0
  609. package/config.yml +24 -0
  610. package/docs/plugins.md +128 -220
  611. package/docs/sdk.md +1 -1
  612. package/i18n/dicts/_en.json +43 -2
  613. package/i18n/dicts/aml.json +163 -0
  614. package/i18n/dicts/channelSessionList.json +4 -1
  615. package/i18n/dicts/daqDetail.json +1 -0
  616. package/i18n/dicts/settings.json +33 -1
  617. package/i18n/dicts/teams.json +9 -1
  618. package/i18n/locales/en.ts +364 -132
  619. package/i18n/locales/zh-CN.ts +433 -201
  620. package/nuxt.config.ts +18 -3
  621. package/package.json +153 -149
  622. package/scripts/_audit/.tmp/audit-data/dcws.json +28 -0
  623. package/scripts/_audit/.tmp/dcw-writes.json +15650 -0
  624. package/scripts/_audit/.tmp/dcws.json +9033 -0
  625. package/scripts/_audit/.tmp/pollution-backup/dcw-rollback.polluted.json +470006 -0
  626. package/scripts/_audit/.tmp/pollution-backup/dcws.polluted.json +9085 -0
  627. package/scripts/_audit/.tmp/probe-cwd.txt +1 -0
  628. package/scripts/_audit/audit-harness-adapters.md +664 -0
  629. package/scripts/_audit/awhome/commands/README.md +3 -0
  630. package/scripts/_audit/awhome/commands/hello.mjs +12 -0
  631. package/scripts/_audit/dcw-controller-e2e.ts +99 -0
  632. package/scripts/_audit/dcw-flush-cost.ts +43 -0
  633. package/scripts/_audit/dcw-rollback-ledger.ts +153 -0
  634. package/scripts/_audit/dcw-unrecorded-write.ts +171 -0
  635. package/scripts/_audit/dcw-write-mutex.ts +157 -0
  636. package/scripts/_audit/diag-cwd.ts +20 -0
  637. package/scripts/_audit/diag-cwd2.ts +19 -0
  638. package/scripts/_audit/exp-cost-scaling.mjs +54 -0
  639. package/scripts/_audit/exp-envelope-and-png.mjs +77 -0
  640. package/scripts/_audit/exp-png-decode.mjs +67 -0
  641. package/scripts/_audit/exp-retention-plan.mjs +61 -0
  642. package/scripts/_audit/exp-retention-rescan.mjs +42 -0
  643. package/scripts/_audit/exp-sweep-fairness.mjs +48 -0
  644. package/scripts/_audit/hello.mjs +12 -0
  645. package/scripts/_audit/http-api-authz-audit.md +657 -0
  646. package/scripts/_audit/ndjson-partial-line-repro.mjs +77 -0
  647. package/scripts/_audit/opencode-await-ternary-repro.mjs +20 -0
  648. package/scripts/_audit/part-frag.txt +84 -0
  649. package/scripts/_audit/part-head.txt +45 -0
  650. package/scripts/_audit/probe-binding.mjs +103 -0
  651. package/scripts/_audit/probe-child.mjs +17 -0
  652. package/scripts/_audit/probe-envelope.mjs +49 -0
  653. package/scripts/_audit/probe-packlist.mjs +67 -0
  654. package/scripts/_audit/probe-routes.mjs +47 -0
  655. package/scripts/_audit/probe-routes2.mjs +38 -0
  656. package/scripts/_audit/probe.ts +9 -0
  657. package/scripts/_audit/probe2.ts +6 -0
  658. package/scripts/_audit/probe3.ts +3 -0
  659. package/scripts/_audit/probe4.ts +3 -0
  660. package/scripts/_audit/proj/.AgentWorkShop/commands/echoargs.mjs +13 -0
  661. package/scripts/_audit/proj/config.yml +1 -0
  662. package/scripts/_audit/run.mjs +30 -0
  663. package/scripts/_audit/runtime-audit.md +716 -0
  664. package/scripts/_audit/ts-resolve-hook.mjs +41 -0
  665. package/scripts/_audit/tsconfig.probe.json +24 -0
  666. package/scripts/_audit/typecheck-out.txt +466 -0
  667. package/scripts/_audit/verify-data-integrity.mjs +112 -0
  668. package/scripts/_dbg-agents-dropdown-shot.py +33 -0
  669. package/scripts/_dbg-anim-verify.mjs +1 -1
  670. package/scripts/_dbg-audit-all-pages.mjs +1 -1
  671. package/scripts/_dbg-availability-probe.ts +11 -0
  672. package/scripts/_dbg-bind-bidi-e2e.mjs +1 -1
  673. package/scripts/_dbg-cf-line-shot.mjs +18 -0
  674. package/scripts/_dbg-channel-plugin-ui.mjs +94 -0
  675. package/scripts/_dbg-configroot-audit.mjs +84 -0
  676. package/scripts/_dbg-crash-recovery.mjs +1 -1
  677. package/scripts/_dbg-crush-probe.sh +21 -0
  678. package/scripts/_dbg-crush-spawn-probe.ts +22 -0
  679. package/scripts/_dbg-daq-acc-probe.mjs +1 -1
  680. package/scripts/_dbg-daq-attrib.mjs +1 -1
  681. package/scripts/_dbg-daq-debug.mjs +1 -1
  682. package/scripts/_dbg-daq-diag.mjs +1 -1
  683. package/scripts/_dbg-daq-e2e.mjs +1 -1
  684. package/scripts/_dbg-daq-filter-e2e.mjs +1 -1
  685. package/scripts/_dbg-daq-filter-e2e2.mjs +1 -1
  686. package/scripts/_dbg-daq-final-regression.mjs +1 -1
  687. package/scripts/_dbg-daq-frame-alarm.mjs +1 -1
  688. package/scripts/_dbg-daq-frame-ui.mjs +1 -1
  689. package/scripts/_dbg-daq-frame-ws.mjs +1 -1
  690. package/scripts/_dbg-daq-frames-e2e.mjs +1 -1
  691. package/scripts/_dbg-daq-full-check.mjs +1 -1
  692. package/scripts/_dbg-daq-intervals-func.mjs +94 -0
  693. package/scripts/_dbg-daq-pages-shot.mjs +1 -1
  694. package/scripts/_dbg-daq-perf.mjs +1 -1
  695. package/scripts/_dbg-daq-probe.mjs +1 -1
  696. package/scripts/_dbg-daq-recipe-e2e.mjs +1 -1
  697. package/scripts/_dbg-daq-rows-probe.mjs +1 -1
  698. package/scripts/_dbg-daq-rowstate-e2e.mjs +1 -1
  699. package/scripts/_dbg-daq-rowstate-shot.mjs +1 -1
  700. package/scripts/_dbg-daq-rowstate-shot2.mjs +1 -1
  701. package/scripts/_dbg-daq-rowstyle-verify.mjs +112 -0
  702. package/scripts/_dbg-dash-console-check.mjs +1 -1
  703. package/scripts/_dbg-dash-deep-probe.mjs +1 -1
  704. package/scripts/_dbg-dash-hitpoint.mjs +1 -1
  705. package/scripts/_dbg-dcw-read-rest.mjs +1 -1
  706. package/scripts/_dbg-dcw-read-ui.mjs +1 -1
  707. package/scripts/_dbg-dcw-shot2.mjs +1 -1
  708. package/scripts/_dbg-diag-mock-loop.mjs +89 -0
  709. package/scripts/_dbg-diag-watch.mjs +95 -0
  710. package/scripts/_dbg-error-probe.mjs +2 -2
  711. package/scripts/_dbg-filter-light-verify.mjs +1 -1
  712. package/scripts/_dbg-final-acceptance-2.mjs +1 -1
  713. package/scripts/_dbg-final-acceptance.mjs +1 -1
  714. package/scripts/_dbg-final-full-e2e.mjs +1 -1
  715. package/scripts/_dbg-final-shots.mjs +32 -0
  716. package/scripts/_dbg-final-t6-hitl.mjs +1 -1
  717. package/scripts/_dbg-fix-unused-imports.py +41 -0
  718. package/scripts/_dbg-fresh-scene-e2e.mjs +1 -1
  719. package/scripts/_dbg-goose-probe.mjs +33 -0
  720. package/scripts/_dbg-goose-probe.sh +10 -0
  721. package/scripts/_dbg-groups-ui-verify.mjs +122 -0
  722. package/scripts/_dbg-harness-cancel-repro.mjs +81 -0
  723. package/scripts/_dbg-harness-ui-shot.py +109 -0
  724. package/scripts/_dbg-hidden-check.mjs +1 -1
  725. package/scripts/_dbg-home-repro.mjs +1 -1
  726. package/scripts/_dbg-home-stack.mjs +1 -1
  727. package/scripts/_dbg-hydration-detail.mjs +1 -1
  728. package/scripts/_dbg-infra-lifecycle.mjs +1 -1
  729. package/scripts/_dbg-line-live-e2e.mjs +1 -1
  730. package/scripts/_dbg-line-repo-test.ts +10 -0
  731. package/scripts/_dbg-login-debug.py +23 -0
  732. package/scripts/_dbg-modbus-latency.mjs +22 -0
  733. package/scripts/_dbg-mqtt-chain-e2e.mjs +1 -1
  734. package/scripts/_dbg-oneshot-impl-probe.ts +67 -0
  735. package/scripts/_dbg-opslog-agent-e2e.mjs +5 -2
  736. package/scripts/_dbg-opt-team-e2e.mjs +1 -1
  737. package/scripts/_dbg-panesplitter-fix-check.mjs +1 -1
  738. package/scripts/_dbg-phase-e3-monitor.mjs +1 -1
  739. package/scripts/_dbg-pi-spawn-probe.ts +33 -0
  740. package/scripts/_dbg-plc-e2e.mjs +1 -1
  741. package/scripts/_dbg-plugin-config-ui.mjs +111 -0
  742. package/scripts/_dbg-plugin-panels-ui.mjs +54 -0
  743. package/scripts/_dbg-plugin-sink-rest.mjs +1 -1
  744. package/scripts/_dbg-plugin-sink-ui.mjs +1 -1
  745. package/scripts/_dbg-plugin-ui-wizard.mjs +1 -1
  746. package/scripts/_dbg-plugin-verify-e2e.mjs +1 -1
  747. package/scripts/_dbg-pop-clamp-verify.mjs +1 -1
  748. package/scripts/_dbg-preview-console.mjs +1 -1
  749. package/scripts/_dbg-preview-minrepro.mjs +1 -1
  750. package/scripts/_dbg-preview-pixels.mjs +1 -1
  751. package/scripts/_dbg-quality-pages-e2e.mjs +1 -1
  752. package/scripts/_dbg-qwen-acp-probe.mjs +30 -0
  753. package/scripts/_dbg-qwen-capture.mjs +21 -0
  754. package/scripts/_dbg-rail-tree-e2e.mjs +1 -1
  755. package/scripts/_dbg-real-driver-e2e.mjs +1 -1
  756. package/scripts/_dbg-real-scenario-timeline.log +55 -123
  757. package/scripts/_dbg-redesign-shots.mjs +1 -1
  758. package/scripts/_dbg-release-smoke.mjs +1 -1
  759. package/scripts/_dbg-resolve-probe.ts +6 -0
  760. package/scripts/_dbg-restart-persist.mjs +1 -1
  761. package/scripts/_dbg-sc001-dispatch.mjs +1 -1
  762. package/scripts/_dbg-scenario-final-shot.mjs +1 -1
  763. package/scripts/_dbg-scenario-phase-e2.mjs +1 -1
  764. package/scripts/_dbg-scenario-phase-e3.mjs +1 -1
  765. package/scripts/_dbg-scenario-phase1.mjs +1 -1
  766. package/scripts/_dbg-scenario-phase2.mjs +1 -1
  767. package/scripts/_dbg-scenario-phase3-monitor.mjs +1 -1
  768. package/scripts/_dbg-scenario-phase3.mjs +1 -1
  769. package/scripts/_dbg-settings-draft-probe.mjs +39 -0
  770. package/scripts/_dbg-settings-probe.mjs +33 -0
  771. package/scripts/_dbg-task-cancel-probe.mjs +66 -0
  772. package/scripts/_dbg-town-alarm-e2e.mjs +1 -1
  773. package/scripts/_dbg-town-daq-shot.mjs +1 -1
  774. package/scripts/_dbg-town-full-e2e.mjs +1 -1
  775. package/scripts/_dbg-town-gate.mjs +1 -1
  776. package/scripts/_dbg-town-ins-probe.mjs +1 -1
  777. package/scripts/_dbg-town-perf.mjs +1 -1
  778. package/scripts/_dbg-town-realtime.mjs +1 -1
  779. package/scripts/_dbg-town-shot.py +25 -0
  780. package/scripts/_dbg-town-shot3.mjs +1 -1
  781. package/scripts/_dbg-town-smoke.mjs +54 -0
  782. package/scripts/_dbg-town-truth.mjs +1 -1
  783. package/scripts/_dbg-town-truth2.mjs +1 -1
  784. package/scripts/_dbg-trend-expand-test.mjs +1 -1
  785. package/scripts/_dbg-twindaq-focus.mjs +1 -1
  786. package/scripts/_dbg-ui-polish-shot.mjs +1 -1
  787. package/scripts/_dbg-ui-polish-verify1.mjs +1 -1
  788. package/scripts/_dbg-ui-polish-verify2.mjs +1 -1
  789. package/scripts/_dbg-ui-polish-verify3.mjs +1 -1
  790. package/scripts/_dbg-ui-polish-verify4.mjs +1 -1
  791. package/scripts/_dbg-unify-shot.mjs +1 -1
  792. package/scripts/_dbg-uplink-probe.mjs +1 -1
  793. package/scripts/_dbg-wizard-preview-shot.mjs +1 -1
  794. package/scripts/_dbg-wizard-ui-e2e.mjs +1 -1
  795. package/scripts/_dbg-ws-probe.mjs +1 -1
  796. package/scripts/_dbg-wsdot-sanity.mjs +1 -1
  797. package/scripts/_node-state-probe.mjs +1 -1
  798. package/scripts/_tmp-args-probe.mjs +20 -0
  799. package/scripts/_tmp-cyc-entry.mjs +8 -0
  800. package/scripts/_tmp-cyc-main.mjs +5 -0
  801. package/scripts/_tmp-cyc-mod.mjs +2 -0
  802. package/scripts/_tmp-cycle-a.mjs +6 -0
  803. package/scripts/_tmp-cycle-b.mjs +2 -0
  804. package/scripts/_tmp-cycle-probe.mjs +4 -0
  805. package/scripts/_tmp-entry-variant.mjs +2 -0
  806. package/scripts/_tmp-help-probe.mjs +19 -0
  807. package/scripts/_tmp-help-probe2.mjs +2 -0
  808. package/scripts/_tmp-trace-preload.mjs +1 -0
  809. package/scripts/aml-agent-bridge.ts +230 -0
  810. package/scripts/aml-industrial-loop.ts +232 -0
  811. package/scripts/aml-ui-smoke.mjs +67 -0
  812. package/scripts/aw-start-smoke.mjs +194 -0
  813. package/scripts/design-verify-templates.mjs +1 -1
  814. package/scripts/device-line-restore.mjs +1 -1
  815. package/scripts/e2e-aml.ts +259 -0
  816. package/scripts/e2e-config-groups.mjs +238 -0
  817. package/scripts/e2e-full-closedloop.mjs +911 -0
  818. package/scripts/e2e-full-scenario.ts +321 -0
  819. package/scripts/e2e-harness-consistency.ts +204 -0
  820. package/scripts/e2e-multi-harness.ts +233 -76
  821. package/scripts/e2e-plc-plugin-closedloop.mjs +518 -0
  822. package/scripts/e2e-real-scenario.mjs +466 -452
  823. package/scripts/e2e-template-isolation.mjs +2 -2
  824. package/scripts/experiment-castfilm-closedloop.mjs +423 -0
  825. package/scripts/experiment-castfilm-finish.mjs +194 -0
  826. package/scripts/experiment-castfilm-ui-shot.mjs +52 -0
  827. package/scripts/experiment-castfilm-viz.mjs +172 -0
  828. package/scripts/production-closed-loop-e2e.mjs +78 -29
  829. package/scripts/test-aml-integration.ts +159 -0
  830. package/scripts/test-aml-job.ts +174 -0
  831. package/scripts/test-aml-unit.ts +184 -0
  832. package/scripts/test-cli-exit.mjs +235 -0
  833. package/scripts/test-daq-frame-race.mjs +310 -0
  834. package/scripts/test-data-root.mjs +208 -0
  835. package/scripts/test-log-flooding.mjs +160 -0
  836. package/scripts/test-lru.mjs +78 -0
  837. package/scripts/test-memory-month-query.mjs +62 -0
  838. package/scripts/test-plugin-hardening.mjs +45 -0
  839. package/scripts/test-rollback-index.mjs +79 -0
  840. package/scripts/test-sdk-surface.mjs +155 -0
  841. package/scripts/three-system-e2e.mjs +662 -448
  842. package/scripts/town-scene-clear.mjs +1 -1
  843. package/sdk/client.d.mts +110 -0
  844. package/sdk/client.mjs +144 -124
  845. package/sdk/context.mjs +161 -1
  846. package/sdk/index.d.mts +37 -5
  847. package/sdk/index.mjs +44 -41
  848. package/sdk/lifecycle.mjs +4 -1
  849. package/server/api/plugins/i18n.get.ts +12 -0
  850. package/server/api/system/config-groups/[id].delete.ts +21 -0
  851. package/server/api/system/config-groups/[id].patch.ts +26 -0
  852. package/server/api/system/config-groups/index.get.ts +21 -0
  853. package/server/api/system/config-groups/index.post.ts +33 -0
  854. package/server/api/system/settings/events.get.ts +8 -4
  855. package/server/api/workshop/agent-tools/bindings/[id].delete.ts +6 -1
  856. package/server/api/workshop/agent-tools/bindings/[id].patch.ts +12 -3
  857. package/server/api/workshop/agent-tools/bindings/index.get.ts +29 -2
  858. package/server/api/workshop/agent-tools/invoke.post.ts +30 -5
  859. package/server/api/workshop/aml/datasets/[id]/preview.get.ts +68 -0
  860. package/server/api/workshop/aml/datasets/[id].get.ts +24 -0
  861. package/server/api/workshop/aml/datasets/index.get.ts +20 -0
  862. package/server/api/workshop/aml/datasets/index.post.ts +27 -0
  863. package/server/api/workshop/aml/experiments/index.get.ts +35 -0
  864. package/server/api/workshop/aml/index.get.ts +24 -0
  865. package/server/api/workshop/aml/jobs/[id]/cancel.post.ts +21 -0
  866. package/server/api/workshop/aml/jobs/[id]/logs.get.ts +23 -0
  867. package/server/api/workshop/aml/jobs/[id]/retry.post.ts +20 -0
  868. package/server/api/workshop/aml/jobs/[id].get.ts +23 -0
  869. package/server/api/workshop/aml/jobs/index.get.ts +26 -0
  870. package/server/api/workshop/aml/jobs/index.post.ts +44 -0
  871. package/server/api/workshop/aml/models/[id]/predict.post.ts +24 -0
  872. package/server/api/workshop/aml/models/[id]/promote.post.ts +30 -0
  873. package/server/api/workshop/aml/models/index.get.ts +48 -0
  874. package/server/api/workshop/daq/[id].delete.ts +6 -0
  875. package/server/api/workshop/dcw/[id].patch.ts +14 -2
  876. package/server/api/workshop/hitl/respond.post.ts +3 -1
  877. package/server/api/workshop/teams/[id]/plugins/index.get.ts +36 -0
  878. package/server/api/workshop/teams/[id]/plugins/index.put.ts +42 -0
  879. package/server/api/workshop/teams/index.post.ts +13 -0
  880. package/server/api/workshop/users/me.get.ts +5 -0
  881. package/server/api/workshop/ws.ts +14 -2
  882. package/server/data/daqs.json +1648 -123
  883. package/server/data/dcw-lines.json +301 -0
  884. package/server/data/dcw-products.json +140 -0
  885. package/server/data/dcw-recipes.json +890 -0
  886. package/server/data/dcw-rollback.json +11591 -5740
  887. package/server/data/dcw-runs.json +3745 -3559
  888. package/server/data/dcw-templates.json +120 -0
  889. package/server/data/dcw-writes.json +1800 -0
  890. package/server/data/dcws.json +1576 -287
  891. package/server/data/line-runs.json +137 -27
  892. package/server/harness/pi-aw-tools.mjs +51 -0
  893. package/server/plugins/dev-stability-guard.ts +63 -63
  894. package/server/plugins/system-config.ts +10 -11
  895. package/server/plugins/workshop.ts +10 -0
  896. package/server/plugins-builtin/diag-bridge/client.mjs +84 -0
  897. package/server/plugins-builtin/diag-bridge/i18n.json +72 -0
  898. package/server/plugins-builtin/diag-bridge/index.mjs +127 -22
  899. package/server/plugins-builtin/rag-bridge/client.mjs +108 -0
  900. package/server/plugins-builtin/rag-bridge/i18n.json +60 -0
  901. package/server/plugins-builtin/rag-bridge/index.mjs +67 -20
  902. package/server/services/system-config.ts +610 -396
  903. package/server/services/workshop/agents/adapters/line-spawn.ts +15 -6
  904. package/server/services/workshop/agents/adapters/one-shot-cli-agent.ts +530 -0
  905. package/server/services/workshop/agents/base-agent.ts +219 -0
  906. package/server/services/workshop/agents/binding-authz.ts +57 -0
  907. package/server/services/workshop/agents/claude-agent.ts +546 -30
  908. package/server/services/workshop/agents/codex-agent.ts +40 -116
  909. package/server/services/workshop/agents/copilot-agent.ts +136 -0
  910. package/server/services/workshop/agents/crush-agent.ts +107 -0
  911. package/server/services/workshop/agents/cursor-agent.ts +102 -0
  912. package/server/services/workshop/agents/dsh-agent.ts +578 -670
  913. package/server/services/workshop/agents/gemini-agent.ts +121 -0
  914. package/server/services/workshop/agents/goose-agent.ts +98 -0
  915. package/server/services/workshop/agents/harness-models.ts +305 -270
  916. package/server/services/workshop/agents/hermes-agent.ts +528 -0
  917. package/server/services/workshop/agents/host-tool-bridge.ts +53 -2
  918. package/server/services/workshop/agents/industrial-tools.ts +659 -7
  919. package/server/services/workshop/agents/omp-agent.ts +74 -59
  920. package/server/services/workshop/agents/opencode-agent.ts +936 -987
  921. package/server/services/workshop/agents/pi-agent.ts +108 -0
  922. package/server/services/workshop/agents/qwen-agent.ts +540 -0
  923. package/server/services/workshop/agents/registry.ts +117 -5
  924. package/server/services/workshop/agents/tool-approvals.ts +3 -3
  925. package/server/services/workshop/aml/aml.repo.ts +368 -0
  926. package/server/services/workshop/aml/clean.ts +120 -0
  927. package/server/services/workshop/aml/dataset-builder.ts +491 -0
  928. package/server/services/workshop/aml/gates.ts +121 -0
  929. package/server/services/workshop/aml/job-orchestrator.ts +650 -0
  930. package/server/services/workshop/aml/model-registry.ts +169 -0
  931. package/server/services/workshop/aml/predictor.ts +262 -0
  932. package/server/services/workshop/aml/python/aml_eval.py +171 -0
  933. package/server/services/workshop/aml/python/amlkit.py +120 -0
  934. package/server/services/workshop/aml/python/requirements.txt +7 -0
  935. package/server/services/workshop/aml/python/train-example.py +92 -0
  936. package/server/services/workshop/aml/python-runtime.ts +217 -0
  937. package/server/services/workshop/aml/retention.ts +98 -0
  938. package/server/services/workshop/aml/runtime.ts +45 -0
  939. package/server/services/workshop/aml/spec.ts +63 -0
  940. package/server/services/workshop/aml/stats.ts +140 -0
  941. package/server/services/workshop/daq/bus/mqtt.adapter.ts +8 -1
  942. package/server/services/workshop/daq/daq-controller.ts +147 -19
  943. package/server/services/workshop/daq/daq-node.repo.ts +13 -11
  944. package/server/services/workshop/daq/daq-runtime.ts +11 -0
  945. package/server/services/workshop/daq/drivers.ts +89 -8
  946. package/server/services/workshop/db/aml-team-seeds.ts +118 -0
  947. package/server/services/workshop/db/channel-plugins.repo.ts +27 -1
  948. package/server/services/workshop/db/database.ts +89 -1
  949. package/server/services/workshop/db/memory.repo.ts +31 -0
  950. package/server/services/workshop/db/user.repo.ts +9 -0
  951. package/server/services/workshop/dcw/dcw-controller.ts +33 -7
  952. package/server/services/workshop/dcw/dcw-line.repo.ts +5 -3
  953. package/server/services/workshop/dcw/dcw-node.repo.ts +4 -4
  954. package/server/services/workshop/dcw/dcw-product.repo.ts +8 -8
  955. package/server/services/workshop/dcw/dcw-recipe.repo.ts +6 -7
  956. package/server/services/workshop/dcw/dcw-runtime.ts +16 -2
  957. package/server/services/workshop/dcw/dcw-templates.ts +4 -4
  958. package/server/services/workshop/dcw/line-run.ts +5 -5
  959. package/server/services/workshop/dcw/recipe-rollback-manager.ts +3 -1
  960. package/server/services/workshop/dcw/recipe-rollback.repo.ts +155 -52
  961. package/server/services/workshop/logger.ts +145 -3
  962. package/server/services/workshop/plugins/host.mjs +854 -566
  963. package/server/services/workshop/prompts/loader.ts +32 -6
  964. package/server/services/workshop/runtime/agent-runtime.ts +32 -3
  965. package/server/services/workshop/runtime/manager.ts +53 -13
  966. package/server/services/workshop/runtime/scheduler-loop.ts +18 -1
  967. package/server/services/workshop/scene/scene-layout.repo.ts +5 -5
  968. package/server/services/workshop/settings.ts +64 -0
  969. package/shared/config/engine.mjs +5 -0
  970. package/shared/config/groups.mjs +220 -0
  971. package/shared/config/home.mjs +11 -2
  972. package/shared/config/schema.json +31 -6
  973. package/shared/daq-protocol.ts +6 -0
  974. package/shared/lru.mjs +94 -0
  975. package/shared/workshop-protocol.ts +2 -2
  976. package/.output/public/_nuxt/2jaJHWIJ.js +0 -1
  977. package/.output/public/_nuxt/B8kt898d.js +0 -1
  978. package/.output/public/_nuxt/BFGpEo8S.js +0 -1
  979. package/.output/public/_nuxt/BG4zduPf.js +0 -14
  980. package/.output/public/_nuxt/BHcpzI2n.js +0 -19
  981. package/.output/public/_nuxt/BWyR3awA.js +0 -1
  982. package/.output/public/_nuxt/Bc89zKq2.js +0 -1
  983. package/.output/public/_nuxt/BetmGSO4.js +0 -1
  984. package/.output/public/_nuxt/BowTbasd.js +0 -1
  985. package/.output/public/_nuxt/BvtknqSC2.js +0 -1
  986. package/.output/public/_nuxt/BytVi9VX2.js +0 -4
  987. package/.output/public/_nuxt/CJviSvm-.js +0 -1
  988. package/.output/public/_nuxt/CTfqWGdy.js +0 -1
  989. package/.output/public/_nuxt/Cb3SnTM8.js +0 -1
  990. package/.output/public/_nuxt/Chc5pfAA.js +0 -1
  991. package/.output/public/_nuxt/CobSUzQv.js +0 -2
  992. package/.output/public/_nuxt/D95h62Jn.js +0 -1
  993. package/.output/public/_nuxt/DGAOugLt.js +0 -1
  994. package/.output/public/_nuxt/DHbTyoAV.js +0 -1
  995. package/.output/public/_nuxt/DfLUN8kY.js +0 -1
  996. package/.output/public/_nuxt/DnziMlcX.js +0 -1
  997. package/.output/public/_nuxt/DvgKXPgu2.js +0 -13
  998. package/.output/public/_nuxt/Q_SJDSgx.js +0 -1
  999. package/.output/public/_nuxt/_id_.DdbYeLqn.css +0 -1
  1000. package/.output/public/_nuxt/_wsId_.BqWBlY7X.css +0 -1
  1001. package/.output/public/_nuxt/agents.CB9Ck7VQ.css +0 -1
  1002. package/.output/public/_nuxt/bFnZa2yd.js +0 -1
  1003. package/.output/public/_nuxt/builds/meta/f7a8e33d-5422-45ac-895d-27168f97e3ad.json +0 -1
  1004. package/.output/public/_nuxt/daq.DGV9QS8d.css +0 -1
  1005. package/.output/public/_nuxt/default.BbgdTDCk.css +0 -1
  1006. package/.output/public/_nuxt/entry.BN02X8iR.css +0 -1
  1007. package/.output/public/_nuxt/pages.CG8UJ2TK.css +0 -1
  1008. package/.output/public/_nuxt/plugins.DpCuwaJt.css +0 -1
  1009. package/.output/public/_nuxt/rkVgzg62.js +0 -1
  1010. package/.output/public/_nuxt/settings.W6qrYAui.css +0 -1
  1011. package/.output/public/_nuxt/teams.BBXVkyKq.css +0 -1
  1012. package/.output/server/chunks/build/_id_-3Axz2-gV.mjs.map +0 -1
  1013. package/.output/server/chunks/build/_id_-CahfkmEt.mjs.map +0 -1
  1014. package/.output/server/chunks/build/agents-DuMiSWKp.mjs.map +0 -1
  1015. package/.output/server/chunks/build/alert-qJnjyRcP.mjs.map +0 -1
  1016. package/.output/server/chunks/build/channel-templates-BStqJ-of.mjs.map +0 -1
  1017. package/.output/server/chunks/build/daq-ChYCABz1.mjs.map +0 -1
  1018. package/.output/server/chunks/build/dcw-CcQNGggh.mjs.map +0 -1
  1019. package/.output/server/chunks/build/logs-D-2UyGtE.mjs.map +0 -1
  1020. package/.output/server/chunks/build/pages-Dfosfchr.mjs.map +0 -1
  1021. package/.output/server/chunks/build/permissions-B-hhZuzm.mjs.map +0 -1
  1022. package/.output/server/chunks/build/plugins-DZR0T4Mh.mjs.map +0 -1
  1023. package/.output/server/chunks/build/responsiveObserve-CS0UB6wQ.mjs +0 -78
  1024. package/.output/server/chunks/build/responsiveObserve-CS0UB6wQ.mjs.map +0 -1
  1025. package/.output/server/chunks/build/settings-BajN9TQW.mjs.map +0 -1
  1026. package/.output/server/chunks/build/tag-NO9jEqKy.mjs.map +0 -1
  1027. package/.output/server/chunks/build/teams-t2SkRlJP.mjs.map +0 -1
  1028. package/.output/server/chunks/build/tokens-DiCojbN8.mjs.map +0 -1
  1029. package/.output/server/chunks/build/town-C7QM8DYK.mjs.map +0 -1
  1030. package/.output/server/chunks/build/useDaqStream-BeA2X8KR.mjs.map +0 -1
  1031. package/.output/server/chunks/build/useDcwStream-BJW_MitY.mjs.map +0 -1
  1032. package/.output/server/chunks/build/users-B9SAdEtH.mjs.map +0 -1
  1033. /package/.output/public/_nuxt/{ORt9oDIy.js → ORt9oDIy2.js} +0 -0
@@ -0,0 +1,1949 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * AML 自动建模平台 —— 单页五区:概览条 / 数据集快照 / 训练作业 / 实验排行榜 / 模型注册表 + 预测控制台。
4
+ * REST 快照(GET /api/workshop/aml/*)+ WS 实时帧(useAmlStream 经 townBus)双通道;
5
+ * 训练判定以平台门禁为准,页面只做诚实的状态呈现与人工晋升/取消/重试入口。
6
+ */
7
+ import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
8
+ import { message } from 'ant-design-vue'
9
+ import { useAmlStream } from '@/app/composables/workshop/useAmlStream'
10
+ import { useWorkshopWs } from '@/app/composables/workshop/useWorkshopWs'
11
+ import { useVisibleInterval } from '@/app/composables/workshop/useVisibleInterval'
12
+ import { apiFetch } from '@/app/composables/workshop/apiClient'
13
+
14
+ const { t: tt } = useI18n()
15
+
16
+ definePageMeta({ layout: 'default' })
17
+ useHead({ title: () => tt('aml.k1amlx160') })
18
+
19
+ /** 统一客户端:信封 {code,message,data} 解析取 .data(与 daq 页请求写法同源) */
20
+ function api<T>(path: string, init?: RequestInit): Promise<T> {
21
+ return apiFetch<T>({ base: '/api/workshop/aml', path, init })
22
+ }
23
+
24
+ // ---------- 类型(对齐 server/services/workshop/aml 行投影) ----------
25
+
26
+ interface AmlRuntimeStatus {
27
+ python: { ok: boolean, version?: string, reason?: string }
28
+ venvReady: boolean
29
+ queued: number
30
+ running: number
31
+ }
32
+ interface AmlOverview {
33
+ runtime: AmlRuntimeStatus
34
+ counts: { datasets: number, models: number, productions: number }
35
+ }
36
+ interface AmlDatasetRow {
37
+ id: string
38
+ lineId: string
39
+ productId: string
40
+ recipeId: string
41
+ runIds: string[]
42
+ rowCount: number
43
+ createdBy: string
44
+ createdByKind: string
45
+ note: string
46
+ createdAt: string
47
+ }
48
+ interface SeriesSummary {
49
+ nodeId: string
50
+ role: string
51
+ count: number
52
+ mean: number
53
+ std: number
54
+ min: number
55
+ max: number
56
+ missingRatio: number
57
+ cleanedRatio: number
58
+ }
59
+ interface LagEstimate { controlId: string, targetId: string, lagSteps: number, corr: number }
60
+ interface AmlDatasetReport {
61
+ builtAt: string
62
+ nodeSummaries: SeriesSummary[]
63
+ lagEstimates: LagEstimate[]
64
+ runProfiles: RunProfile[]
65
+ cleaning: Record<string, { total: number, droppedState: number, droppedRange: number, droppedHampel: number, interpolated: number, missingRatio: number }>
66
+ runsUsed: string[]
67
+ runsDropped: { runId: string, reason: string }[]
68
+ windowCount: { train: number, val: number, test: number }
69
+ }
70
+ interface PlatformMetrics {
71
+ oneStepVal?: { windows: number, nrmse: number } | null
72
+ oneStepTest?: { windows: number, nrmse: number } | null
73
+ rolloutTest?: { windows: number, nrmse: number, horizon: number } | null
74
+ }
75
+ interface AmlJobRow {
76
+ id: string
77
+ datasetId: string
78
+ purpose: string
79
+ status: string
80
+ stage: string
81
+ progress: number
82
+ metricsJson: string | null
83
+ error: string | null
84
+ retryCount: number
85
+ createdAt: string
86
+ startedAt: string | null
87
+ endedAt: string | null
88
+ }
89
+ interface GateCheck { id: string, name: string, value: number | null, threshold: number | null, pass: boolean, detail: string }
90
+ interface GateReport { passed: boolean, checks: GateCheck[] }
91
+ interface AmlExperiment {
92
+ id: string
93
+ jobId: string
94
+ datasetId: string
95
+ parentExperimentId: string | null
96
+ changeNote: string
97
+ metrics: PlatformMetrics | null
98
+ gates: GateReport | null
99
+ status: string
100
+ createdAt: string
101
+ }
102
+ type AmlModelStage = 'candidate' | 'shadow' | 'production' | 'retired'
103
+ interface IoSpec {
104
+ purpose: string
105
+ historySteps: number
106
+ horizonSteps: number
107
+ allNodes: string[]
108
+ controlNodes: string[]
109
+ targetNodes: string[]
110
+ beatMs: number
111
+ assumptions: string
112
+ }
113
+ interface AmlModelRow {
114
+ id: string
115
+ experimentId: string
116
+ datasetId: string
117
+ productId: string
118
+ recipeId: string
119
+ purpose: string
120
+ stage: AmlModelStage
121
+ ioSpec: IoSpec | null
122
+ metrics: PlatformMetrics | null
123
+ note: string
124
+ createdAt: string
125
+ }
126
+ interface PredictResult {
127
+ modelId: string
128
+ stage: string
129
+ targetNodes: string[]
130
+ forecast: number[][]
131
+ beatMs: number
132
+ assumptions: string
133
+ }
134
+
135
+ // ---------- WS 实时流(aml.job / aml.dataset / aml.model 帧;连接层即注册 scene peer) ----------
136
+
137
+ const aml = useAmlStream()
138
+ const ws = useWorkshopWs()
139
+ let unsubFeed: (() => void) | null = null
140
+ let logTimer: ReturnType<typeof setInterval> | null = null
141
+
142
+ onMounted(() => {
143
+ ws.ensureConnected()
144
+ unsubFeed = aml.ensure()
145
+ void loadOverview()
146
+ void loadDatasets()
147
+ void loadJobs()
148
+ void loadModels()
149
+ // 低频兜底轮询(WS 直推收敛状态,轮询只兜丢帧):可见性调度,后台自动降频
150
+ useVisibleInterval(() => {
151
+ void loadOverview()
152
+ void loadJobs()
153
+ }, 8000, { bgMs: 30000 })
154
+ // 展开中的活跃作业:日志尾随 5s 轮询
155
+ logTimer = setInterval(() => {
156
+ const id = expandedJob.value
157
+ if (!id || document.hidden) return
158
+ const j = jobRows.value.find(x => x.id === id)
159
+ if (j && isActiveStatus(j.status)) void refreshJobLogs(id)
160
+ }, 5000)
161
+ })
162
+ onBeforeUnmount(() => {
163
+ unsubFeed?.()
164
+ if (logTimer) clearInterval(logTimer)
165
+ })
166
+
167
+ // 作业终态帧 → 立即收敛列表(不等轮询拍);模型晋升帧 → 注册表即时刷新
168
+ watch(() => aml.lastJob.value, (f) => {
169
+ if (f && isTerminalStatus(f.status)) void loadJobs()
170
+ })
171
+ watch(() => aml.lastModel.value, () => {
172
+ void loadModels()
173
+ })
174
+ watch(() => aml.lastDataset.value, () => {
175
+ void loadDatasets()
176
+ })
177
+
178
+ // ---------- 通用小工具 ----------
179
+
180
+ function fmtTime(iso: string | null | undefined): string {
181
+ if (!iso) return '--'
182
+ const d = new Date(iso)
183
+ return Number.isFinite(d.getTime())
184
+ ? `${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
185
+ : '--'
186
+ }
187
+ function fmtNum(v: number | null | undefined, digits = 4): string {
188
+ return v == null || !Number.isFinite(v) ? '--' : String(Number(v.toFixed(digits)))
189
+ }
190
+ function fmtPct(v: number | null | undefined, digits = 1): string {
191
+ return v == null || !Number.isFinite(v) ? '--' : `${(v * 100).toFixed(digits)}%`
192
+ }
193
+ function shortId(id: string): string {
194
+ return id.length > 12 ? `${id.slice(0, 10)}…` : id
195
+ }
196
+ function isActiveStatus(s: string): boolean {
197
+ return s === 'queued' || s === 'provisioning' || s === 'training' || s === 'evaluating'
198
+ }
199
+ function isTerminalStatus(s: string): boolean {
200
+ return s === 'done' || s === 'failed' || s === 'cancelled' || s === 'timeout' || s === 'interrupted'
201
+ }
202
+ function canRetry(s: string): boolean {
203
+ return s === 'failed' || s === 'timeout' || s === 'interrupted'
204
+ }
205
+ function statusLabel(s: string): string {
206
+ const m: Record<string, string> = {
207
+ queued: 'aml.k1amlx100', provisioning: 'aml.k1amlx101', training: 'aml.k1amlx102',
208
+ evaluating: 'aml.k1amlx103', done: 'aml.k1amlx104', failed: 'aml.k1amlx105',
209
+ cancelled: 'aml.k1amlx106', timeout: 'aml.k1amlx107', interrupted: 'aml.k1amlx108',
210
+ }
211
+ return m[s] ? tt(m[s]) : s
212
+ }
213
+ function expStatusLabel(s: string): string {
214
+ const m: Record<string, string> = { running: 'aml.k1amlx119', gates_passed: 'aml.k1amlx080', gates_failed: 'aml.k1amlx081', failed: 'aml.k1amlx105' }
215
+ return m[s] ? tt(m[s]) : s
216
+ }
217
+
218
+ // ---------- 1. 概览条 ----------
219
+
220
+ const overview = ref<AmlOverview | null>(null)
221
+ const overviewError = ref('')
222
+
223
+ async function loadOverview(): Promise<void> {
224
+ try {
225
+ overview.value = await api<AmlOverview>('')
226
+ overviewError.value = ''
227
+ }
228
+ catch (err) {
229
+ overviewError.value = apiErrorMessage(err)
230
+ }
231
+ }
232
+
233
+ const pythonText = computed(() => {
234
+ const rt = overview.value?.runtime
235
+ if (!rt) return '--'
236
+ return rt.python.ok ? (rt.python.version ?? tt('aml.k1amlx004')) : tt('aml.k1amlx005')
237
+ })
238
+ const venvText = computed(() =>
239
+ overview.value ? (overview.value.runtime.venvReady ? tt('aml.k1amlx007') : tt('aml.k1amlx008')) : '--')
240
+
241
+ function reloadAll(): void {
242
+ void loadOverview()
243
+ void loadDatasets()
244
+ void loadJobs()
245
+ void loadModels()
246
+ }
247
+
248
+ // ---------- 2. 数据集快照 ----------
249
+
250
+ const datasets = ref<AmlDatasetRow[]>([])
251
+ const expandedDs = ref('')
252
+
253
+ async function loadDatasets(): Promise<void> {
254
+ try {
255
+ const data = await api<{ datasets: AmlDatasetRow[] }>('/datasets')
256
+ datasets.value = data.datasets
257
+ }
258
+ catch { /* 概览条已呈现错误,列表静默保持旧值 */ }
259
+ }
260
+
261
+ interface DsDetail { loading: boolean, error: string, report: AmlDatasetReport | null }
262
+ const dsDetails = reactive<Record<string, DsDetail>>({})
263
+
264
+ async function toggleDs(id: string): Promise<void> {
265
+ expandedDs.value = expandedDs.value === id ? '' : id
266
+ if (expandedDs.value && !dsDetails[id]) {
267
+ dsDetails[id] = { loading: true, error: '', report: null }
268
+ try {
269
+ const data = await api<{ dataset: AmlDatasetRow, report: AmlDatasetReport | null }>(`/datasets/${id}`)
270
+ dsDetails[id] = { loading: false, error: '', report: data.report }
271
+ }
272
+ catch (err) {
273
+ dsDetails[id] = { loading: false, error: apiErrorMessage(err), report: null }
274
+ }
275
+ }
276
+ }
277
+
278
+ // 新建数据集表单(spec 与 server/services/workshop/aml/spec.ts 的 zod 模式对齐)
279
+ const dsFormOpen = ref(false)
280
+ const dsSaving = ref(false)
281
+ const dsFormError = ref('')
282
+ const dsForm = reactive({
283
+ lineId: '',
284
+ productId: '',
285
+ recipeId: '',
286
+ beatMs: 5000,
287
+ historySteps: 60,
288
+ horizonSteps: 30,
289
+ valRatio: 0.15,
290
+ testRatio: 0.15,
291
+ seed: 7,
292
+ purpose: 'mpc_surrogate',
293
+ note: '',
294
+ })
295
+ const dsNodes = reactive<Array<{ nodeId: string, role: 'control' | 'feature' | 'target' }>>([
296
+ { nodeId: '', role: 'control' },
297
+ { nodeId: '', role: 'target' },
298
+ ])
299
+
300
+ function openDsForm(): void {
301
+ dsFormError.value = ''
302
+ dsFormOpen.value = true
303
+ }
304
+ function addDsNode(): void {
305
+ dsNodes.push({ nodeId: '', role: 'feature' })
306
+ }
307
+ function removeDsNode(i: number): void {
308
+ dsNodes.splice(i, 1)
309
+ }
310
+
311
+ async function submitDsForm(): Promise<void> {
312
+ dsFormError.value = ''
313
+ const nodes = dsNodes.filter(n => n.nodeId.trim()).map(n => ({ nodeId: n.nodeId.trim(), role: n.role }))
314
+ if (!dsForm.lineId.trim() || !dsForm.productId.trim() || !dsForm.recipeId.trim()) {
315
+ dsFormError.value = tt('aml.k1amlx161')
316
+ return
317
+ }
318
+ if (nodes.length < 2 || !nodes.some(n => n.role === 'target')) {
319
+ dsFormError.value = tt('aml.k1amlx054')
320
+ return
321
+ }
322
+ dsSaving.value = true
323
+ try {
324
+ const data = await api<{ dataset: AmlDatasetRow, report: AmlDatasetReport | null }>('/datasets', {
325
+ method: 'POST',
326
+ body: JSON.stringify({
327
+ lineId: dsForm.lineId.trim(),
328
+ productId: dsForm.productId.trim(),
329
+ recipeId: dsForm.recipeId.trim(),
330
+ nodes,
331
+ beatMs: Number(dsForm.beatMs),
332
+ window: { historySteps: Number(dsForm.historySteps), horizonSteps: Number(dsForm.horizonSteps) },
333
+ split: { valRatio: Number(dsForm.valRatio), testRatio: Number(dsForm.testRatio), seed: Number(dsForm.seed) },
334
+ purpose: dsForm.purpose,
335
+ note: dsForm.note.trim() || undefined,
336
+ }),
337
+ })
338
+ message.success(tt('aml.k1amlx073', { p0: shortId(data.dataset.id), p1: data.dataset.rowCount }))
339
+ dsFormOpen.value = false
340
+ await loadDatasets()
341
+ }
342
+ catch (err) {
343
+ dsFormError.value = apiErrorMessage(err)
344
+ }
345
+ finally {
346
+ dsSaving.value = false
347
+ }
348
+ }
349
+
350
+ // ---------- 3. 训练作业(REST 快照 + WS 实时投影合并) ----------
351
+
352
+ const jobs = ref<AmlJobRow[]>([])
353
+
354
+ async function loadJobs(): Promise<void> {
355
+ try {
356
+ const data = await api<{ jobs: AmlJobRow[] }>('/jobs')
357
+ jobs.value = data.jobs
358
+ }
359
+ catch { /* 同上:静默保旧值 */ }
360
+ }
361
+
362
+ /** WS 实时投影覆盖 status/stage/progress(帧权威,REST 兜底) */
363
+ const jobRows = computed<Array<AmlJobRow & { live?: boolean }>>(() =>
364
+ jobs.value.map((j) => {
365
+ const live = aml.jobs.value.get(j.id)
366
+ if (!live) return j
367
+ return { ...j, status: live.status || j.status, stage: live.stage || j.stage, progress: live.progress ?? j.progress, live: true }
368
+ }))
369
+
370
+ interface JobDetail { loading: boolean, error: string, metrics: PlatformMetrics | null, gates: GateReport | null, logs: string[] }
371
+ const jobDetails = reactive<Record<string, JobDetail>>({})
372
+ const expandedJob = ref('')
373
+
374
+ async function fetchJobLogs(id: string): Promise<string[]> {
375
+ const data = await api<{ logs: string[] }>(`/jobs/${id}/logs?lines=120`)
376
+ return data.logs
377
+ }
378
+
379
+ async function toggleJob(id: string): Promise<void> {
380
+ expandedJob.value = expandedJob.value === id ? '' : id
381
+ if (expandedJob.value && !jobDetails[id]) {
382
+ jobDetails[id] = { loading: true, error: '', metrics: null, gates: null, logs: [] }
383
+ try {
384
+ const [detail, logs] = await Promise.all([
385
+ api<{ job: AmlJobRow, metrics: PlatformMetrics | null, gates: GateReport | null }>(`/jobs/${id}`),
386
+ fetchJobLogs(id),
387
+ ])
388
+ jobDetails[id] = { loading: false, error: '', metrics: detail.metrics, gates: detail.gates, logs }
389
+ }
390
+ catch (err) {
391
+ jobDetails[id] = { loading: false, error: apiErrorMessage(err), metrics: null, gates: null, logs: [] }
392
+ }
393
+ }
394
+ }
395
+
396
+ /** 活跃作业 5s 轮询尾随日志(仅刷新日志,不重拉门禁) */
397
+ async function refreshJobLogs(id: string): Promise<void> {
398
+ const d = jobDetails[id]
399
+ if (!d) return
400
+ try {
401
+ d.logs = await fetchJobLogs(id)
402
+ }
403
+ catch { /* 轮询失败静默,下一拍再试 */ }
404
+ }
405
+
406
+ const confirmCancel = ref('')
407
+ const cancelling = ref('')
408
+
409
+ async function onCancelJob(id: string): Promise<void> {
410
+ if (confirmCancel.value !== id) {
411
+ confirmCancel.value = id
412
+ return
413
+ }
414
+ confirmCancel.value = ''
415
+ cancelling.value = id
416
+ try {
417
+ await api(`/jobs/${id}/cancel`, { method: 'POST', body: JSON.stringify({}) })
418
+ message.success(tt('aml.k1amlx097', { p0: shortId(id) }))
419
+ await loadJobs()
420
+ }
421
+ catch (err) {
422
+ message.error(apiErrorMessage(err))
423
+ }
424
+ finally {
425
+ cancelling.value = ''
426
+ }
427
+ }
428
+
429
+ const confirmRetry = ref('')
430
+ const retrying = ref('')
431
+
432
+ async function onRetryJob(id: string): Promise<void> {
433
+ if (confirmRetry.value !== id) {
434
+ confirmRetry.value = id
435
+ return
436
+ }
437
+ confirmRetry.value = ''
438
+ retrying.value = id
439
+ try {
440
+ await api(`/jobs/${id}/retry`, { method: 'POST', body: JSON.stringify({}) })
441
+ message.success(tt('aml.k1amlx098', { p0: shortId(id) }))
442
+ await loadJobs()
443
+ }
444
+ catch (err) {
445
+ message.error(apiErrorMessage(err))
446
+ }
447
+ finally {
448
+ retrying.value = ''
449
+ }
450
+ }
451
+
452
+ // ---------- 4. 实验排行榜(选数据集 → 谱系 + 门禁) ----------
453
+
454
+ const expDatasetId = ref('')
455
+ const experiments = ref<AmlExperiment[]>([])
456
+ const expLoading = ref(false)
457
+ const expError = ref('')
458
+
459
+ async function loadExperiments(): Promise<void> {
460
+ if (!expDatasetId.value) {
461
+ experiments.value = []
462
+ return
463
+ }
464
+ expLoading.value = true
465
+ expError.value = ''
466
+ try {
467
+ const data = await api<{ experiments: AmlExperiment[] }>(`/experiments?datasetId=${encodeURIComponent(expDatasetId.value)}`)
468
+ experiments.value = data.experiments
469
+ }
470
+ catch (err) {
471
+ expError.value = apiErrorMessage(err)
472
+ }
473
+ finally {
474
+ expLoading.value = false
475
+ }
476
+ }
477
+
478
+ /** 最优行:门禁通过且测试集单步 NRMSE 最小 */
479
+ const bestExpId = computed(() => {
480
+ let best: { id: string, nrmse: number } | null = null
481
+ for (const e of experiments.value) {
482
+ const n = e.metrics?.oneStepTest?.nrmse
483
+ if (e.status === 'gates_passed' && n != null && Number.isFinite(n) && (best == null || n < best.nrmse))
484
+ best = { id: e.id, nrmse: n }
485
+ }
486
+ return best?.id ?? ''
487
+ })
488
+
489
+ // ---------- 5. 模型注册表 + 预测控制台 ----------
490
+
491
+ const models = ref<AmlModelRow[]>([])
492
+
493
+ async function loadModels(): Promise<void> {
494
+ try {
495
+ const data = await api<{ models: AmlModelRow[] }>('/models')
496
+ models.value = data.models
497
+ }
498
+ catch { /* 静默保旧值 */ }
499
+ }
500
+
501
+ const confirmPromote = ref('')
502
+ const promoting = ref('')
503
+
504
+ function promoteActionOf(m: AmlModelRow): Array<{ to: Exclude<AmlModelStage, 'candidate'>, key: string }> {
505
+ if (m.stage === 'candidate') return [{ to: 'shadow', key: 'aml.k1amlx128' }, { to: 'production', key: 'aml.k1amlx129' }]
506
+ if (m.stage === 'shadow') return [{ to: 'production', key: 'aml.k1amlx129' }, { to: 'retired', key: 'aml.k1amlx130' }]
507
+ if (m.stage === 'production') return [{ to: 'retired', key: 'aml.k1amlx130' }]
508
+ return []
509
+ }
510
+
511
+ async function onPromote(m: AmlModelRow, to: Exclude<AmlModelStage, 'candidate'>): Promise<void> {
512
+ const key = `${m.id}:${to}`
513
+ if (confirmPromote.value !== key) {
514
+ confirmPromote.value = key
515
+ return
516
+ }
517
+ confirmPromote.value = ''
518
+ promoting.value = key
519
+ try {
520
+ const r = await api<{ ok: boolean, from?: AmlModelStage, retiredId?: string }>(`/models/${m.id}/promote`, {
521
+ method: 'POST',
522
+ body: JSON.stringify({ toStage: to }),
523
+ })
524
+ if (r.ok) message.success(tt('aml.k1amlx132', { p0: r.from ?? m.stage, p1: to }))
525
+ await Promise.all([loadModels(), loadOverview()])
526
+ }
527
+ catch (err) {
528
+ message.error(apiErrorMessage(err))
529
+ }
530
+ finally {
531
+ promoting.value = ''
532
+ }
533
+ }
534
+
535
+ // 预测控制台:production 模型 → ioSpec → history JSON 粘贴 → forecast 表
536
+ const productionModels = computed(() => models.value.filter(m => m.stage === 'production'))
537
+ const predModelId = ref('')
538
+ const predModel = computed(() => models.value.find(m => m.id === predModelId.value) ?? null)
539
+ const predHistory = ref('')
540
+ const predControls = ref('')
541
+ const predSteps = ref<number | null>(null)
542
+ const predBusy = ref(false)
543
+ const predError = ref('')
544
+ const predResult = ref<PredictResult | null>(null)
545
+
546
+ function onPullLatest(): void {
547
+ // 页面暂不内联拉数:引导用户走 Agent 工具取数(与任务口径一致)
548
+ message.info(tt('aml.k1amlx146'))
549
+ }
550
+
551
+ function parseMatrix(text: string): number[][] | null {
552
+ const t = text.trim()
553
+ if (!t) return null
554
+ try {
555
+ const v: unknown = JSON.parse(t)
556
+ if (!Array.isArray(v) || v.length === 0) return null
557
+ const ok = v.every(r => Array.isArray(r) && r.length > 0 && r.every(x => typeof x === 'number' && Number.isFinite(x)))
558
+ return ok ? (v as number[][]) : null
559
+ }
560
+ catch {
561
+ return null
562
+ }
563
+ }
564
+
565
+ async function doPredict(): Promise<void> {
566
+ predError.value = ''
567
+ predResult.value = null
568
+ const model = predModel.value
569
+ if (!model) return
570
+ const history = parseMatrix(predHistory.value)
571
+ if (!history) {
572
+ predError.value = tt('aml.k1amlx153')
573
+ return
574
+ }
575
+ const controls = predControls.value.trim() ? parseMatrix(predControls.value) : undefined
576
+ if (predControls.value.trim() && !controls) {
577
+ predError.value = tt('aml.k1amlx153')
578
+ return
579
+ }
580
+ predBusy.value = true
581
+ try {
582
+ const steps = typeof predSteps.value === 'number' && Number.isFinite(predSteps.value) ? predSteps.value : undefined
583
+ const data = await api<{ prediction: PredictResult }>(`/models/${model.id}/predict`, {
584
+ method: 'POST',
585
+ body: JSON.stringify({ history, controls, steps }),
586
+ })
587
+ predResult.value = data.prediction
588
+ message.success(tt('aml.k1amlx154', { p0: data.prediction.forecast.length, p1: data.prediction.targetNodes.length }))
589
+ }
590
+ catch (err) {
591
+ predError.value = apiErrorMessage(err)
592
+ }
593
+ finally {
594
+ predBusy.value = false
595
+ }
596
+ }
597
+ </script>
598
+
599
+ <template>
600
+ <div class="page">
601
+ <div class="aw-page-head">
602
+ <div>
603
+ <p class="aw-kicker">
604
+ AGENTWORKSHOP / AML STUDIO
605
+ </p>
606
+ <h1>{{ $t('aml.k1amlx001') }}</h1>
607
+ <p class="sub">
608
+ {{ $t('aml.k1amlx002') }}
609
+ </p>
610
+ </div>
611
+ <div class="badges mono">
612
+ <span
613
+ class="badge"
614
+ :class="{ bad: overview != null && !overview.runtime.python.ok }"
615
+ :title="overview?.runtime.python.reason ?? ''"
616
+ >PYTHON · {{ pythonText }}</span>
617
+ <span
618
+ class="badge"
619
+ :class="{ bad: overview != null && !overview.runtime.venvReady }"
620
+ >VENV · {{ venvText }}</span>
621
+ </div>
622
+ </div>
623
+
624
+ <!-- 1. 概览条:Python 运行时 / 依赖环境 / 队列 / 计数;不 ok 给醒目提示条 -->
625
+ <div
626
+ v-if="overview != null && !overview.runtime.python.ok"
627
+ class="infra-banner"
628
+ >
629
+ <span class="i-tabler-alert-triangle" />
630
+ <span class="txt">{{ $t('aml.k1amlx014') }}<b class="mono">{{ overview.runtime.python.reason ?? '' }}</b></span>
631
+ </div>
632
+ <section
633
+ v-if="overview"
634
+ class="aw-tile ov-card"
635
+ >
636
+ <div class="ov-row mono">
637
+ <span
638
+ class="ov-item"
639
+ :class="overview.runtime.python.ok ? 'ok' : 'bad'"
640
+ >
641
+ <span :class="overview.runtime.python.ok ? 'i-tabler-circle-check' : 'i-tabler-alert-triangle'" />
642
+ {{ $t('aml.k1amlx003') }} · {{ pythonText }}
643
+ </span>
644
+ <span
645
+ class="ov-item"
646
+ :class="{ ok: overview.runtime.venvReady }"
647
+ >{{ $t('aml.k1amlx006') }} · {{ venvText }}</span>
648
+ <span class="ov-item">{{ $t('aml.k1amlx009') }} <b>{{ overview.runtime.queued }}</b></span>
649
+ <span class="ov-item">{{ $t('aml.k1amlx010') }} <b>{{ overview.runtime.running }}</b></span>
650
+ <span class="sep">·</span>
651
+ <span class="ov-item">{{ $t('aml.k1amlx011') }} <b>{{ overview.counts.datasets }}</b></span>
652
+ <span class="ov-item">{{ $t('aml.k1amlx012') }} <b>{{ overview.counts.models }}</b></span>
653
+ <span
654
+ class="ov-item accent"
655
+ :title="$t('aml.k1amlx013')"
656
+ >{{ $t('aml.k1amlx013') }} <b>{{ overview.counts.productions }}</b></span>
657
+ <button
658
+ class="mini-btn reload"
659
+ @click="reloadAll"
660
+ >
661
+ {{ $t('aml.k1amlx017') }}
662
+ </button>
663
+ </div>
664
+ </section>
665
+ <p
666
+ v-else-if="overviewError"
667
+ class="err"
668
+ >
669
+ {{ $t('aml.k1amlx015') }}:{{ overviewError }}
670
+ </p>
671
+
672
+ <!-- 2. 数据集快照:注册表 + 行内展开(清洗报告/滞后估计/run 概览)+ 新建 -->
673
+ <section class="aw-tile zone">
674
+ <div class="zone-head">
675
+ <h2>
676
+ <span class="i-tabler-database" />
677
+ {{ $t('aml.k1amlx016') }}
678
+ <b class="mono cnt">{{ datasets.length }}</b>
679
+ </h2>
680
+ <div class="zone-actions">
681
+ <button
682
+ class="mini-btn"
683
+ @click="loadDatasets()"
684
+ >
685
+ {{ $t('aml.k1amlx017') }}
686
+ </button>
687
+ <button
688
+ class="pill-btn"
689
+ @click="openDsForm"
690
+ >
691
+ <span class="i-tabler-plus" />
692
+ {{ $t('aml.k1amlx018') }}
693
+ </button>
694
+ </div>
695
+ </div>
696
+ <table
697
+ v-if="datasets.length"
698
+ class="tbl"
699
+ >
700
+ <thead>
701
+ <tr>
702
+ <th>{{ $t('aml.k1amlx020') }}</th>
703
+ <th>{{ $t('aml.k1amlx021') }}</th>
704
+ <th>{{ $t('aml.k1amlx022') }}</th>
705
+ <th class="num">
706
+ {{ $t('aml.k1amlx023') }}
707
+ </th>
708
+ <th class="num">
709
+ {{ $t('aml.k1amlx024') }}
710
+ </th>
711
+ <th>{{ $t('aml.k1amlx025') }}</th>
712
+ <th>{{ $t('aml.k1amlx026') }}</th>
713
+ </tr>
714
+ </thead>
715
+ <tbody>
716
+ <template
717
+ v-for="d in datasets"
718
+ :key="d.id"
719
+ >
720
+ <tr
721
+ class="row-main"
722
+ :class="{ open: expandedDs === d.id }"
723
+ @click="toggleDs(d.id)"
724
+ >
725
+ <td class="mono dim">
726
+ {{ fmtTime(d.createdAt) }}
727
+ </td>
728
+ <td class="mono">
729
+ {{ shortId(d.productId) }}
730
+ </td>
731
+ <td class="mono">
732
+ {{ shortId(d.recipeId) }}
733
+ </td>
734
+ <td class="mono num">
735
+ {{ d.rowCount }}
736
+ </td>
737
+ <td class="mono num">
738
+ {{ d.runIds.length }}
739
+ </td>
740
+ <td>
741
+ {{ d.createdBy }}<small
742
+ class="kind"
743
+ :class="d.createdByKind"
744
+ >{{ d.createdByKind === 'agent' ? 'Agent' : $t('aml.k1amlx049') }}</small>
745
+ </td>
746
+ <td class="note-cell">
747
+ <span
748
+ class="note"
749
+ :title="d.note"
750
+ >{{ d.note || '--' }}</span>
751
+ </td>
752
+ </tr>
753
+ <tr
754
+ v-if="expandedDs === d.id"
755
+ class="detail-row"
756
+ >
757
+ <td colspan="7">
758
+ <div
759
+ v-if="dsDetails[d.id]?.loading"
760
+ class="dim pad"
761
+ >
762
+ {{ $t('aml.k1amlx030') }}
763
+ </div>
764
+ <div
765
+ v-else-if="dsDetails[d.id]?.error"
766
+ class="err pad"
767
+ >
768
+ {{ $t('aml.k1amlx031') }}:{{ dsDetails[d.id]?.error }}
769
+ </div>
770
+ <div
771
+ v-else-if="dsDetails[d.id]?.report"
772
+ class="det-grid"
773
+ >
774
+ <div>
775
+ <p class="det-title">
776
+ {{ $t('aml.k1amlx027') }}
777
+ </p>
778
+ <table class="sub-tbl">
779
+ <thead>
780
+ <tr>
781
+ <th>{{ $t('aml.k1amlx033') }}</th>
782
+ <th>{{ $t('aml.k1amlx034') }}</th>
783
+ <th class="num">
784
+ {{ $t('aml.k1amlx035') }}
785
+ </th>
786
+ <th class="num">
787
+ {{ $t('aml.k1amlx036') }}
788
+ </th>
789
+ <th class="num">
790
+ {{ $t('aml.k1amlx037') }}
791
+ </th>
792
+ <th class="num">
793
+ {{ $t('aml.k1amlx038') }}
794
+ </th>
795
+ <th class="num">
796
+ {{ $t('aml.k1amlx039') }}
797
+ </th>
798
+ </tr>
799
+ </thead>
800
+ <tbody>
801
+ <tr
802
+ v-for="s in dsDetails[d.id]?.report?.nodeSummaries"
803
+ :key="s.nodeId"
804
+ >
805
+ <td class="mono">
806
+ {{ s.nodeId }}
807
+ </td>
808
+ <td>
809
+ <small class="role-chip">{{ s.role }}</small>
810
+ </td>
811
+ <td class="mono num">
812
+ {{ fmtPct(s.cleanedRatio) }}
813
+ </td>
814
+ <td class="mono num">
815
+ {{ fmtPct(s.missingRatio) }}
816
+ </td>
817
+ <td class="mono num">
818
+ {{ fmtNum(s.mean, 3) }}
819
+ </td>
820
+ <td class="mono num">
821
+ {{ fmtNum(s.std, 3) }}
822
+ </td>
823
+ <td class="mono num">
824
+ {{ fmtNum(s.min, 2) }}~{{ fmtNum(s.max, 2) }}
825
+ </td>
826
+ </tr>
827
+ </tbody>
828
+ </table>
829
+ </div>
830
+ <div>
831
+ <p class="det-title">
832
+ {{ $t('aml.k1amlx028') }}
833
+ </p>
834
+ <table
835
+ v-if="dsDetails[d.id]?.report?.lagEstimates.length"
836
+ class="sub-tbl"
837
+ >
838
+ <thead>
839
+ <tr>
840
+ <th>{{ $t('aml.k1amlx040') }}</th>
841
+ <th>{{ $t('aml.k1amlx041') }}</th>
842
+ <th class="num">
843
+ {{ $t('aml.k1amlx042') }}
844
+ </th>
845
+ <th class="num">
846
+ {{ $t('aml.k1amlx043') }}
847
+ </th>
848
+ </tr>
849
+ </thead>
850
+ <tbody>
851
+ <tr
852
+ v-for="l in dsDetails[d.id]?.report?.lagEstimates"
853
+ :key="`${l.controlId}->${l.targetId}`"
854
+ >
855
+ <td class="mono">
856
+ {{ l.controlId }}
857
+ </td>
858
+ <td class="mono">
859
+ {{ l.targetId }}
860
+ </td>
861
+ <td class="mono num">
862
+ {{ l.lagSteps }}
863
+ </td>
864
+ <td class="mono num">
865
+ {{ fmtNum(l.corr, 3) }}
866
+ </td>
867
+ </tr>
868
+ </tbody>
869
+ </table>
870
+ <p
871
+ v-else
872
+ class="dim"
873
+ >
874
+ {{ $t('aml.k1amlx032') }}
875
+ </p>
876
+ <p class="det-title">
877
+ {{ $t('aml.k1amlx029') }}
878
+ </p>
879
+ <p class="mono dim run-line">
880
+ {{ $t('aml.k1amlx044') }}
881
+ <b>{{ dsDetails[d.id]?.report?.runsUsed.length ?? 0 }}</b>
882
+ · {{ $t('aml.k1amlx045') }}
883
+ <b>{{ dsDetails[d.id]?.report?.runsDropped.length ?? 0 }}</b>
884
+ · {{ $t('aml.k1amlx046') }}
885
+ <b>{{ dsDetails[d.id]?.report?.windowCount.train }}/{{ dsDetails[d.id]?.report?.windowCount.val }}/{{ dsDetails[d.id]?.report?.windowCount.test }}</b>
886
+ </p>
887
+ <p
888
+ v-for="r in dsDetails[d.id]?.report?.runsDropped"
889
+ :key="r.runId"
890
+ class="mono drop-line"
891
+ >
892
+ ✗ {{ shortId(r.runId) }} — {{ r.reason }}
893
+ </p>
894
+ </div>
895
+ </div>
896
+ <p
897
+ v-else
898
+ class="dim pad"
899
+ >
900
+ {{ $t('aml.k1amlx047') }}
901
+ </p>
902
+ </td>
903
+ </tr>
904
+ </template>
905
+ </tbody>
906
+ </table>
907
+ <p
908
+ v-else
909
+ class="empty"
910
+ >
911
+ {{ $t('aml.k1amlx019') }}
912
+ </p>
913
+ </section>
914
+
915
+ <!-- 3. 训练作业:REST 快照 + WS 实时进度;展开 = 门禁逐项 + 日志尾随(活跃 5s 轮询) -->
916
+ <section class="aw-tile zone">
917
+ <div class="zone-head">
918
+ <h2>
919
+ <span class="i-tabler-brain" />
920
+ {{ $t('aml.k1amlx074') }}
921
+ <b class="mono cnt">{{ jobRows.length }}</b>
922
+ <span
923
+ v-if="jobRows.some(j => isActiveStatus(j.status))"
924
+ class="live-dot"
925
+ :title="$t('aml.k1amlx091')"
926
+ />
927
+ </h2>
928
+ <button
929
+ class="mini-btn"
930
+ @click="loadJobs()"
931
+ >
932
+ {{ $t('aml.k1amlx017') }}
933
+ </button>
934
+ </div>
935
+ <table
936
+ v-if="jobRows.length"
937
+ class="tbl"
938
+ >
939
+ <thead>
940
+ <tr>
941
+ <th>{{ $t('aml.k1amlx076') }}</th>
942
+ <th>{{ $t('aml.k1amlx011') }}</th>
943
+ <th>{{ $t('aml.k1amlx066') }}</th>
944
+ <th>{{ $t('aml.k1amlx077') }}</th>
945
+ <th>{{ $t('aml.k1amlx078') }}</th>
946
+ <th class="prog-th">
947
+ {{ $t('aml.k1amlx079') }}
948
+ </th>
949
+ <th>{{ $t('aml.k1amlx020') }}</th>
950
+ <th class="right">
951
+ {{ $t('aml.k1amlx127') }}
952
+ </th>
953
+ </tr>
954
+ </thead>
955
+ <tbody>
956
+ <template
957
+ v-for="j in jobRows"
958
+ :key="j.id"
959
+ >
960
+ <tr
961
+ class="row-main"
962
+ :class="{ open: expandedJob === j.id }"
963
+ @click="toggleJob(j.id)"
964
+ >
965
+ <td class="mono">
966
+ {{ shortId(j.id) }}
967
+ </td>
968
+ <td class="mono dim">
969
+ {{ shortId(j.datasetId) }}
970
+ </td>
971
+ <td class="mono dim">
972
+ {{ j.purpose }}
973
+ </td>
974
+ <td>
975
+ <span
976
+ class="st-pill"
977
+ :class="j.status"
978
+ >{{ statusLabel(j.status) }}</span>
979
+ </td>
980
+ <td class="mono dim">
981
+ {{ j.stage || '--' }}
982
+ </td>
983
+ <td class="prog-cell">
984
+ <span class="prog"><i
985
+ :style="{ width: `${Math.max(0, Math.min(100, j.progress))}%` }"
986
+ :class="{ done: j.status === 'done', bad: j.status === 'failed' }"
987
+ /></span>
988
+ <span class="mono prog-num">{{ Math.round(j.progress) }}%</span>
989
+ </td>
990
+ <td class="mono dim">
991
+ {{ fmtTime(j.createdAt) }}
992
+ </td>
993
+ <td class="right acts">
994
+ <button
995
+ v-if="isActiveStatus(j.status)"
996
+ class="mini-btn danger"
997
+ :disabled="cancelling === j.id"
998
+ @click.stop="onCancelJob(j.id)"
999
+ >
1000
+ {{ confirmCancel === j.id ? $t('aml.k1amlx094') : (cancelling === j.id ? $t('aml.k1amlx093') : $t('aml.k1amlx071')) }}
1001
+ </button>
1002
+ <button
1003
+ v-if="canRetry(j.status)"
1004
+ class="mini-btn"
1005
+ :disabled="retrying === j.id"
1006
+ @click.stop="onRetryJob(j.id)"
1007
+ >
1008
+ {{ confirmRetry === j.id ? $t('aml.k1amlx096') : $t('aml.k1amlx095') }}
1009
+ </button>
1010
+ </td>
1011
+ </tr>
1012
+ <tr
1013
+ v-if="expandedJob === j.id"
1014
+ class="detail-row"
1015
+ >
1016
+ <td colspan="8">
1017
+ <div
1018
+ v-if="jobDetails[j.id]?.loading"
1019
+ class="dim pad"
1020
+ >
1021
+ {{ $t('aml.k1amlx030') }}
1022
+ </div>
1023
+ <div
1024
+ v-else-if="jobDetails[j.id]?.error"
1025
+ class="err pad"
1026
+ >
1027
+ {{ jobDetails[j.id]?.error }}
1028
+ </div>
1029
+ <div
1030
+ v-else
1031
+ class="det-grid"
1032
+ >
1033
+ <div>
1034
+ <p class="det-title">
1035
+ {{ $t('aml.k1amlx083') }}
1036
+ </p>
1037
+ <table
1038
+ v-if="jobDetails[j.id]?.gates?.checks.length"
1039
+ class="sub-tbl"
1040
+ >
1041
+ <thead>
1042
+ <tr>
1043
+ <th>{{ $t('aml.k1amlx084') }}</th>
1044
+ <th class="num">
1045
+ {{ $t('aml.k1amlx085') }}
1046
+ </th>
1047
+ <th class="num">
1048
+ {{ $t('aml.k1amlx086') }}
1049
+ </th>
1050
+ <th>{{ $t('aml.k1amlx118') }}</th>
1051
+ </tr>
1052
+ </thead>
1053
+ <tbody>
1054
+ <tr
1055
+ v-for="g in jobDetails[j.id]?.gates?.checks"
1056
+ :key="g.id"
1057
+ >
1058
+ <td>
1059
+ <b class="mono gate-id">{{ g.id }}</b>
1060
+ <small class="dim"> {{ g.name }}</small>
1061
+ </td>
1062
+ <td class="mono num">
1063
+ {{ fmtNum(g.value) }}
1064
+ </td>
1065
+ <td class="mono num dim">
1066
+ {{ fmtNum(g.threshold) }}
1067
+ </td>
1068
+ <td>
1069
+ <span
1070
+ class="verdict"
1071
+ :class="g.pass ? 'pass' : 'fail'"
1072
+ >{{ g.pass ? $t('aml.k1amlx087') : $t('aml.k1amlx088') }}</span>
1073
+ <small class="dim gate-detail">{{ g.detail }}</small>
1074
+ </td>
1075
+ </tr>
1076
+ </tbody>
1077
+ </table>
1078
+ <p
1079
+ v-else
1080
+ class="dim"
1081
+ >
1082
+ {{ $t('aml.k1amlx082') }}
1083
+ </p>
1084
+ <p
1085
+ v-if="jobDetails[j.id]?.metrics?.oneStepTest"
1086
+ class="mono dim gate-detail"
1087
+ >
1088
+ {{ $t('aml.k1amlx099') }}: {{ $t('aml.k1amlx116') }} {{ fmtNum(jobDetails[j.id]?.metrics?.oneStepTest?.nrmse) }}
1089
+ <template v-if="jobDetails[j.id]?.metrics?.rolloutTest">
1090
+ · {{ $t('aml.k1amlx117') }} {{ fmtNum(jobDetails[j.id]?.metrics?.rolloutTest?.nrmse) }}
1091
+ </template>
1092
+ </p>
1093
+ <p
1094
+ v-if="j.error"
1095
+ class="err gate-detail"
1096
+ >
1097
+ {{ $t('aml.k1amlx092') }}:{{ j.error }}
1098
+ </p>
1099
+ </div>
1100
+ <div>
1101
+ <p class="det-title">
1102
+ {{ $t('aml.k1amlx089') }}
1103
+ <span
1104
+ v-if="isActiveStatus(j.status)"
1105
+ class="mono live-hint"
1106
+ >{{ $t('aml.k1amlx091') }}</span>
1107
+ </p>
1108
+ <pre class="logs">{{ (jobDetails[j.id]?.logs ?? []).join('\n') || $t('aml.k1amlx090') }}</pre>
1109
+ </div>
1110
+ </div>
1111
+ </td>
1112
+ </tr>
1113
+ </template>
1114
+ </tbody>
1115
+ </table>
1116
+ <p
1117
+ v-else
1118
+ class="empty"
1119
+ >
1120
+ {{ $t('aml.k1amlx075') }}
1121
+ </p>
1122
+ </section>
1123
+
1124
+ <!-- 4. 实验排行榜:选数据集 → 谱系表(变更说明/父实验/G1/G2/门禁态),最优行高亮 -->
1125
+ <section class="aw-tile zone">
1126
+ <div class="zone-head">
1127
+ <h2>
1128
+ <span class="i-tabler-trophy" />
1129
+ {{ $t('aml.k1amlx109') }}
1130
+ <b class="mono cnt">{{ experiments.length }}</b>
1131
+ </h2>
1132
+ <div class="zone-actions">
1133
+ <select
1134
+ v-model="expDatasetId"
1135
+ class="inp-sel"
1136
+ @change="loadExperiments"
1137
+ >
1138
+ <option value="">
1139
+ {{ $t('aml.k1amlx111') }}
1140
+ </option>
1141
+ <option
1142
+ v-for="d in datasets"
1143
+ :key="d.id"
1144
+ :value="d.id"
1145
+ >
1146
+ {{ shortId(d.id) }} · {{ shortId(d.recipeId) }}
1147
+ </option>
1148
+ </select>
1149
+ <button
1150
+ class="mini-btn"
1151
+ :disabled="!expDatasetId"
1152
+ @click="loadExperiments"
1153
+ >
1154
+ {{ $t('aml.k1amlx017') }}
1155
+ </button>
1156
+ </div>
1157
+ </div>
1158
+ <table
1159
+ v-if="experiments.length"
1160
+ class="tbl"
1161
+ >
1162
+ <thead>
1163
+ <tr>
1164
+ <th>{{ $t('aml.k1amlx113') }}</th>
1165
+ <th>{{ $t('aml.k1amlx020') }}</th>
1166
+ <th>{{ $t('aml.k1amlx114') }}</th>
1167
+ <th>{{ $t('aml.k1amlx115') }}</th>
1168
+ <th
1169
+ class="num"
1170
+ :title="$t('aml.k1amlx121')"
1171
+ >
1172
+ {{ $t('aml.k1amlx116') }}
1173
+ </th>
1174
+ <th
1175
+ class="num"
1176
+ :title="$t('aml.k1amlx122')"
1177
+ >
1178
+ {{ $t('aml.k1amlx117') }}
1179
+ </th>
1180
+ <th>{{ $t('aml.k1amlx118') }}</th>
1181
+ </tr>
1182
+ </thead>
1183
+ <tbody>
1184
+ <tr
1185
+ v-for="e in experiments"
1186
+ :key="e.id"
1187
+ :class="{ best: e.id === bestExpId }"
1188
+ >
1189
+ <td class="mono">
1190
+ <span
1191
+ v-if="e.id === bestExpId"
1192
+ class="best-tag"
1193
+ >{{ $t('aml.k1amlx120') }}</span>
1194
+ {{ shortId(e.id) }}
1195
+ </td>
1196
+ <td class="mono dim">
1197
+ {{ fmtTime(e.createdAt) }}
1198
+ </td>
1199
+ <td class="note-cell">
1200
+ <span
1201
+ class="note"
1202
+ :title="e.changeNote"
1203
+ >{{ e.changeNote || '--' }}</span>
1204
+ </td>
1205
+ <td class="mono dim">
1206
+ {{ e.parentExperimentId ? shortId(e.parentExperimentId) : '--' }}
1207
+ </td>
1208
+ <td class="mono num">
1209
+ {{ fmtNum(e.metrics?.oneStepTest?.nrmse) }}
1210
+ </td>
1211
+ <td class="mono num">
1212
+ {{ fmtNum(e.metrics?.rolloutTest?.nrmse) }}
1213
+ </td>
1214
+ <td>
1215
+ <span
1216
+ class="st-pill"
1217
+ :class="e.status"
1218
+ >{{ expStatusLabel(e.status) }}</span>
1219
+ </td>
1220
+ </tr>
1221
+ </tbody>
1222
+ </table>
1223
+ <p
1224
+ v-else
1225
+ class="empty"
1226
+ >
1227
+ {{ expDatasetId ? $t('aml.k1amlx112') : $t('aml.k1amlx110') }}
1228
+ </p>
1229
+ <p
1230
+ v-if="expError"
1231
+ class="err pad"
1232
+ >
1233
+ {{ expError }}
1234
+ </p>
1235
+ </section>
1236
+
1237
+ <!-- 5. 模型注册表:阶段徽标 + 指标 + 两段确认晋升 -->
1238
+ <section class="aw-tile zone">
1239
+ <div class="zone-head">
1240
+ <h2>
1241
+ <span class="i-tabler-cube-3d-sphere" />
1242
+ {{ $t('aml.k1amlx123') }}
1243
+ <b class="mono cnt">{{ models.length }}</b>
1244
+ </h2>
1245
+ <button
1246
+ class="mini-btn"
1247
+ @click="loadModels()"
1248
+ >
1249
+ {{ $t('aml.k1amlx017') }}
1250
+ </button>
1251
+ </div>
1252
+ <table
1253
+ v-if="models.length"
1254
+ class="tbl"
1255
+ >
1256
+ <thead>
1257
+ <tr>
1258
+ <th>{{ $t('aml.k1amlx125') }}</th>
1259
+ <th>{{ $t('aml.k1amlx021') }}</th>
1260
+ <th>{{ $t('aml.k1amlx022') }}</th>
1261
+ <th>{{ $t('aml.k1amlx078') }}</th>
1262
+ <th :title="$t('aml.k1amlx126')">
1263
+ {{ $t('aml.k1amlx099') }}
1264
+ </th>
1265
+ <th>{{ $t('aml.k1amlx020') }}</th>
1266
+ <th class="right">
1267
+ {{ $t('aml.k1amlx127') }}
1268
+ </th>
1269
+ </tr>
1270
+ </thead>
1271
+ <tbody>
1272
+ <tr
1273
+ v-for="m in models"
1274
+ :key="m.id"
1275
+ >
1276
+ <td class="mono">
1277
+ {{ shortId(m.id) }}
1278
+ </td>
1279
+ <td class="mono dim">
1280
+ {{ shortId(m.productId) }}
1281
+ </td>
1282
+ <td class="mono dim">
1283
+ {{ shortId(m.recipeId) }}
1284
+ </td>
1285
+ <td>
1286
+ <span
1287
+ class="stage-pill"
1288
+ :class="m.stage"
1289
+ >{{ m.stage }}</span>
1290
+ </td>
1291
+ <td class="mono dim">
1292
+ {{ $t('aml.k1amlx116') }} {{ fmtNum(m.metrics?.oneStepTest?.nrmse) }} · {{ $t('aml.k1amlx117') }} {{ fmtNum(m.metrics?.rolloutTest?.nrmse) }}
1293
+ </td>
1294
+ <td class="mono dim">
1295
+ {{ fmtTime(m.createdAt) }}
1296
+ </td>
1297
+ <td class="right acts">
1298
+ <template
1299
+ v-for="a in promoteActionOf(m)"
1300
+ :key="a.to"
1301
+ >
1302
+ <button
1303
+ class="mini-btn"
1304
+ :class="{ danger: a.to === 'retired' }"
1305
+ :disabled="promoting === `${m.id}:${a.to}`"
1306
+ @click="onPromote(m, a.to)"
1307
+ >
1308
+ {{ confirmPromote === `${m.id}:${a.to}` ? $t('aml.k1amlx131') : $t(a.key) }}
1309
+ </button>
1310
+ </template>
1311
+ <span
1312
+ v-if="promoteActionOf(m).length === 0"
1313
+ class="dim"
1314
+ >--</span>
1315
+ </td>
1316
+ </tr>
1317
+ </tbody>
1318
+ </table>
1319
+ <p
1320
+ v-else
1321
+ class="empty"
1322
+ >
1323
+ {{ $t('aml.k1amlx124') }}
1324
+ </p>
1325
+ </section>
1326
+
1327
+ <!-- 5b. 预测控制台:production 模型 → ioSpec → history JSON → forecast 表 -->
1328
+ <section class="aw-tile zone">
1329
+ <div class="zone-head">
1330
+ <h2>
1331
+ <span class="i-tabler-chart-line" />
1332
+ {{ $t('aml.k1amlx133') }}
1333
+ </h2>
1334
+ <select
1335
+ v-if="productionModels.length"
1336
+ v-model="predModelId"
1337
+ class="inp-sel"
1338
+ >
1339
+ <option value="">
1340
+ {{ $t('aml.k1amlx134') }}
1341
+ </option>
1342
+ <option
1343
+ v-for="m in productionModels"
1344
+ :key="m.id"
1345
+ :value="m.id"
1346
+ >
1347
+ {{ shortId(m.id) }} · {{ shortId(m.recipeId) }}
1348
+ </option>
1349
+ </select>
1350
+ </div>
1351
+ <template v-if="productionModels.length">
1352
+ <div
1353
+ v-if="predModel?.ioSpec"
1354
+ class="pc-body"
1355
+ >
1356
+ <p class="det-title">
1357
+ {{ $t('aml.k1amlx136') }}
1358
+ </p>
1359
+ <div class="io-grid mono">
1360
+ <span class="io-item">{{ $t('aml.k1amlx140') }} <b>{{ predModel.ioSpec.historySteps }}</b></span>
1361
+ <span class="io-item">{{ $t('aml.k1amlx141') }} <b>{{ predModel.ioSpec.horizonSteps }}</b></span>
1362
+ <span class="io-item">{{ $t('aml.k1amlx142') }} <b>{{ predModel.ioSpec.beatMs }}ms</b></span>
1363
+ <span
1364
+ class="io-item"
1365
+ :title="predModel.ioSpec.allNodes.join(', ')"
1366
+ >{{ $t('aml.k1amlx137') }}({{ predModel.ioSpec.allNodes.length }}) <b>{{ predModel.ioSpec.allNodes.map(n => shortId(n)).join(', ') }}</b></span>
1367
+ <span
1368
+ class="io-item"
1369
+ :title="predModel.ioSpec.controlNodes.join(', ')"
1370
+ >{{ $t('aml.k1amlx138') }} <b>{{ predModel.ioSpec.controlNodes.map(n => shortId(n)).join(', ') }}</b></span>
1371
+ <span
1372
+ class="io-item"
1373
+ :title="predModel.ioSpec.targetNodes.join(', ')"
1374
+ >{{ $t('aml.k1amlx139') }} <b>{{ predModel.ioSpec.targetNodes.map(n => shortId(n)).join(', ') }}</b></span>
1375
+ </div>
1376
+ <div class="pc-form">
1377
+ <label class="pc-field">
1378
+ <span>{{ $t('aml.k1amlx143') }}</span>
1379
+ <textarea
1380
+ v-model="predHistory"
1381
+ class="inp area"
1382
+ rows="5"
1383
+ :placeholder="$t('aml.k1amlx144')"
1384
+ />
1385
+ </label>
1386
+ <div class="pc-side">
1387
+ <button
1388
+ class="ghost-btn"
1389
+ @click="onPullLatest"
1390
+ >
1391
+ <span class="i-tabler-download" />
1392
+ {{ $t('aml.k1amlx145') }}
1393
+ </button>
1394
+ <label class="pc-field">
1395
+ <span>{{ $t('aml.k1amlx156') }}</span>
1396
+ <textarea
1397
+ v-model="predControls"
1398
+ class="inp area"
1399
+ rows="3"
1400
+ :placeholder="'[[…]]'"
1401
+ />
1402
+ </label>
1403
+ <label class="pc-field">
1404
+ <span>{{ $t('aml.k1amlx147') }}</span>
1405
+ <input
1406
+ v-model.number="predSteps"
1407
+ type="number"
1408
+ min="1"
1409
+ class="inp"
1410
+ >
1411
+ </label>
1412
+ <button
1413
+ class="pill-btn"
1414
+ :disabled="predBusy || !predHistory.trim()"
1415
+ @click="doPredict"
1416
+ >
1417
+ {{ predBusy ? $t('aml.k1amlx149') : $t('aml.k1amlx148') }}
1418
+ </button>
1419
+ </div>
1420
+ </div>
1421
+ <p class="hint dim">
1422
+ {{ $t('aml.k1amlx146') }}
1423
+ </p>
1424
+ <p
1425
+ v-if="predError"
1426
+ class="err"
1427
+ >
1428
+ {{ predError }}
1429
+ </p>
1430
+ <template v-if="predResult">
1431
+ <p class="det-title">
1432
+ {{ $t('aml.k1amlx150') }}
1433
+ </p>
1434
+ <table class="sub-tbl">
1435
+ <thead>
1436
+ <tr>
1437
+ <th class="num">
1438
+ {{ $t('aml.k1amlx151') }}
1439
+ </th>
1440
+ <th class="num">
1441
+ {{ $t('aml.k1amlx152') }}
1442
+ </th>
1443
+ <th
1444
+ v-for="(n, i) in predResult.targetNodes"
1445
+ :key="n"
1446
+ class="num"
1447
+ >
1448
+ {{ shortId(n) }}<small
1449
+ v-if="i === 0"
1450
+ class="dim"
1451
+ > ({{ $t('aml.k1amlx041') }})</small>
1452
+ </th>
1453
+ </tr>
1454
+ </thead>
1455
+ <tbody>
1456
+ <tr
1457
+ v-for="(row, ri) in predResult.forecast"
1458
+ :key="ri"
1459
+ >
1460
+ <td class="mono num">
1461
+ {{ ri + 1 }}
1462
+ </td>
1463
+ <td class="mono num dim">
1464
+ {{ fmtNum(((ri + 1) * predResult.beatMs) / 1000, 1) }}
1465
+ </td>
1466
+ <td
1467
+ v-for="(v, ci) in row"
1468
+ :key="ci"
1469
+ class="mono num"
1470
+ >
1471
+ {{ fmtNum(v, 3) }}
1472
+ </td>
1473
+ </tr>
1474
+ </tbody>
1475
+ </table>
1476
+ <p class="mono dim gate-detail">
1477
+ {{ $t('aml.k1amlx155') }}:{{ predResult.assumptions }}
1478
+ </p>
1479
+ </template>
1480
+ </div>
1481
+ <p
1482
+ v-else
1483
+ class="empty"
1484
+ >
1485
+ {{ $t('aml.k1amlx134') }}
1486
+ </p>
1487
+ </template>
1488
+ <p
1489
+ v-else
1490
+ class="empty"
1491
+ >
1492
+ {{ $t('aml.k1amlx135') }}
1493
+ </p>
1494
+ </section>
1495
+
1496
+ <!-- 新建数据集快照(spec 与 server zod 模式对齐) -->
1497
+ <div
1498
+ v-if="dsFormOpen"
1499
+ class="modal-mask"
1500
+ @click.self="dsFormOpen = false"
1501
+ >
1502
+ <div class="modal">
1503
+ <h3 class="m-title">
1504
+ {{ $t('aml.k1amlx050') }}
1505
+ </h3>
1506
+ <div class="f-grid">
1507
+ <label class="f">
1508
+ <span>{{ $t('aml.k1amlx051') }}<em>*</em></span>
1509
+ <input
1510
+ v-model="dsForm.lineId"
1511
+ class="inp"
1512
+ placeholder="line-ov-01"
1513
+ >
1514
+ </label>
1515
+ <label class="f">
1516
+ <span>{{ $t('aml.k1amlx052') }}<em>*</em></span>
1517
+ <input
1518
+ v-model="dsForm.productId"
1519
+ class="inp"
1520
+ >
1521
+ </label>
1522
+ <label class="f">
1523
+ <span>{{ $t('aml.k1amlx053') }}<em>*</em></span>
1524
+ <input
1525
+ v-model="dsForm.recipeId"
1526
+ class="inp"
1527
+ >
1528
+ </label>
1529
+ </div>
1530
+ <p class="sec-label">
1531
+ {{ $t('aml.k1amlx054') }}
1532
+ </p>
1533
+ <div class="node-rows">
1534
+ <div
1535
+ v-for="(n, i) in dsNodes"
1536
+ :key="i"
1537
+ class="node-row"
1538
+ >
1539
+ <input
1540
+ v-model="n.nodeId"
1541
+ class="inp grow"
1542
+ :placeholder="$t('aml.k1amlx056')"
1543
+ >
1544
+ <select
1545
+ v-model="n.role"
1546
+ class="inp sel"
1547
+ >
1548
+ <option value="control">
1549
+ {{ $t('aml.k1amlx057') }}
1550
+ </option>
1551
+ <option value="feature">
1552
+ {{ $t('aml.k1amlx058') }}
1553
+ </option>
1554
+ <option value="target">
1555
+ {{ $t('aml.k1amlx059') }}
1556
+ </option>
1557
+ </select>
1558
+ <button
1559
+ class="mini-btn danger"
1560
+ :disabled="dsNodes.length <= 1"
1561
+ @click="removeDsNode(i)"
1562
+ >
1563
+ ✕
1564
+ </button>
1565
+ </div>
1566
+ <button
1567
+ class="mini-btn"
1568
+ @click="addDsNode"
1569
+ >
1570
+ <span class="i-tabler-plus" />
1571
+ {{ $t('aml.k1amlx055') }}
1572
+ </button>
1573
+ </div>
1574
+ <div class="f-grid">
1575
+ <label class="f">
1576
+ <span>{{ $t('aml.k1amlx060') }}</span>
1577
+ <input
1578
+ v-model.number="dsForm.beatMs"
1579
+ type="number"
1580
+ min="1000"
1581
+ step="500"
1582
+ class="inp"
1583
+ >
1584
+ </label>
1585
+ <label class="f">
1586
+ <span>{{ $t('aml.k1amlx061') }}</span>
1587
+ <input
1588
+ v-model.number="dsForm.historySteps"
1589
+ type="number"
1590
+ min="1"
1591
+ class="inp"
1592
+ >
1593
+ </label>
1594
+ <label class="f">
1595
+ <span>{{ $t('aml.k1amlx062') }}</span>
1596
+ <input
1597
+ v-model.number="dsForm.horizonSteps"
1598
+ type="number"
1599
+ min="1"
1600
+ class="inp"
1601
+ >
1602
+ </label>
1603
+ <label class="f">
1604
+ <span>{{ $t('aml.k1amlx063') }}</span>
1605
+ <input
1606
+ v-model.number="dsForm.valRatio"
1607
+ type="number"
1608
+ min="0"
1609
+ max="0.8"
1610
+ step="0.05"
1611
+ class="inp"
1612
+ >
1613
+ </label>
1614
+ <label class="f">
1615
+ <span>{{ $t('aml.k1amlx064') }}</span>
1616
+ <input
1617
+ v-model.number="dsForm.testRatio"
1618
+ type="number"
1619
+ min="0"
1620
+ max="0.8"
1621
+ step="0.05"
1622
+ class="inp"
1623
+ >
1624
+ </label>
1625
+ <label class="f">
1626
+ <span>{{ $t('aml.k1amlx065') }}</span>
1627
+ <input
1628
+ v-model.number="dsForm.seed"
1629
+ type="number"
1630
+ class="inp"
1631
+ >
1632
+ </label>
1633
+ <label class="f">
1634
+ <span>{{ $t('aml.k1amlx066') }}</span>
1635
+ <select
1636
+ v-model="dsForm.purpose"
1637
+ class="inp"
1638
+ >
1639
+ <option value="mpc_surrogate">
1640
+ {{ $t('aml.k1amlx067') }}
1641
+ </option>
1642
+ <option value="quality_predict">
1643
+ {{ $t('aml.k1amlx068') }}
1644
+ </option>
1645
+ </select>
1646
+ </label>
1647
+ <label class="f wide">
1648
+ <span>{{ $t('aml.k1amlx026') }}</span>
1649
+ <input
1650
+ v-model="dsForm.note"
1651
+ class="inp"
1652
+ :placeholder="$t('aml.k1amlx069')"
1653
+ >
1654
+ </label>
1655
+ </div>
1656
+ <p
1657
+ v-if="dsFormError"
1658
+ class="m-err"
1659
+ >
1660
+ {{ dsFormError }}
1661
+ </p>
1662
+ <div class="m-actions">
1663
+ <button
1664
+ class="ghost-btn"
1665
+ @click="dsFormOpen = false"
1666
+ >
1667
+ {{ $t('aml.k1amlx071') }}
1668
+ </button>
1669
+ <button
1670
+ class="pill-btn"
1671
+ :disabled="dsSaving"
1672
+ @click="submitDsForm"
1673
+ >
1674
+ {{ dsSaving ? $t('aml.k1amlx070') : $t('aml.k1amlx072') }}
1675
+ </button>
1676
+ </div>
1677
+ </div>
1678
+ </div>
1679
+ </div>
1680
+ </template>
1681
+
1682
+ <style scoped>
1683
+ .page { padding: 4px; }
1684
+ h1 { margin: 2px 0 4px; font-size: 30px; font-weight: 400; letter-spacing: -0.015em; }
1685
+ .sub { margin: 0; font-size: 12.5px; opacity: 0.6; }
1686
+ .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
1687
+ .dim { opacity: 0.55; }
1688
+ .err { margin: 6px 0; font-size: 12.5px; color: var(--tone-danger-dot); }
1689
+ .pad { padding: 10px 12px; }
1690
+
1691
+ .badges { display: flex; gap: 8px; }
1692
+ .badge {
1693
+ padding: 3px 10px;
1694
+ font-size: 11px;
1695
+ letter-spacing: 0.05em;
1696
+ color: var(--ink-soft);
1697
+ border: 1px solid var(--line-strong);
1698
+ border-radius: var(--radius-chip);
1699
+ }
1700
+ .badge.bad { color: var(--tone-danger-dot); border-color: color-mix(in srgb, var(--tone-danger-dot) 45%, transparent); }
1701
+
1702
+ /* Python 不可用提示条(与 daq 基础设施横幅同语) */
1703
+ .infra-banner {
1704
+ display: flex;
1705
+ gap: 10px;
1706
+ align-items: center;
1707
+ padding: 10px 14px;
1708
+ margin-bottom: 14px;
1709
+ color: var(--tone-warning-dot);
1710
+ background: var(--tone-warning-bg);
1711
+ border: 1px solid color-mix(in srgb, var(--tone-warning-dot) 40%, transparent);
1712
+ border-radius: var(--radius-chip);
1713
+ }
1714
+ .infra-banner .txt { flex: 1 1 auto; font-size: 12.5px; line-height: 1.5; }
1715
+
1716
+ /* ── 1. 概览条 ── */
1717
+ .ov-card { padding: 10px 18px; margin-bottom: 14px; }
1718
+ .ov-row { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; font-size: 12px; color: var(--ink-soft); }
1719
+ .ov-item { display: inline-flex; gap: 5px; align-items: center; }
1720
+ .ov-item b { color: var(--ink); font-weight: 700; }
1721
+ .ov-item.ok { color: var(--tone-success-dot); }
1722
+ .ov-item.bad { color: var(--tone-danger-dot); }
1723
+ .ov-item.accent b { color: var(--accent); }
1724
+ .ov-row .sep { opacity: 0.4; }
1725
+ .ov-row .reload { margin-left: auto; }
1726
+
1727
+ /* ── 通用区块 ── */
1728
+ .zone { padding: 12px 18px 14px; margin-bottom: 14px; overflow-x: auto; }
1729
+ .zone-head { display: flex; gap: 12px; align-items: center; justify-content: space-between; margin-bottom: 10px; }
1730
+ .zone-head h2 { display: inline-flex; gap: 8px; align-items: center; margin: 0; font-size: 15px; font-weight: 600; letter-spacing: 0.01em; }
1731
+ .zone-head h2 .cnt { font-size: 11px; font-weight: 400; color: var(--ink-faint); }
1732
+ .zone-actions { display: flex; gap: 8px; align-items: center; }
1733
+ .live-dot {
1734
+ width: 7px;
1735
+ height: 7px;
1736
+ background: var(--tone-success-dot);
1737
+ border-radius: 50%;
1738
+ box-shadow: 0 0 6px color-mix(in srgb, var(--tone-success-dot) 60%, transparent);
1739
+ }
1740
+ @media (prefers-reduced-motion: no-preference) {
1741
+ .live-dot { animation: amlPulse 1.8s ease-in-out infinite; }
1742
+ }
1743
+ @keyframes amlPulse {
1744
+ 50% { opacity: 0.4; }
1745
+ }
1746
+
1747
+ /* 表:信息密度优先,行可展开 */
1748
+ .tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
1749
+ .tbl th, .tbl td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--divider-hair); }
1750
+ .tbl th {
1751
+ font-size: 11px;
1752
+ font-weight: 600;
1753
+ letter-spacing: 0.06em;
1754
+ text-transform: uppercase;
1755
+ color: var(--ink-faint);
1756
+ border-bottom: 1px solid var(--line-strong);
1757
+ }
1758
+ .tbl .num { text-align: right; }
1759
+ .tbl .right { text-align: right; }
1760
+ .tbl .acts { white-space: nowrap; }
1761
+ .tbl .acts .mini-btn + .mini-btn { margin-left: 6px; }
1762
+ .row-main { cursor: pointer; }
1763
+ @media (prefers-reduced-motion: no-preference) {
1764
+ .row-main:hover { background: var(--hover-tint); }
1765
+ }
1766
+ .row-main.open td { border-bottom-color: transparent; }
1767
+ .note-cell { max-width: 260px; }
1768
+ .note { display: inline-block; overflow: hidden; width: 100%; text-overflow: ellipsis; white-space: nowrap; }
1769
+ .kind {
1770
+ margin-left: 6px;
1771
+ padding: 1px 6px;
1772
+ font-size: 10px;
1773
+ border: 1px solid var(--line);
1774
+ border-radius: 99px;
1775
+ color: var(--ink-faint);
1776
+ }
1777
+ .kind.agent { color: var(--tone-info-dot); border-color: color-mix(in srgb, var(--tone-info-dot) 40%, transparent); }
1778
+
1779
+ /* 展开详情:双栏(清洗报告 | 滞后+run) */
1780
+ .detail-row td { padding: 0 12px 12px; background: var(--frost-bg); }
1781
+ .det-grid { display: grid; grid-template-columns: minmax(340px, 3fr) minmax(280px, 2fr); gap: 10px 22px; }
1782
+ @media (max-width: 1100px) {
1783
+ .det-grid { grid-template-columns: 1fr; }
1784
+ }
1785
+ .det-title { margin: 10px 0 6px; font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
1786
+ .det-title:first-child { margin-top: 10px; }
1787
+ .sub-tbl { width: 100%; border-collapse: collapse; font-size: 12px; }
1788
+ .sub-tbl th, .sub-tbl td { padding: 5px 8px; text-align: left; border-bottom: 1px solid var(--divider-hair); }
1789
+ .sub-tbl th { font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-faint); }
1790
+ .sub-tbl .num { text-align: right; }
1791
+ .role-chip { padding: 1px 6px; font-family: var(--font-mono); font-size: 10px; background: var(--paper-deep); border-radius: 5px; color: var(--ink-soft); }
1792
+ .run-line { margin: 4px 0; font-size: 11.5px; }
1793
+ .run-line b { color: var(--ink); }
1794
+ .drop-line { margin: 2px 0; overflow: hidden; font-size: 11px; color: var(--tone-danger-dot); text-overflow: ellipsis; white-space: nowrap; }
1795
+
1796
+ /* 作业状态 pill / 进度条 */
1797
+ .st-pill {
1798
+ display: inline-block;
1799
+ padding: 2px 9px;
1800
+ font-family: var(--font-mono);
1801
+ font-size: 10.5px;
1802
+ letter-spacing: 0.04em;
1803
+ border-radius: var(--radius-pill);
1804
+ }
1805
+ .st-pill.queued, .st-pill.provisioning { color: var(--tone-neutral-dot); background: var(--tone-neutral-bg); }
1806
+ .st-pill.training, .st-pill.evaluating, .st-pill.running { color: var(--tone-info-dot); background: color-mix(in srgb, var(--tone-info-dot) 12%, transparent); }
1807
+ .st-pill.done, .st-pill.gates_passed { color: var(--tone-success-dot); background: var(--tone-success-bg); }
1808
+ .st-pill.failed, .st-pill.timeout, .st-pill.gates_failed { color: var(--tone-danger-dot); background: var(--tone-danger-bg); }
1809
+ .st-pill.cancelled, .st-pill.interrupted { color: var(--tone-neutral-dot); background: var(--tone-neutral-bg); }
1810
+
1811
+ .prog-th { min-width: 140px; }
1812
+ .prog-cell { white-space: nowrap; }
1813
+ .prog {
1814
+ display: inline-block;
1815
+ width: 96px;
1816
+ height: 6px;
1817
+ overflow: hidden;
1818
+ vertical-align: middle;
1819
+ background: var(--paper-deep);
1820
+ border-radius: 3px;
1821
+ }
1822
+ .prog i { display: block; height: 100%; background: var(--tone-info-dot); border-radius: 3px; transition: width 0.4s ease; }
1823
+ .prog i.done { background: var(--tone-success-dot); }
1824
+ .prog i.bad { background: var(--tone-danger-dot); }
1825
+ .prog-num { margin-left: 7px; font-size: 11px; color: var(--ink-soft); }
1826
+
1827
+ /* 门禁 */
1828
+ .gate-id { font-weight: 700; }
1829
+ .gate-detail { display: block; margin-top: 3px; font-size: 11px; }
1830
+ .verdict { padding: 1px 7px; font-size: 10.5px; border-radius: 99px; }
1831
+ .verdict.pass { color: var(--tone-success-dot); background: var(--tone-success-bg); }
1832
+ .verdict.fail { color: var(--tone-danger-dot); background: var(--tone-danger-bg); }
1833
+ .live-hint { margin-left: 8px; font-size: 10px; font-weight: 400; letter-spacing: 0; color: var(--tone-info-dot); text-transform: none; }
1834
+ .logs {
1835
+ max-height: 260px;
1836
+ margin: 0;
1837
+ padding: 9px 11px;
1838
+ overflow-y: auto;
1839
+ font-family: var(--font-mono);
1840
+ font-size: 11px;
1841
+ line-height: 1.55;
1842
+ color: var(--ink-soft);
1843
+ background: var(--paper-deep);
1844
+ border: 1px solid var(--divider-hair);
1845
+ border-radius: 8px;
1846
+ white-space: pre-wrap;
1847
+ word-break: break-all;
1848
+ }
1849
+
1850
+ /* 排行榜最优行 */
1851
+ tr.best { background: color-mix(in srgb, var(--accent) 9%, transparent); }
1852
+ tr.best td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
1853
+ .best-tag {
1854
+ margin-right: 6px;
1855
+ padding: 1px 7px;
1856
+ font-size: 10px;
1857
+ color: var(--on-accent);
1858
+ background: var(--accent);
1859
+ border-radius: 99px;
1860
+ }
1861
+
1862
+ /* 模型阶段徽标 */
1863
+ .stage-pill {
1864
+ display: inline-block;
1865
+ padding: 2px 9px;
1866
+ font-family: var(--font-mono);
1867
+ font-size: 10.5px;
1868
+ letter-spacing: 0.04em;
1869
+ border: 1px solid var(--line-strong);
1870
+ border-radius: var(--radius-pill);
1871
+ color: var(--ink-soft);
1872
+ }
1873
+ .stage-pill.shadow { color: var(--tone-info-dot); border-color: color-mix(in srgb, var(--tone-info-dot) 45%, transparent); }
1874
+ .stage-pill.production { color: var(--tone-success-dot); background: var(--tone-success-bg); border-color: transparent; }
1875
+ .stage-pill.retired { opacity: 0.55; border-style: dashed; }
1876
+
1877
+ /* ── 预测控制台 ── */
1878
+ .inp-sel {
1879
+ padding: 5px 10px;
1880
+ font-size: 12px;
1881
+ color: var(--ink);
1882
+ background: var(--paper-deep);
1883
+ border: 1px solid var(--line-strong);
1884
+ border-radius: var(--radius-chip);
1885
+ }
1886
+ .pc-body { margin-top: 4px; }
1887
+ .io-grid { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 10px; font-size: 11.5px; color: var(--ink-soft); }
1888
+ .io-item b { font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
1889
+ .pc-form { display: grid; grid-template-columns: minmax(300px, 3fr) minmax(220px, 2fr); gap: 12px 18px; }
1890
+ @media (max-width: 1100px) {
1891
+ .pc-form { grid-template-columns: 1fr; }
1892
+ }
1893
+ .pc-field { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; font-size: 12px; color: var(--ink-soft); }
1894
+ .pc-side { display: flex; flex-direction: column; gap: 8px; align-items: stretch; }
1895
+ .pc-side .ghost-btn { align-self: flex-start; margin-top: 8px; }
1896
+ .pc-side .pill-btn { margin-top: auto; }
1897
+ .inp {
1898
+ padding: 6px 10px;
1899
+ font-family: var(--font-mono);
1900
+ font-size: 12px;
1901
+ color: var(--ink);
1902
+ background: var(--paper-deep);
1903
+ border: 1px solid var(--line-strong);
1904
+ border-radius: var(--radius-chip);
1905
+ }
1906
+ .inp.area { resize: vertical; line-height: 1.5; }
1907
+ .inp:focus { outline: none; border-color: var(--accent); }
1908
+ .hint { margin: 8px 0 0; font-size: 11.5px; line-height: 1.6; }
1909
+
1910
+ /* ── 新建数据集弹窗(工业风:纸面 + 发丝线,与 daq 向导同语) ── */
1911
+ .modal-mask {
1912
+ position: fixed;
1913
+ inset: 0;
1914
+ z-index: 60;
1915
+ display: flex;
1916
+ align-items: flex-start;
1917
+ justify-content: center;
1918
+ padding: 8vh 16px 16px;
1919
+ background: color-mix(in srgb, var(--ink) 45%, transparent);
1920
+ backdrop-filter: blur(3px);
1921
+ }
1922
+ .modal {
1923
+ width: min(760px, 100%);
1924
+ max-height: 84vh;
1925
+ padding: 18px 22px 16px;
1926
+ overflow-y: auto;
1927
+ background: var(--paper);
1928
+ border: 1px solid var(--line-strong);
1929
+ border-radius: 14px;
1930
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.25);
1931
+ }
1932
+ .m-title { margin: 0 0 12px; font-size: 16px; font-weight: 600; }
1933
+ .f-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px 14px; margin-bottom: 10px; }
1934
+ @media (max-width: 720px) {
1935
+ .f-grid { grid-template-columns: 1fr; }
1936
+ }
1937
+ .f { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--ink-soft); }
1938
+ .f.wide { grid-column: 1 / -1; }
1939
+ .f em { margin-left: 2px; color: var(--tone-danger-dot); font-style: normal; }
1940
+ .sec-label { margin: 12px 0 8px; font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
1941
+ .node-rows { display: flex; flex-direction: column; gap: 7px; margin-bottom: 12px; }
1942
+ .node-row { display: flex; gap: 8px; align-items: center; }
1943
+ .node-row .grow { flex: 1 1 auto; }
1944
+ .node-row .sel { flex: 0 0 220px; }
1945
+ .m-err { margin: 6px 0; font-size: 12.5px; color: var(--tone-danger-dot); }
1946
+ .m-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 12px; }
1947
+
1948
+ .empty { margin: 6px 0; padding: 18px 0; font-size: 12.5px; color: var(--ink-faint); text-align: center; }
1949
+ </style>