agentworkshop 0.8.2 → 0.8.4

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 (1646) hide show
  1. package/.output/.AgentWorkShop/aml-python/train-example.py +92 -92
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/_nuxt/{BCLUwdP52.js → 39W1CH-l2.js} +1 -1
  4. package/.output/public/_nuxt/7xbYPfY6.js +1 -0
  5. package/.output/public/_nuxt/{BfvuWqSa.js → ATAvN55g.js} +1 -1
  6. package/.output/public/_nuxt/{B2NbzUau2.js → B3eCVqcT2.js} +1 -1
  7. package/.output/public/_nuxt/B4iJT5PX2.js +2 -0
  8. package/.output/public/_nuxt/{DuUc4bbY2.js → B9qIhT7k2.js} +1 -1
  9. package/.output/public/_nuxt/{BkEokGX5.js → BE9oKpOt.js} +1 -1
  10. package/.output/public/_nuxt/BNUaS1jv.js +20 -0
  11. package/.output/public/_nuxt/BhJA-E372.js +1 -0
  12. package/.output/public/_nuxt/Bq8YzXzs2.js +1 -0
  13. package/.output/public/_nuxt/{dHwWyr6b.js → CT4bi_Y4.js} +1 -1
  14. package/.output/public/_nuxt/{26OL4Ao82.js → CeCSjB9O2.js} +1 -1
  15. package/.output/public/_nuxt/Cf7ER7e2.js +1 -0
  16. package/.output/public/_nuxt/{Dyxf2xZw.js → Cot5VNae.js} +1 -1
  17. package/.output/public/_nuxt/{BVg2R2VB2.js → Crf8_Ad02.js} +1 -1
  18. package/.output/public/_nuxt/{rDvMijKA.js → D9tNM-1a.js} +2 -2
  19. package/.output/public/_nuxt/{YAA98rWJ.js → DAug2CPf.js} +7 -7
  20. package/.output/public/_nuxt/{DrlnrdvY2.js → DPnjnDtg.js} +1 -1
  21. package/.output/public/_nuxt/{CQSxS_Ek.js → DbhTN7-T.js} +1 -1
  22. package/.output/public/_nuxt/DgGzwjAr2.js +2 -0
  23. package/.output/public/_nuxt/DgTqKyYF2.js +1 -0
  24. package/.output/public/_nuxt/DkRozlDP2.js +1 -0
  25. package/.output/public/_nuxt/{Byiiiwc72.js → DxH5focQ.js} +1 -1
  26. package/.output/public/_nuxt/Dyr3LPGL.js +1 -0
  27. package/.output/public/_nuxt/{CC2Pv8VL2.js → MC_i34H42.js} +1 -1
  28. package/.output/public/_nuxt/MmlCf-EZ.js +1 -0
  29. package/.output/public/_nuxt/OmpTerminalPanel.DMWgGwDs.css +1 -0
  30. package/.output/public/_nuxt/PluginSlot.BqBzLD4T.css +1 -0
  31. package/.output/public/_nuxt/TownView.Cn8SPG7S.css +1 -0
  32. package/.output/public/_nuxt/{CmuGMxDP.js → TugRY_4O.js} +1 -1
  33. package/.output/public/_nuxt/{BPUQZ9Lq2.js → WybiLTow2.js} +1 -1
  34. package/.output/public/_nuxt/{BaYDgyaR.js → Zn0BZpf0.js} +3 -3
  35. package/.output/public/_nuxt/{_id_.BQRWK7J2.css → _id_.Be5JaH-P.css} +1 -1
  36. package/.output/public/_nuxt/{_wsId_.DCnKQQdY.css → _wsId_.p_vAYtTp.css} +1 -1
  37. package/.output/public/_nuxt/{agents.D-JPovTZ.css → agents.CRomddYR.css} +1 -1
  38. package/.output/public/_nuxt/aml.DgOMpDpv.css +1 -0
  39. package/.output/public/_nuxt/builds/latest.json +1 -1
  40. package/.output/public/_nuxt/builds/meta/8a151630-3285-41b8-a1e5-063fee2002ac.json +1 -0
  41. package/.output/public/_nuxt/{default.BEXGWZFQ.css → default.CpAx70gC.css} +1 -1
  42. package/.output/public/_nuxt/{entry.C7koBPom.css → entry.D6nBdXet.css} +1 -1
  43. package/.output/public/_nuxt/{logs.BkJPbR_K.css → logs.DcSvz6vi.css} +1 -1
  44. package/.output/public/_nuxt/{monitor.D3yEqqrv.css → monitor.OoNTwfMJ.css} +1 -1
  45. package/.output/public/_nuxt/ontology.D4P756Tc.css +1 -0
  46. package/.output/public/_nuxt/{operations.-l6u44Ar.css → operations.C48ggFa5.css} +1 -1
  47. package/.output/public/_nuxt/{pages.Cdpm_B-G.css → pages.Dpa28tJW.css} +1 -1
  48. package/.output/public/_nuxt/permissions.CrV-4t-6.css +1 -0
  49. package/.output/public/_nuxt/pipeline.NFs5z5V-.css +1 -0
  50. package/.output/public/_nuxt/{BfeXib9G.js → rcdmiszh2.js} +1 -1
  51. package/.output/public/_nuxt/schedules.DYWOjGHm.css +1 -0
  52. package/.output/public/_nuxt/{teams.CLQaXno5.css → teams.DEJoJ4QV.css} +1 -1
  53. package/.output/public/_nuxt/{tokens.BDSUWF-L.css → tokens.DKZWCP5v.css} +1 -1
  54. package/.output/public/_nuxt/tools.DP-nsTli.css +1 -0
  55. package/.output/public/_nuxt/wK6Pp4Zc2.js +2 -0
  56. package/.output/public/_nuxt/{workshop.BBiFhXuM.css → workshop.PT1xhP8C.css} +1 -1
  57. package/.output/public/favicon.svg +14 -14
  58. package/.output/public/robots.txt +3 -3
  59. package/.output/server/chunks/_/LeftOutlined.mjs.map +1 -1
  60. package/.output/server/chunks/_/RightOutlined.mjs.map +1 -1
  61. package/.output/server/chunks/_/SearchOutlined.mjs +1230 -1261
  62. package/.output/server/chunks/_/SearchOutlined.mjs.map +1 -1
  63. package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
  64. package/.output/server/chunks/_/chart-repo.mjs +1 -1
  65. package/.output/server/chunks/_/chart-repo.mjs.map +1 -1
  66. package/.output/server/chunks/_/eda-db.mjs +12 -0
  67. package/.output/server/chunks/_/eda-db.mjs.map +1 -1
  68. package/.output/server/chunks/_/error-500.mjs.map +1 -1
  69. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  70. package/.output/server/chunks/_/nitro.mjs +3258 -3313
  71. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  72. package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
  73. package/.output/server/chunks/_/template-repo.mjs +97 -0
  74. package/.output/server/chunks/_/template-repo.mjs.map +1 -0
  75. package/.output/server/chunks/build/AuthGate-G74Wr5IV.mjs +704 -0
  76. package/.output/server/chunks/build/AuthGate-G74Wr5IV.mjs.map +1 -0
  77. package/.output/server/chunks/build/FormItemContext-DmuQqaeJ.mjs +77 -0
  78. package/.output/server/chunks/build/FormItemContext-DmuQqaeJ.mjs.map +1 -0
  79. package/.output/server/chunks/build/OmpTerminalPanel-5cB-78zp.mjs +889 -0
  80. package/.output/server/chunks/build/OmpTerminalPanel-5cB-78zp.mjs.map +1 -0
  81. package/.output/server/chunks/build/PluginSlot-CZlGlRoR.mjs +131 -0
  82. package/.output/server/chunks/build/PluginSlot-CZlGlRoR.mjs.map +1 -0
  83. package/.output/server/chunks/build/TownView-CcUPLqF1.mjs +5960 -0
  84. package/.output/server/chunks/build/TownView-CcUPLqF1.mjs.map +1 -0
  85. package/.output/server/chunks/build/_id_-AgACEyL6.mjs +1922 -0
  86. package/.output/server/chunks/build/_id_-AgACEyL6.mjs.map +1 -0
  87. package/.output/server/chunks/build/_id_-B3yCK2lD.mjs +373 -0
  88. package/.output/server/chunks/build/_id_-B3yCK2lD.mjs.map +1 -0
  89. package/.output/server/chunks/build/_wsId_-kcDriA4i.mjs +13707 -0
  90. package/.output/server/chunks/build/_wsId_-kcDriA4i.mjs.map +1 -0
  91. package/.output/server/chunks/build/agents-DRod4lTC.mjs +1047 -0
  92. package/.output/server/chunks/build/agents-DRod4lTC.mjs.map +1 -0
  93. package/.output/server/chunks/build/alert-CNGhs--Y.mjs +260 -0
  94. package/.output/server/chunks/build/alert-CNGhs--Y.mjs.map +1 -0
  95. package/.output/server/chunks/build/aml-B3Umz4DR.mjs +729 -0
  96. package/.output/server/chunks/build/aml-B3Umz4DR.mjs.map +1 -0
  97. package/.output/server/chunks/build/analysis-CMsMTMCg.mjs +502 -0
  98. package/.output/server/chunks/build/analysis-CMsMTMCg.mjs.map +1 -0
  99. package/.output/server/chunks/build/{api-B4Om0mEc.mjs → api-D-zkgkj-.mjs} +8 -10
  100. package/.output/server/chunks/build/api-D-zkgkj-.mjs.map +1 -0
  101. package/.output/server/chunks/build/{api-BsAgXWxi.mjs → api-D3gy2e2q.mjs} +22 -24
  102. package/.output/server/chunks/build/api-D3gy2e2q.mjs.map +1 -0
  103. package/.output/server/chunks/build/{api-BEW_ebY_.mjs → api-bn4OKkl_.mjs} +17 -19
  104. package/.output/server/chunks/build/api-bn4OKkl_.mjs.map +1 -0
  105. package/.output/server/chunks/build/api-error-CnW_xiNI.mjs +46 -0
  106. package/.output/server/chunks/build/api-error-CnW_xiNI.mjs.map +1 -0
  107. package/.output/server/chunks/build/apiClient-DIXx9sfD.mjs +70 -0
  108. package/.output/server/chunks/build/apiClient-DIXx9sfD.mjs.map +1 -0
  109. package/.output/server/chunks/build/board-B2oYXGBy.mjs +172 -0
  110. package/.output/server/chunks/build/board-B2oYXGBy.mjs.map +1 -0
  111. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs +81 -94
  112. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs.map +1 -1
  113. package/.output/server/chunks/build/card-BECE6y_G.mjs +922 -0
  114. package/.output/server/chunks/build/card-BECE6y_G.mjs.map +1 -0
  115. package/.output/server/chunks/build/channel-templates-R2TInv8B.mjs +950 -0
  116. package/.output/server/chunks/build/channel-templates-R2TInv8B.mjs.map +1 -0
  117. package/.output/server/chunks/build/chart-trend-BWeZh5Lv.mjs +113 -112
  118. package/.output/server/chunks/build/chart-trend-BWeZh5Lv.mjs.map +1 -1
  119. package/.output/server/chunks/build/checkbox-C6xY5uc6.mjs +429 -0
  120. package/.output/server/chunks/build/checkbox-C6xY5uc6.mjs.map +1 -0
  121. package/.output/server/chunks/build/client-only-S7k53PIm.mjs +42 -0
  122. package/.output/server/chunks/build/client-only-S7k53PIm.mjs.map +1 -0
  123. package/.output/server/chunks/build/constants-HPHJvjne.mjs +65 -75
  124. package/.output/server/chunks/build/constants-HPHJvjne.mjs.map +1 -1
  125. package/.output/server/chunks/build/core-CRlsQhzd.mjs +292 -0
  126. package/.output/server/chunks/build/core-CRlsQhzd.mjs.map +1 -0
  127. package/.output/server/chunks/build/daq-DFQQOtcZ.mjs +1210 -0
  128. package/.output/server/chunks/build/daq-DFQQOtcZ.mjs.map +1 -0
  129. package/.output/server/chunks/build/data-Cl4wRZO6.mjs +459 -0
  130. package/.output/server/chunks/build/data-Cl4wRZO6.mjs.map +1 -0
  131. package/.output/server/chunks/build/dcw-8415S3Km.mjs +467 -0
  132. package/.output/server/chunks/build/dcw-8415S3Km.mjs.map +1 -0
  133. package/.output/server/chunks/build/dcw-driver-badge-Df5wL_ZA.mjs +3 -15
  134. package/.output/server/chunks/build/dcw-driver-badge-Df5wL_ZA.mjs.map +1 -1
  135. package/.output/server/chunks/build/default-DDRKP2Mb.mjs +2246 -0
  136. package/.output/server/chunks/build/default-DDRKP2Mb.mjs.map +1 -0
  137. package/.output/server/chunks/build/descriptions-B3uhDesi.mjs +401 -0
  138. package/.output/server/chunks/build/descriptions-B3uhDesi.mjs.map +1 -0
  139. package/.output/server/chunks/build/drawer-DwXxapMg.mjs +822 -0
  140. package/.output/server/chunks/build/drawer-DwXxapMg.mjs.map +1 -0
  141. package/.output/server/chunks/build/dropdown-DLrGy-Fs.mjs +12 -0
  142. package/.output/server/chunks/build/dropdown-DLrGy-Fs.mjs.map +1 -0
  143. package/.output/server/chunks/build/dropdown-nsGv8Gqx.mjs +530 -0
  144. package/.output/server/chunks/build/dropdown-nsGv8Gqx.mjs.map +1 -0
  145. package/.output/server/chunks/build/{es-Bxu10NJ2.mjs → es-DXSEkmAm.mjs} +1 -2
  146. package/.output/server/chunks/build/es-DXSEkmAm.mjs.map +1 -0
  147. package/.output/server/chunks/build/firstNotUndefined-laiThpLD.mjs +2082 -0
  148. package/.output/server/chunks/build/firstNotUndefined-laiThpLD.mjs.map +1 -0
  149. package/.output/server/chunks/build/form-Cw2Ex9w5.mjs +3543 -0
  150. package/.output/server/chunks/build/form-Cw2Ex9w5.mjs.map +1 -0
  151. package/.output/server/chunks/build/hasIn-RYRGomyg.mjs +192 -0
  152. package/.output/server/chunks/build/hasIn-RYRGomyg.mjs.map +1 -0
  153. package/.output/server/chunks/build/hitl-B4cHRlkC.mjs +120 -0
  154. package/.output/server/chunks/build/hitl-B4cHRlkC.mjs.map +1 -0
  155. package/.output/server/chunks/build/input-CJgB-RL6.mjs +1705 -0
  156. package/.output/server/chunks/build/input-CJgB-RL6.mjs.map +1 -0
  157. package/.output/server/chunks/build/input-number-CQKL42p_.mjs +1027 -0
  158. package/.output/server/chunks/build/input-number-CQKL42p_.mjs.map +1 -0
  159. package/.output/server/chunks/build/interval-DiAUqODq.mjs +8 -0
  160. package/.output/server/chunks/build/interval-DiAUqODq.mjs.map +1 -0
  161. package/.output/server/chunks/build/isNumeric-DQiJ-b15.mjs +6 -0
  162. package/.output/server/chunks/build/isNumeric-DQiJ-b15.mjs.map +1 -0
  163. package/.output/server/chunks/build/logs-C-dWpJ80.mjs +381 -0
  164. package/.output/server/chunks/build/logs-C-dWpJ80.mjs.map +1 -0
  165. package/.output/server/chunks/build/menu-xO8ocVtL.mjs +1833 -0
  166. package/.output/server/chunks/build/menu-xO8ocVtL.mjs.map +1 -0
  167. package/.output/server/chunks/build/monitor-BNrG6v3b.mjs +2216 -0
  168. package/.output/server/chunks/build/monitor-BNrG6v3b.mjs.map +1 -0
  169. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs +0 -2
  170. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs.map +1 -1
  171. package/.output/server/chunks/build/ontology-DoXAsa2y.mjs +1416 -0
  172. package/.output/server/chunks/build/ontology-DoXAsa2y.mjs.map +1 -0
  173. package/.output/server/chunks/build/operations-Ch6tZIKo.mjs +278 -0
  174. package/.output/server/chunks/build/operations-Ch6tZIKo.mjs.map +1 -0
  175. package/.output/server/chunks/build/optimizer-DaTyaY3c.mjs +202 -0
  176. package/.output/server/chunks/build/optimizer-DaTyaY3c.mjs.map +1 -0
  177. package/.output/server/chunks/build/pages-CQOfwKB4.mjs +439 -0
  178. package/.output/server/chunks/build/pages-CQOfwKB4.mjs.map +1 -0
  179. package/.output/server/chunks/build/pagination-BTzq7dD5.mjs +1330 -0
  180. package/.output/server/chunks/build/pagination-BTzq7dD5.mjs.map +1 -0
  181. package/.output/server/chunks/build/permissions-qmimwB0M.mjs +649 -0
  182. package/.output/server/chunks/build/permissions-qmimwB0M.mjs.map +1 -0
  183. package/.output/server/chunks/build/pipeline-eo2RWN3f.mjs +226 -0
  184. package/.output/server/chunks/build/pipeline-eo2RWN3f.mjs.map +1 -0
  185. package/.output/server/chunks/build/plugins-Dh_goy-k.mjs +269 -0
  186. package/.output/server/chunks/build/plugins-Dh_goy-k.mjs.map +1 -0
  187. package/.output/server/chunks/build/popconfirm-DuGF7ty-.mjs +333 -0
  188. package/.output/server/chunks/build/popconfirm-DuGF7ty-.mjs.map +1 -0
  189. package/.output/server/chunks/build/responsiveObserve-CzRpNXkr.mjs +77 -0
  190. package/.output/server/chunks/build/responsiveObserve-CzRpNXkr.mjs.map +1 -0
  191. package/.output/server/chunks/build/schedules-C2_x38gj.mjs +7039 -0
  192. package/.output/server/chunks/build/schedules-C2_x38gj.mjs.map +1 -0
  193. package/.output/server/chunks/build/segmented-29uEKZ3D.mjs +332 -0
  194. package/.output/server/chunks/build/segmented-29uEKZ3D.mjs.map +1 -0
  195. package/.output/server/chunks/build/select-CJb2XrQf.mjs +3734 -0
  196. package/.output/server/chunks/build/select-CJb2XrQf.mjs.map +1 -0
  197. package/.output/server/chunks/build/settings-Cz2Plds0.mjs +944 -0
  198. package/.output/server/chunks/build/settings-Cz2Plds0.mjs.map +1 -0
  199. package/.output/server/chunks/build/space-BByD-mFE.mjs +107 -0
  200. package/.output/server/chunks/build/space-BByD-mFE.mjs.map +1 -0
  201. package/.output/server/chunks/build/spin-XhbgGeLP.mjs +313 -0
  202. package/.output/server/chunks/build/spin-XhbgGeLP.mjs.map +1 -0
  203. package/.output/server/chunks/build/studio-CwYXl00G.mjs +329 -0
  204. package/.output/server/chunks/build/studio-CwYXl00G.mjs.map +1 -0
  205. package/.output/server/chunks/build/switch-DWcwVFxW.mjs +374 -0
  206. package/.output/server/chunks/build/switch-DWcwVFxW.mjs.map +1 -0
  207. package/.output/server/chunks/build/table-Zhuo7Fq-.mjs +7249 -0
  208. package/.output/server/chunks/build/table-Zhuo7Fq-.mjs.map +1 -0
  209. package/.output/server/chunks/build/tabs-BCwBXjNt.mjs +1838 -0
  210. package/.output/server/chunks/build/tabs-BCwBXjNt.mjs.map +1 -0
  211. package/.output/server/chunks/build/tag-CRW-anwy.mjs +1010 -0
  212. package/.output/server/chunks/build/tag-CRW-anwy.mjs.map +1 -0
  213. package/.output/server/chunks/build/teams-CwhFdcYn.mjs +1160 -0
  214. package/.output/server/chunks/build/teams-CwhFdcYn.mjs.map +1 -0
  215. package/.output/server/chunks/build/tokens-C5ODO1HA.mjs +992 -0
  216. package/.output/server/chunks/build/tokens-C5ODO1HA.mjs.map +1 -0
  217. package/.output/server/chunks/build/tools-C0YKragH.mjs +487 -0
  218. package/.output/server/chunks/build/tools-C0YKragH.mjs.map +1 -0
  219. package/.output/server/chunks/build/tooltip-GlMrUZzx.mjs +888 -0
  220. package/.output/server/chunks/build/tooltip-GlMrUZzx.mjs.map +1 -0
  221. package/.output/server/chunks/build/town-BV-hbwb5.mjs +16 -29
  222. package/.output/server/chunks/build/town-BV-hbwb5.mjs.map +1 -1
  223. package/.output/server/chunks/build/town-DLFB4SZl.mjs +117 -0
  224. package/.output/server/chunks/build/town-DLFB4SZl.mjs.map +1 -0
  225. package/.output/server/chunks/build/types-D6J7slEa.mjs.map +1 -1
  226. package/.output/server/chunks/build/types-DWqIeMRP.mjs +28 -29
  227. package/.output/server/chunks/build/types-DWqIeMRP.mjs.map +1 -1
  228. package/.output/server/chunks/build/useAgentHarnessOptions-CYKuLtZ2.mjs +120 -0
  229. package/.output/server/chunks/build/useAgentHarnessOptions-CYKuLtZ2.mjs.map +1 -0
  230. package/.output/server/chunks/build/useAgentTemplateActions-Da_V1LSD.mjs +71 -0
  231. package/.output/server/chunks/build/useAgentTemplateActions-Da_V1LSD.mjs.map +1 -0
  232. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs +16 -23
  233. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs.map +1 -1
  234. package/.output/server/chunks/build/useAgentTemplateForm-BWvax5_E.mjs +112 -0
  235. package/.output/server/chunks/build/useAgentTemplateForm-BWvax5_E.mjs.map +1 -0
  236. package/.output/server/chunks/build/useAgentTemplatesCatalog-BnYjZy59.mjs +140 -0
  237. package/.output/server/chunks/build/useAgentTemplatesCatalog-BnYjZy59.mjs.map +1 -0
  238. package/.output/server/chunks/build/useAmlDatasets-nGi10DAl.mjs +88 -0
  239. package/.output/server/chunks/build/useAmlDatasets-nGi10DAl.mjs.map +1 -0
  240. package/.output/server/chunks/build/useAmlEntities-CTgNAgcZ.mjs +79 -0
  241. package/.output/server/chunks/build/useAmlEntities-CTgNAgcZ.mjs.map +1 -0
  242. package/.output/server/chunks/build/useAmlEnv-Da2TVfyK.mjs +188 -0
  243. package/.output/server/chunks/build/useAmlEnv-Da2TVfyK.mjs.map +1 -0
  244. package/.output/server/chunks/build/useAmlExperiments-U9AQ52RI.mjs +86 -0
  245. package/.output/server/chunks/build/useAmlExperiments-U9AQ52RI.mjs.map +1 -0
  246. package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs +32 -37
  247. package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs.map +1 -1
  248. package/.output/server/chunks/build/useAmlJobs-BM1mu5iH.mjs +251 -0
  249. package/.output/server/chunks/build/useAmlJobs-BM1mu5iH.mjs.map +1 -0
  250. package/.output/server/chunks/build/useAmlModels-C1DwIOMi.mjs +90 -0
  251. package/.output/server/chunks/build/useAmlModels-C1DwIOMi.mjs.map +1 -0
  252. package/.output/server/chunks/build/useAmlNotes-CNm47QdS.mjs +80 -0
  253. package/.output/server/chunks/build/useAmlNotes-CNm47QdS.mjs.map +1 -0
  254. package/.output/server/chunks/build/useAmlPredict-m8I1AdRn.mjs +126 -0
  255. package/.output/server/chunks/build/useAmlPredict-m8I1AdRn.mjs.map +1 -0
  256. package/.output/server/chunks/build/useAnalysisFeed-CpbOaiBD.mjs +120 -0
  257. package/.output/server/chunks/build/useAnalysisFeed-CpbOaiBD.mjs.map +1 -0
  258. package/.output/server/chunks/build/useDaqAddNode-D_1EBuR3.mjs +141 -0
  259. package/.output/server/chunks/build/useDaqAddNode-D_1EBuR3.mjs.map +1 -0
  260. package/.output/server/chunks/build/useDaqDetailBinding-j05iSApd.mjs +72 -0
  261. package/.output/server/chunks/build/useDaqDetailBinding-j05iSApd.mjs.map +1 -0
  262. package/.output/server/chunks/build/useDaqDetailFrames-BKciVJ78.mjs +78 -0
  263. package/.output/server/chunks/build/useDaqDetailFrames-BKciVJ78.mjs.map +1 -0
  264. package/.output/server/chunks/build/useDaqDetailHistory-DgemICkr.mjs +166 -0
  265. package/.output/server/chunks/build/useDaqDetailHistory-DgemICkr.mjs.map +1 -0
  266. package/.output/server/chunks/build/useDaqDetailNode-Cn7_og6t.mjs +103 -0
  267. package/.output/server/chunks/build/useDaqDetailNode-Cn7_og6t.mjs.map +1 -0
  268. package/.output/server/chunks/build/useDaqDetailParams-DX_vjFyK.mjs +157 -0
  269. package/.output/server/chunks/build/useDaqDetailParams-DX_vjFyK.mjs.map +1 -0
  270. package/.output/server/chunks/build/useDaqFilters-DMS4GN20.mjs +224 -0
  271. package/.output/server/chunks/build/useDaqFilters-DMS4GN20.mjs.map +1 -0
  272. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs +43 -44
  273. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs.map +1 -1
  274. package/.output/server/chunks/build/useDaqOptimizations-OPbdy5YB.mjs +132 -0
  275. package/.output/server/chunks/build/useDaqOptimizations-OPbdy5YB.mjs.map +1 -0
  276. package/.output/server/chunks/build/useDaqStream-CS1G6iro.mjs +385 -0
  277. package/.output/server/chunks/build/useDaqStream-CS1G6iro.mjs.map +1 -0
  278. package/.output/server/chunks/build/useDaqTemplates-DqhRYo88.mjs +181 -0
  279. package/.output/server/chunks/build/useDaqTemplates-DqhRYo88.mjs.map +1 -0
  280. package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs +312 -310
  281. package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs.map +1 -1
  282. package/.output/server/chunks/build/useDashboardData-CeaMjEA9.mjs +139 -0
  283. package/.output/server/chunks/build/useDashboardData-CeaMjEA9.mjs.map +1 -0
  284. package/.output/server/chunks/build/useDcwAddNode-Cytz_odQ.mjs +217 -0
  285. package/.output/server/chunks/build/useDcwAddNode-Cytz_odQ.mjs.map +1 -0
  286. package/.output/server/chunks/build/{useDcwCards-SaiImIYQ.mjs → useDcwCards-BKCFqkRd.mjs} +20 -23
  287. package/.output/server/chunks/build/useDcwCards-BKCFqkRd.mjs.map +1 -0
  288. package/.output/server/chunks/build/useDcwDetailScope-CvdvcKAv.mjs +184 -0
  289. package/.output/server/chunks/build/useDcwDetailScope-CvdvcKAv.mjs.map +1 -0
  290. package/.output/server/chunks/build/useDcwDetailTemplates-CC2FcEge.mjs +143 -0
  291. package/.output/server/chunks/build/useDcwDetailTemplates-CC2FcEge.mjs.map +1 -0
  292. package/.output/server/chunks/build/useDcwFilter-CVoiXbZh.mjs +65 -0
  293. package/.output/server/chunks/build/useDcwFilter-CVoiXbZh.mjs.map +1 -0
  294. package/.output/server/chunks/build/{useDcwLedger-0ie-0WTc.mjs → useDcwLedger-Cd-ckHoJ.mjs} +29 -35
  295. package/.output/server/chunks/build/useDcwLedger-Cd-ckHoJ.mjs.map +1 -0
  296. package/.output/server/chunks/build/useDcwLineMutations-BOQs-fw3.mjs +133 -0
  297. package/.output/server/chunks/build/useDcwLineMutations-BOQs-fw3.mjs.map +1 -0
  298. package/.output/server/chunks/build/useDcwLineRun-D9qvcyTM.mjs +100 -0
  299. package/.output/server/chunks/build/useDcwLineRun-D9qvcyTM.mjs.map +1 -0
  300. package/.output/server/chunks/build/useDcwParamApprovals-D36q4can.mjs +119 -0
  301. package/.output/server/chunks/build/useDcwParamApprovals-D36q4can.mjs.map +1 -0
  302. package/.output/server/chunks/build/useDcwProducts-BozctrwT.mjs +88 -0
  303. package/.output/server/chunks/build/useDcwProducts-BozctrwT.mjs.map +1 -0
  304. package/.output/server/chunks/build/useDcwQuery-C8FikKgu.mjs +93 -0
  305. package/.output/server/chunks/build/useDcwQuery-C8FikKgu.mjs.map +1 -0
  306. package/.output/server/chunks/build/useDcwQuickActions-IyQ8Rkpe.mjs +84 -0
  307. package/.output/server/chunks/build/useDcwQuickActions-IyQ8Rkpe.mjs.map +1 -0
  308. package/.output/server/chunks/build/useDcwRecipes-k9HGhMwF.mjs +263 -0
  309. package/.output/server/chunks/build/useDcwRecipes-k9HGhMwF.mjs.map +1 -0
  310. package/.output/server/chunks/build/useDcwStream-BnBOiawo.mjs +455 -0
  311. package/.output/server/chunks/build/useDcwStream-BnBOiawo.mjs.map +1 -0
  312. package/.output/server/chunks/build/useDcwTemplates-CnyYOOy0.mjs +87 -0
  313. package/.output/server/chunks/build/useDcwTemplates-CnyYOOy0.mjs.map +1 -0
  314. package/.output/server/chunks/build/useDcwWrites-Cco590iv.mjs +136 -0
  315. package/.output/server/chunks/build/useDcwWrites-Cco590iv.mjs.map +1 -0
  316. package/.output/server/chunks/build/useDeviceTwins-DL-VLFeX.mjs +118 -0
  317. package/.output/server/chunks/build/useDeviceTwins-DL-VLFeX.mjs.map +1 -0
  318. package/.output/server/chunks/build/useExpConfirmations-DgwqTb9O.mjs +104 -0
  319. package/.output/server/chunks/build/useExpConfirmations-DgwqTb9O.mjs.map +1 -0
  320. package/.output/server/chunks/build/useLocalTime-C__kwn8h.mjs +52 -0
  321. package/.output/server/chunks/build/useLocalTime-C__kwn8h.mjs.map +1 -0
  322. package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs +30 -33
  323. package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs.map +1 -1
  324. package/.output/server/chunks/build/useLogsManual-BcfanT0s.mjs +80 -0
  325. package/.output/server/chunks/build/useLogsManual-BcfanT0s.mjs.map +1 -0
  326. package/.output/server/chunks/build/useLogsQuery-BGlKVKpV.mjs +136 -0
  327. package/.output/server/chunks/build/useLogsQuery-BGlKVKpV.mjs.map +1 -0
  328. package/.output/server/chunks/build/useLogsScope-C-yrta-v.mjs +75 -0
  329. package/.output/server/chunks/build/useLogsScope-C-yrta-v.mjs.map +1 -0
  330. package/.output/server/chunks/build/useMonitorColumns-vVnt3r5Q.mjs +155 -166
  331. package/.output/server/chunks/build/useMonitorColumns-vVnt3r5Q.mjs.map +1 -1
  332. package/.output/server/chunks/build/useMonitorData-BUey2Xly.mjs +128 -0
  333. package/.output/server/chunks/build/useMonitorData-BUey2Xly.mjs.map +1 -0
  334. package/.output/server/chunks/build/useMonitorFormat-rhs7FlNo.mjs +77 -0
  335. package/.output/server/chunks/build/useMonitorFormat-rhs7FlNo.mjs.map +1 -0
  336. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs +20 -27
  337. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs.map +1 -1
  338. package/.output/server/chunks/build/useOperationsFeed-DWfCjP4l.mjs +182 -0
  339. package/.output/server/chunks/build/useOperationsFeed-DWfCjP4l.mjs.map +1 -0
  340. package/.output/server/chunks/build/useOpsLog--yf8erUi.mjs +139 -0
  341. package/.output/server/chunks/build/useOpsLog--yf8erUi.mjs.map +1 -0
  342. package/.output/server/chunks/build/useRecipeDispatchApprovals-CKF2sB9P.mjs +146 -0
  343. package/.output/server/chunks/build/useRecipeDispatchApprovals-CKF2sB9P.mjs.map +1 -0
  344. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs +23 -39
  345. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs.map +1 -1
  346. package/.output/server/chunks/build/useTeamActions-C08sAVqY.mjs +71 -0
  347. package/.output/server/chunks/build/useTeamActions-C08sAVqY.mjs.map +1 -0
  348. package/.output/server/chunks/build/useTeamAddMemberDialog-fzTmflr8.mjs +78 -0
  349. package/.output/server/chunks/build/useTeamAddMemberDialog-fzTmflr8.mjs.map +1 -0
  350. package/.output/server/chunks/build/useTeamCreateDialog-De63ep-X.mjs +91 -0
  351. package/.output/server/chunks/build/useTeamCreateDialog-De63ep-X.mjs.map +1 -0
  352. package/.output/server/chunks/build/useTeamDeployDialog-CpAtG5Jy.mjs +76 -0
  353. package/.output/server/chunks/build/useTeamDeployDialog-CpAtG5Jy.mjs.map +1 -0
  354. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs +31 -38
  355. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs.map +1 -1
  356. package/.output/server/chunks/build/useTeamPluginDialog-C1OOe1sL.mjs +99 -0
  357. package/.output/server/chunks/build/useTeamPluginDialog-C1OOe1sL.mjs.map +1 -0
  358. package/.output/server/chunks/build/useTeamsCatalog-DA41SMDu.mjs +124 -0
  359. package/.output/server/chunks/build/useTeamsCatalog-DA41SMDu.mjs.map +1 -0
  360. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs +21 -28
  361. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs.map +1 -1
  362. package/.output/server/chunks/build/useTokenCreate-XHTQExra.mjs +106 -0
  363. package/.output/server/chunks/build/useTokenCreate-XHTQExra.mjs.map +1 -0
  364. package/.output/server/chunks/build/useTokenRename-Cf1B0cRy.mjs +81 -0
  365. package/.output/server/chunks/build/useTokenRename-Cf1B0cRy.mjs.map +1 -0
  366. package/.output/server/chunks/build/useTokenReveal-C8n1Vt9t.mjs +108 -0
  367. package/.output/server/chunks/build/useTokenReveal-C8n1Vt9t.mjs.map +1 -0
  368. package/.output/server/chunks/build/useTokensList-MMIq24E-.mjs +86 -0
  369. package/.output/server/chunks/build/useTokensList-MMIq24E-.mjs.map +1 -0
  370. package/.output/server/chunks/build/useTownBus-D9SoIsAN.mjs +16 -17
  371. package/.output/server/chunks/build/useTownBus-D9SoIsAN.mjs.map +1 -1
  372. package/.output/server/chunks/build/useWorkbenchAuth-Dyc_czui.mjs +131 -0
  373. package/.output/server/chunks/build/useWorkbenchAuth-Dyc_czui.mjs.map +1 -0
  374. package/.output/server/chunks/build/useWorkbenchWorkspaces-DT33HbBD.mjs +128 -0
  375. package/.output/server/chunks/build/useWorkbenchWorkspaces-DT33HbBD.mjs.map +1 -0
  376. package/.output/server/chunks/build/useWorkshopApi-BkEgGBIM.mjs +118 -0
  377. package/.output/server/chunks/build/useWorkshopApi-BkEgGBIM.mjs.map +1 -0
  378. package/.output/server/chunks/build/useWorkshopWs-BWrVj4jL.mjs +1577 -0
  379. package/.output/server/chunks/build/useWorkshopWs-BWrVj4jL.mjs.map +1 -0
  380. package/.output/server/chunks/build/{useWorkspaceAuth-Dlvj9csD.mjs → useWorkspaceAuth-TahC9EC7.mjs} +4 -16
  381. package/.output/server/chunks/build/useWorkspaceAuth-TahC9EC7.mjs.map +1 -0
  382. package/.output/server/chunks/build/useWorkspaceChannels-BVAHmhN3.mjs +94 -0
  383. package/.output/server/chunks/build/useWorkspaceChannels-BVAHmhN3.mjs.map +1 -0
  384. package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs +30 -33
  385. package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs.map +1 -1
  386. package/.output/server/chunks/build/useWorkspaceShell-rQHWNNWJ.mjs +150 -0
  387. package/.output/server/chunks/build/useWorkspaceShell-rQHWNNWJ.mjs.map +1 -0
  388. package/.output/server/chunks/build/users-pVCK50z-.mjs +566 -0
  389. package/.output/server/chunks/build/users-pVCK50z-.mjs.map +1 -0
  390. package/.output/server/chunks/build/workshop-DAgsBgG4.mjs +499 -0
  391. package/.output/server/chunks/build/workshop-DAgsBgG4.mjs.map +1 -0
  392. package/.output/server/chunks/build/workspaces-CmW0cpOt.mjs +111 -121
  393. package/.output/server/chunks/build/workspaces-CmW0cpOt.mjs.map +1 -1
  394. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
  395. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
  396. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  397. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +1 -1
  398. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +1 -1
  399. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
  400. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  401. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  402. package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs +1 -1
  403. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +1 -1
  404. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +1 -1
  405. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
  406. package/.output/server/chunks/routes/api/workshop/eda/index8.get.mjs +33 -0
  407. package/.output/server/chunks/routes/api/workshop/eda/index8.get.mjs.map +1 -0
  408. package/.output/server/chunks/routes/api/workshop/eda/index8.post.mjs +41 -0
  409. package/.output/server/chunks/routes/api/workshop/eda/index8.post.mjs.map +1 -0
  410. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.delete.mjs +36 -0
  411. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.delete.mjs.map +1 -0
  412. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.get.mjs +37 -0
  413. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.get.mjs.map +1 -0
  414. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.patch.mjs +42 -0
  415. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.patch.mjs.map +1 -0
  416. package/.output/server/chunks/routes/api/workshop/index10.post.mjs +33 -0
  417. package/.output/server/chunks/routes/api/workshop/index10.post.mjs.map +1 -0
  418. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +45 -46
  419. package/.output/server/chunks/routes/api/workshop/index2.post.mjs.map +1 -1
  420. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +46 -23
  421. package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
  422. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +10 -9
  423. package/.output/server/chunks/routes/api/workshop/index4.post.mjs.map +1 -1
  424. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +22 -19
  425. package/.output/server/chunks/routes/api/workshop/index5.post.mjs.map +1 -1
  426. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +18 -42
  427. package/.output/server/chunks/routes/api/workshop/index6.post.mjs.map +1 -1
  428. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +43 -17
  429. package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
  430. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +13 -15
  431. package/.output/server/chunks/routes/api/workshop/index8.post.mjs.map +1 -1
  432. package/.output/server/chunks/routes/api/workshop/index9.post.mjs +18 -4
  433. package/.output/server/chunks/routes/api/workshop/index9.post.mjs.map +1 -1
  434. package/.output/server/chunks/routes/api/workshop/process-model/datasets.post.mjs +1 -1
  435. package/.output/server/chunks/routes/api/workshop/process-model/eligibility.mjs +1 -1
  436. package/.output/server/chunks/routes/api/workshop/process-model/experiments.mjs +1 -1
  437. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
  438. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  439. package/.output/server/chunks/routes/renderer.mjs +1 -1
  440. package/.output/server/chunks/routes/renderer.mjs.map +1 -1
  441. package/.output/server/chunks/virtual/entry.mjs +9581 -10848
  442. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  443. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  444. package/.output/server/chunks/virtual/precomputed.mjs.map +1 -1
  445. package/.output/server/package.json +1 -1
  446. package/README-zh.md +8 -5
  447. package/README.md +9 -6
  448. package/app/components/AwChart.vue +14 -0
  449. package/app/components/AwLogo.vue +75 -75
  450. package/app/components/aml/AmlDatasetFormModal.vue +279 -279
  451. package/app/components/aml/AmlDatasetTable.vue +319 -319
  452. package/app/components/aml/AmlExperimentsTable.vue +142 -142
  453. package/app/components/aml/AmlInfraBanner.vue +23 -23
  454. package/app/components/aml/AmlJobsTable.vue +248 -248
  455. package/app/components/aml/AmlOverviewBar.vue +62 -62
  456. package/app/components/aml/AmlPageHeader.vue +47 -47
  457. package/app/components/aml/AmlPredictConsole.vue +201 -201
  458. package/app/components/app-header/HitlBell.vue +423 -423
  459. package/app/components/daq/DaqAddNodeModal.vue +209 -209
  460. package/app/components/daq/DaqAlarmBar.vue +46 -46
  461. package/app/components/daq/DaqControlCard.vue +159 -159
  462. package/app/components/daq/DaqInfraBanner.vue +31 -31
  463. package/app/components/daq/DaqLineBanner.vue +47 -47
  464. package/app/components/daq/DaqNodePanel.vue +396 -396
  465. package/app/components/daq/DaqOptPanel.vue +197 -197
  466. package/app/components/daq/DaqTemplateModal.vue +246 -246
  467. package/app/components/dashboard/DashboardGaugeBand.vue +78 -78
  468. package/app/components/dashboard/DashboardHero.vue +209 -209
  469. package/app/components/dashboard/DashboardLineStatePanel.vue +78 -78
  470. package/app/components/dashboard/DashboardNodeStatePanel.vue +46 -46
  471. package/app/components/dashboard/DashboardPipelinePanel.vue +46 -46
  472. package/app/components/dashboard/DashboardTrendPanel.vue +83 -83
  473. package/app/components/dashboard/DashboardWritePanel.vue +52 -52
  474. package/app/components/dcw/DcwCreateLineModal.vue +105 -105
  475. package/app/components/dcw/DcwDeleteLineModal.vue +73 -73
  476. package/app/components/dcw/DcwDetailTemplateModal.vue +238 -238
  477. package/app/components/dcw/DcwLedgerCard.vue +160 -160
  478. package/app/components/dcw/DcwMesArtifacts.vue +140 -140
  479. package/app/components/dcw/DcwProductCreateModal.vue +113 -113
  480. package/app/components/dcw/DcwRecipeDispatchHistoryModal.vue +244 -244
  481. package/app/components/dcw/DcwRecipeEditModal.vue +399 -399
  482. package/app/components/dcw/DcwRecipeHistoryModal.vue +165 -165
  483. package/app/components/dcw/DcwRunDataModal.vue +191 -191
  484. package/app/components/dcw/DcwTemplateModal.vue +227 -227
  485. package/app/components/dcw/DcwWriteHistoryCard.vue +96 -96
  486. package/app/components/dcw/ExpConfirmCard.vue +103 -103
  487. package/app/components/dcw/RecipeDispatchApprovalCard.vue +330 -330
  488. package/app/components/logs/LogsPageHead.vue +71 -71
  489. package/app/components/monitor/MonitorAgentTable.vue +143 -143
  490. package/app/components/monitor/MonitorChannelTable.vue +80 -80
  491. package/app/components/monitor/MonitorLoginGate.vue +24 -24
  492. package/app/components/monitor/MonitorPageHead.vue +92 -92
  493. package/app/components/monitor/MonitorProcessTable.vue +159 -159
  494. package/app/components/ontology/OntologyGraph.vue +356 -356
  495. package/app/components/operations/OperationsFilterCard.vue +164 -164
  496. package/app/components/operations/OperationsPageHead.vue +47 -47
  497. package/app/components/tokens/TokenCreateModal.vue +42 -42
  498. package/app/components/tokens/TokenOnceModal.vue +164 -164
  499. package/app/components/tokens/TokenRenameModal.vue +40 -40
  500. package/app/components/tokens/TokensPageHead.vue +76 -76
  501. package/app/components/workshop/A2aRpcDebugger.vue +237 -237
  502. package/app/components/workshop/AgentInspectorDrawer.vue +424 -424
  503. package/app/components/workshop/AgentLanesView.vue +278 -278
  504. package/app/components/workshop/ArtifactCard.vue +120 -120
  505. package/app/components/workshop/AssetLibrary.vue +452 -452
  506. package/app/components/workshop/ChatMemberPanel.vue +556 -556
  507. package/app/components/workshop/CommandPalette.vue +270 -270
  508. package/app/components/workshop/Composer.vue +540 -540
  509. package/app/components/workshop/DaqTemplateIcon.vue +33 -33
  510. package/app/components/workshop/DeviceTwinPanel.vue +167 -167
  511. package/app/components/workshop/FileSelectorModal.vue +188 -188
  512. package/app/components/workshop/InspectorPanel.vue +301 -301
  513. package/app/components/workshop/PluginSlot.vue +120 -120
  514. package/app/components/workshop/TranscriptTimeline.vue +223 -223
  515. package/app/components/workshop/agents/AgentTemplateEditModal.vue +139 -139
  516. package/app/components/workshop/blocks/ClusterArtifact.vue +61 -61
  517. package/app/components/workshop/blocks/ClusterError.vue +85 -85
  518. package/app/components/workshop/blocks/ClusterLife.vue +87 -87
  519. package/app/components/workshop/blocks/ClusterMember.vue +95 -95
  520. package/app/components/workshop/blocks/ClusterMemory.vue +84 -84
  521. package/app/components/workshop/blocks/ClusterOther.vue +67 -67
  522. package/app/components/workshop/blocks/ClusterStatus.vue +149 -149
  523. package/app/components/workshop/blocks/ClusterTool.vue +176 -176
  524. package/app/components/workshop/blocks/EventBlockAvatar.vue +114 -114
  525. package/app/components/workshop/blocks/EventBlockHead.vue +232 -232
  526. package/app/components/workshop/composer/ComposerToolbar.vue +278 -278
  527. package/app/components/workshop/composer/MentionMenu.vue +135 -135
  528. package/app/components/workshop/composer/ReplyChip.vue +65 -65
  529. package/app/components/workshop/composer/StatusChip.vue +171 -171
  530. package/app/components/workshop/console/Dock.vue +71 -71
  531. package/app/components/workshop/console/LeftPane.vue +84 -84
  532. package/app/components/workshop/device-twin/DeviceTwinCard.vue +265 -265
  533. package/app/components/workshop/device-twin/DeviceTwinDcwSection.vue +203 -203
  534. package/app/components/workshop/lanes/AddMemberModal.vue +270 -270
  535. package/app/components/workshop/lanes/EditMemberModal.vue +106 -106
  536. package/app/components/workshop/lanes/LanesToolbar.vue +97 -97
  537. package/app/components/workshop/session-list/ChannelSettingsModal.vue +3 -3
  538. package/app/components/workshop/session-list/MountChannelModal.vue +124 -124
  539. package/app/components/workshop/session-list/SaveTemplateModal.vue +93 -93
  540. package/app/components/workshop/task-board/Card.vue +172 -172
  541. package/app/components/workshop/task-board/Column.vue +151 -151
  542. package/app/components/workshop/task-board/List.vue +157 -157
  543. package/app/components/workshop/task-board/StatusMenu.vue +88 -88
  544. package/app/components/workshop/teams/TeamAddMemberModal.vue +53 -53
  545. package/app/components/workshop/teams/TeamCreateModal.vue +94 -94
  546. package/app/components/workshop/teams/TeamDeployModal.vue +40 -40
  547. package/app/components/workshop/teams/TeamPluginModal.vue +119 -119
  548. package/app/components/workshop/terminal/OmpTerminalPanel.vue +270 -270
  549. package/app/components/workshop/terminal/TerminalHitlCard.vue +170 -170
  550. package/app/components/workshop/town/TownScene.ts +466 -466
  551. package/app/components/workshop/town/TownView.vue +561 -561
  552. package/app/components/workshop/town/components/AutoModeConfirmModal.vue +94 -94
  553. package/app/components/workshop/town/components/TownAgentBindings.vue +405 -405
  554. package/app/components/workshop/town/components/TownAgentInspector.vue +554 -554
  555. package/app/components/workshop/town/components/TownAlarmList.vue +147 -147
  556. package/app/components/workshop/town/components/TownBoundaryPanel.vue +350 -350
  557. package/app/components/workshop/town/components/TownCalloutLayer.vue +147 -147
  558. package/app/components/workshop/town/components/TownChannelDock.vue +116 -116
  559. package/app/components/workshop/town/components/TownControlDock.vue +405 -405
  560. package/app/components/workshop/town/components/TownDaqNodeInspector.vue +345 -345
  561. package/app/components/workshop/town/components/TownDaqTree.vue +366 -366
  562. package/app/components/workshop/town/components/TownDcwBindSection.vue +473 -473
  563. package/app/components/workshop/town/components/TownDcwNodeInspector.vue +185 -185
  564. package/app/components/workshop/town/components/TownDcwTree.vue +280 -280
  565. package/app/components/workshop/town/components/TownDeviceBindings.vue +394 -394
  566. package/app/components/workshop/town/components/TownDeviceTransform.vue +248 -248
  567. package/app/components/workshop/town/components/TownEventList.vue +120 -120
  568. package/app/components/workshop/town/components/TownHealthBody.vue +100 -100
  569. package/app/components/workshop/town/components/TownKpiStrip.vue +207 -207
  570. package/app/components/workshop/town/components/TownLeftRail.vue +308 -308
  571. package/app/components/workshop/town/components/TownLoadingMask.vue +61 -61
  572. package/app/components/workshop/town/components/TownNavMap.vue +154 -154
  573. package/app/components/workshop/town/components/TownRightRail.vue +543 -543
  574. package/app/components/workshop/town/components/TownStage.vue +281 -281
  575. package/app/components/workshop/town/components/TownStageTop.vue +238 -238
  576. package/app/components/workshop/town/components/TownStatusBar.vue +108 -108
  577. package/app/components/workshop/town/components/TownTopNav.vue +367 -367
  578. package/app/components/workshop/town/components/TownTrendDock.vue +178 -178
  579. package/app/components/workshop/town/scene/town-scene-agents.ts +254 -254
  580. package/app/components/workshop/town/scene/town-scene-behavior.ts +194 -194
  581. package/app/components/workshop/town/scene/town-scene-bubbles.ts +96 -96
  582. package/app/components/workshop/town/scene/town-scene-core.ts +158 -158
  583. package/app/components/workshop/town/scene/town-scene-models.ts +109 -109
  584. package/app/components/workshop/town/scene/town-scene-visuals.ts +279 -279
  585. package/app/components/workshop/town/scene/town-scene3d-agents.ts +308 -308
  586. package/app/components/workshop/town/scene/town-scene3d-blocks.ts +297 -297
  587. package/app/components/workshop/town/scene/town-scene3d-bubbles.ts +281 -281
  588. package/app/components/workshop/town/scene/town-scene3d-camera.ts +282 -282
  589. package/app/components/workshop/town/scene/town-scene3d-devices.ts +433 -433
  590. package/app/components/workshop/town/scene/town-scene3d-editing.ts +490 -490
  591. package/app/components/workshop/town/scene/town-scene3d-events.ts +173 -173
  592. package/app/components/workshop/town/scene/town-scene3d-factory.ts +412 -412
  593. package/app/components/workshop/town/scene/town-scene3d-hud.ts +110 -110
  594. package/app/components/workshop/town/scene/town-scene3d-lifecycle.ts +144 -144
  595. package/app/components/workshop/town/scene/town-scene3d-links.ts +141 -141
  596. package/app/components/workshop/town/scene/town-scene3d-loop.ts +286 -286
  597. package/app/components/workshop/town/scene/town-scene3d-models.ts +154 -154
  598. package/app/components/workshop/town/scene/town-scene3d-nodes.ts +562 -562
  599. package/app/components/workshop/town/scene/town-scene3d-ranges.ts +273 -273
  600. package/app/components/workshop/town/scene/town-scene3d-renderer.ts +320 -320
  601. package/app/components/workshop/town/scene/town-scene3d-selection.ts +257 -257
  602. package/app/components/workshop/town/scene/town-scene3d-types.ts +264 -264
  603. package/app/components/workshop/transcript/TranscriptBlockList.vue +68 -68
  604. package/app/components/workshop/transcript/TranscriptEarlierPager.vue +81 -81
  605. package/app/components/workshop/transcript/TranscriptFilterBar.vue +126 -126
  606. package/app/components/workshop/workbench/CreateWorkspaceModal.vue +36 -36
  607. package/app/components/workshop/workbench/WorkspaceEmpty.vue +56 -56
  608. package/app/composables/useResponsive.ts +88 -88
  609. package/app/composables/workshop/device-twin-types.ts +29 -29
  610. package/app/composables/workshop/event-blocks/attention.ts +58 -58
  611. package/app/composables/workshop/event-blocks/classify.ts +44 -44
  612. package/app/composables/workshop/event-blocks/clusterer.ts +231 -231
  613. package/app/composables/workshop/event-blocks/fold-stream.ts +45 -45
  614. package/app/composables/workshop/event-blocks/markdown.ts +81 -81
  615. package/app/composables/workshop/event-blocks/mentions.ts +49 -49
  616. package/app/composables/workshop/event-blocks/text-utils.ts +100 -100
  617. package/app/composables/workshop/event-blocks/types.ts +40 -40
  618. package/app/composables/workshop/town/town-relay-props.ts +231 -231
  619. package/app/composables/workshop/town/town-view-types.ts +145 -145
  620. package/app/composables/workshop/town/useTownAgentBindings.ts +182 -182
  621. package/app/composables/workshop/town/useTownAgentChat.ts +203 -203
  622. package/app/composables/workshop/town/useTownAlarms.ts +36 -36
  623. package/app/composables/workshop/town/useTownCallouts.ts +174 -174
  624. package/app/composables/workshop/town/useTownChannels.ts +220 -220
  625. package/app/composables/workshop/town/useTownHealth.ts +66 -66
  626. package/app/composables/workshop/town/useTownHudTickers.ts +77 -77
  627. package/app/composables/workshop/town/useTownLayout.ts +277 -277
  628. package/app/composables/workshop/town/useTownNavMap.ts +301 -301
  629. package/app/composables/workshop/town/useTownNodeBindings.ts +345 -345
  630. package/app/composables/workshop/town/useTownPanelDrag.ts +91 -91
  631. package/app/composables/workshop/town/useTownRailData.ts +421 -421
  632. package/app/composables/workshop/town/useTownSceneControl.ts +92 -92
  633. package/app/composables/workshop/town/useTownSceneInput.ts +275 -275
  634. package/app/composables/workshop/town/useTownSceneRuntime.ts +390 -390
  635. package/app/composables/workshop/town/useTownSheets.ts +41 -41
  636. package/app/composables/workshop/town/useTownTrends.ts +93 -93
  637. package/app/composables/workshop/useChannelList.ts +88 -88
  638. package/app/composables/workshop/useChannelTerminals.ts +65 -65
  639. package/app/composables/workshop/useComposerMentions.ts +130 -130
  640. package/app/composables/workshop/useDcwStream.ts +374 -374
  641. package/app/composables/workshop/useDeviceTwinDcwWrite.ts +77 -77
  642. package/app/composables/workshop/useDeviceTwinPanel.ts +56 -56
  643. package/app/composables/workshop/useEscClose.ts +44 -44
  644. package/app/composables/workshop/useEventBlockView.ts +159 -159
  645. package/app/composables/workshop/useEventBlocks.ts +33 -33
  646. package/app/composables/workshop/useHitlAnswer.ts +184 -184
  647. package/app/composables/workshop/useLaneWidths.ts +27 -27
  648. package/app/composables/workshop/useOmpTerminalSession.ts +424 -424
  649. package/app/composables/workshop/usePluginAdmin.ts +152 -152
  650. package/app/composables/workshop/usePluginPanels.ts +72 -72
  651. package/app/composables/workshop/useRuntimeConfigDraft.ts +118 -118
  652. package/app/composables/workshop/useSettingsGroups.ts +243 -243
  653. package/app/composables/workshop/useTaskBoardColumns.ts +47 -47
  654. package/app/composables/workshop/useTerminalRenderer.ts +308 -308
  655. package/app/composables/workshop/useTranscriptEnterStage.ts +48 -48
  656. package/app/composables/workshop/useTranscriptHistory.ts +52 -52
  657. package/app/composables/workshop/useTranscriptScroll.ts +113 -113
  658. package/app/composables/workshop/useVisibleInterval.ts +42 -42
  659. package/app/composables/workshop/useWorkshopWs.ts +265 -265
  660. package/app/config/index.ts +1 -1
  661. package/app/middleware/locale-cookie.global.ts +22 -22
  662. package/app/pages/aml/api.ts +6 -6
  663. package/app/pages/aml/composables/useAmlDatasets.ts +38 -38
  664. package/app/pages/aml/composables/useAmlEntities.ts +57 -57
  665. package/app/pages/aml/composables/useAmlEnv.ts +191 -191
  666. package/app/pages/aml/composables/useAmlExperiments.ts +45 -45
  667. package/app/pages/aml/composables/useAmlFormat.ts +44 -44
  668. package/app/pages/aml/composables/useAmlJobs.ts +131 -131
  669. package/app/pages/aml/composables/useAmlModels.ts +56 -56
  670. package/app/pages/aml/composables/useAmlNotes.ts +47 -47
  671. package/app/pages/aml/composables/useAmlPredict.ts +93 -93
  672. package/app/pages/aml/constants.ts +63 -63
  673. package/app/pages/aml/index.vue +236 -236
  674. package/app/pages/composables/useDashboardCharts.ts +192 -192
  675. package/app/pages/composables/useDashboardData.ts +144 -144
  676. package/app/pages/daq/composables/useDaqAddNode.ts +126 -126
  677. package/app/pages/daq/composables/useDaqDetailBinding.ts +29 -29
  678. package/app/pages/daq/composables/useDaqDetailFrames.ts +42 -42
  679. package/app/pages/daq/composables/useDaqDetailNode.ts +53 -53
  680. package/app/pages/daq/composables/useDaqDetailParams.ts +138 -138
  681. package/app/pages/daq/composables/useDaqFilters.ts +187 -187
  682. package/app/pages/daq/composables/useDaqNodeWindow.ts +86 -86
  683. package/app/pages/daq/composables/useDaqOptimizations.ts +99 -99
  684. package/app/pages/daq/composables/useDaqTemplates.ts +152 -152
  685. package/app/pages/daq/index.vue +260 -260
  686. package/app/pages/dcw/composables/useDcwCards.ts +27 -27
  687. package/app/pages/dcw/composables/useDcwDetailScope.ts +145 -145
  688. package/app/pages/dcw/composables/useDcwDetailTemplates.ts +94 -94
  689. package/app/pages/dcw/composables/useDcwFilter.ts +29 -29
  690. package/app/pages/dcw/composables/useDcwLedger.ts +34 -34
  691. package/app/pages/dcw/composables/useDcwLineMutations.ts +115 -115
  692. package/app/pages/dcw/composables/useDcwLineRun.ts +60 -60
  693. package/app/pages/dcw/composables/useDcwProducts.ts +54 -54
  694. package/app/pages/dcw/composables/useDcwQuery.ts +68 -68
  695. package/app/pages/dcw/composables/useDcwQuickActions.ts +47 -47
  696. package/app/pages/dcw/composables/useDcwRecipes.ts +256 -256
  697. package/app/pages/dcw/composables/useDcwTemplates.ts +50 -50
  698. package/app/pages/dcw/index.vue +195 -195
  699. package/app/pages/dcw/types.ts +9 -9
  700. package/app/pages/index.vue +126 -126
  701. package/app/pages/logs/composables/useLogsFormat.ts +43 -43
  702. package/app/pages/logs/composables/useLogsScope.ts +39 -39
  703. package/app/pages/monitor/types.ts +61 -61
  704. package/app/pages/ontology/index.vue +1 -1
  705. package/app/pages/operations.vue +61 -61
  706. package/app/pages/permissions/index.vue +369 -369
  707. package/app/pages/studio/pipeline.vue +812 -0
  708. package/app/pages/tokens/composables/useTokenClipboard.ts +33 -33
  709. package/app/pages/tokens/composables/useTokenCreate.ts +93 -93
  710. package/app/pages/tokens/composables/useTokenRename.ts +54 -54
  711. package/app/pages/tokens/composables/useTokenReveal.ts +84 -84
  712. package/app/pages/tokens/composables/useTokensList.ts +60 -60
  713. package/app/pages/tokens.vue +111 -111
  714. package/app/pages/tools/index.vue +98 -98
  715. package/app/pages/workshop/agents.vue +130 -130
  716. package/app/pages/workshop/composables/useAgentHarnessOptions.ts +59 -59
  717. package/app/pages/workshop/composables/useAgentTemplateActions.ts +42 -42
  718. package/app/pages/workshop/composables/useAgentTemplateDialogState.ts +24 -24
  719. package/app/pages/workshop/composables/useAgentTemplateForm.ts +88 -88
  720. package/app/pages/workshop/composables/useAgentTemplatesCatalog.ts +92 -92
  721. package/app/pages/workshop/composables/useTeamActions.ts +44 -44
  722. package/app/pages/workshop/composables/useTeamAddMemberDialog.ts +49 -49
  723. package/app/pages/workshop/composables/useTeamCreateDialog.ts +67 -67
  724. package/app/pages/workshop/composables/useTeamDeployDialog.ts +49 -49
  725. package/app/pages/workshop/composables/useTeamDialogState.ts +46 -46
  726. package/app/pages/workshop/composables/useTeamPluginDialog.ts +72 -72
  727. package/app/pages/workshop/composables/useTeamsCatalog.ts +100 -100
  728. package/app/pages/workshop/composables/useWorkbenchWorkspaces.ts +123 -123
  729. package/app/pages/workshop/composables/useWorkspaceAuth.ts +31 -31
  730. package/app/pages/workshop/composables/useWorkspaceChannels.ts +62 -62
  731. package/app/pages/workshop/composables/useWorkspaceShell.ts +136 -136
  732. package/app/pages/workshop/schedules.vue +553 -553
  733. package/app/pages/workshop/w/[wsId].vue +221 -221
  734. package/app/plugins/aw-plugins.client.ts +213 -213
  735. package/app/plugins/esc-close.client.ts +31 -31
  736. package/app/stores/workshop/hitl.ts +183 -183
  737. package/app/stores/workshop/narrow-fetch.ts +23 -23
  738. package/app/utils/api-error.ts +75 -75
  739. package/app/utils/builtin-catalog.ts +104 -104
  740. package/app/utils/chart-pipeline.ts +193 -0
  741. package/app/utils/chart-trend.ts +97 -97
  742. package/app/utils/dcw-driver-badge.ts +16 -16
  743. package/app/utils/dcw-recipe-form.ts +26 -26
  744. package/cli/commands/tui.mjs +28 -28
  745. package/cli/commands/update.mjs +124 -124
  746. package/cli/core/child-lifecycle.mjs +136 -136
  747. package/cli/core/meta.mjs +38 -38
  748. package/cli/core/post-build.mjs +96 -96
  749. package/config.yml +1 -1
  750. package/docs/cli.en.md +2 -2
  751. package/docs/cli.md +2 -2
  752. package/docs/mcp.en.md +27 -27
  753. package/docs/multi-harness-architecture.md +248 -248
  754. package/docs/plugins.en.md +1 -1
  755. package/docs/plugins.md +1 -1
  756. package/docs/sdk.en.md +1 -1
  757. package/docs/sdk.md +1 -1
  758. package/docs/tui.md +43 -43
  759. package/i18n/dicts/_en.json +1551 -1551
  760. package/i18n/dicts/_en2.json +300 -300
  761. package/i18n/dicts/_en4.json +114 -114
  762. package/i18n/dicts/agentLanesView.json +61 -61
  763. package/i18n/dicts/appHeader.json +17 -17
  764. package/i18n/dicts/channelSessionList.json +51 -51
  765. package/i18n/dicts/chat.json +79 -79
  766. package/i18n/dicts/clusterTool.json +4 -4
  767. package/i18n/dicts/composer.json +38 -38
  768. package/i18n/dicts/ctpl.json +37 -37
  769. package/i18n/dicts/dcwDetail.json +219 -219
  770. package/i18n/dicts/lineOps.json +14 -14
  771. package/i18n/dicts/multiChannelView.json +13 -13
  772. package/i18n/dicts/notifications.json +13 -13
  773. package/i18n/dicts/taskInspectorDrawer.json +25 -25
  774. package/i18n/dicts/teamPlugins.json +10 -10
  775. package/i18n/dicts/townView.json +209 -209
  776. package/i18n/locales/en.ts +46 -0
  777. package/i18n/locales/zh-CN.ts +46 -0
  778. package/mcp/discovery.mjs +227 -227
  779. package/package.json +1 -1
  780. package/public/favicon.svg +14 -14
  781. package/public/robots.txt +3 -3
  782. package/scripts/_audit/audit-harness-adapters.md +664 -664
  783. package/scripts/_audit/aw-mcp-live-e2e.mjs +293 -293
  784. package/scripts/_audit/bump-version.mjs +51 -51
  785. package/scripts/_audit/detached-instance.mjs +112 -112
  786. package/scripts/_audit/detached-start.mjs +103 -103
  787. package/scripts/_audit/eda-ui-fix-acceptance.mjs +212 -212
  788. package/scripts/_audit/guard-upstream-liveness.mjs +104 -104
  789. package/scripts/_audit/http-api-authz-audit.md +657 -657
  790. package/scripts/_audit/kb-team-mock-e2e.mjs +146 -146
  791. package/scripts/_audit/kb-team-omp-e2e.mjs +229 -229
  792. package/scripts/_audit/run.mjs +21 -21
  793. package/scripts/_audit/runtime-audit.md +716 -716
  794. package/scripts/_audit/skills-guided-e2e.mjs +316 -316
  795. package/scripts/_audit/stability-soak.mjs +252 -252
  796. package/scripts/_audit/stubs/nuxt-imports.mjs +67 -67
  797. package/scripts/_audit/ts-register-hook.mjs +12 -12
  798. package/scripts/_audit/ts-resolve-hook.mjs +96 -96
  799. package/scripts/_aw-packaged-start.cjs +22 -22
  800. package/scripts/_aw0746-stage12.mjs +94 -94
  801. package/scripts/_aw0746-stage34.mjs +136 -136
  802. package/scripts/_aw0746-stage6b-train-sweep.mjs +145 -145
  803. package/scripts/_aw0746-stage6c-jobsmoke.mjs +69 -69
  804. package/scripts/_dbg-configroot-audit.mjs +86 -86
  805. package/scripts/_dbg-daq-intervals-func.mjs +115 -115
  806. package/scripts/_dbg-perms-e2e.mjs +142 -142
  807. package/scripts/_dbg-protocol-matrix.mjs +462 -462
  808. package/scripts/_dbg-render-regression.mjs +193 -193
  809. package/scripts/_dbg-schedule-e2e.mjs +262 -262
  810. package/scripts/_e2e-ui-functional.mjs +371 -371
  811. package/scripts/_i18n-en-cjk-scan.mjs +28 -28
  812. package/scripts/_i18n-en-verify.mjs +107 -107
  813. package/scripts/_i18n-extra-checks.mjs +53 -53
  814. package/scripts/_i18n-scan-hardcoded.mjs +180 -180
  815. package/scripts/_lib-aml-python-run.mjs +17 -17
  816. package/scripts/_lint-reflow.mjs +105 -105
  817. package/scripts/_loop-biax-campaign.mjs +130 -130
  818. package/scripts/_plc-sim-detached.cjs +22 -22
  819. package/scripts/_probe-daq-omp-task.mjs +100 -100
  820. package/scripts/_probe-daq-scope-default.mjs +123 -123
  821. package/scripts/_probe-model-channel-link.cjs +25 -25
  822. package/scripts/_probe-recipe-switch.mjs +92 -92
  823. package/scripts/_provision-injection-line.mjs +39 -39
  824. package/scripts/_run-matrix.ps1 +53 -53
  825. package/scripts/_sweep-button-contrast.mjs +87 -87
  826. package/scripts/acceptance-aml-hybrid-e2e.ts +396 -396
  827. package/scripts/acceptance-aml-hybrid-live.mjs +93 -93
  828. package/scripts/acceptance-aml-model-identity.ts +137 -137
  829. package/scripts/agent-daq-isolation-e2e.mjs +91 -91
  830. package/scripts/api-contract-smoke.mjs +126 -126
  831. package/scripts/ask-hitl-e2e.mjs +96 -96
  832. package/scripts/aw-expose.mjs +159 -159
  833. package/scripts/channel-interaction-smoke.mjs +80 -80
  834. package/scripts/check-docs-sync.mjs +1 -1
  835. package/scripts/data-studio-ui-e2e.mjs +163 -163
  836. package/scripts/demo-group-chat-all-real.ts +279 -279
  837. package/scripts/demo-group-chat-omp-cases.ts +210 -210
  838. package/scripts/demo-group-chat-omp.ts +184 -184
  839. package/scripts/demo-group-chat-order.ts +197 -197
  840. package/scripts/dev-modbus-simulator.mjs +55 -55
  841. package/scripts/docs-shots.mjs +36 -36
  842. package/scripts/e2e-agentteam-chat.mjs +473 -473
  843. package/scripts/e2e-agentteam-real-triage.mjs +421 -421
  844. package/scripts/e2e-aml-decoupled.mjs +162 -162
  845. package/scripts/e2e-aw-tui-global.mjs +277 -277
  846. package/scripts/e2e-closedloop/cleanup.mjs +27 -27
  847. package/scripts/e2e-closedloop/lib.mjs +109 -109
  848. package/scripts/e2e-closedloop/main.mjs +59 -59
  849. package/scripts/e2e-closedloop/scenarios-accounts.mjs +210 -210
  850. package/scripts/e2e-closedloop/scenarios-authz.mjs +196 -196
  851. package/scripts/e2e-closedloop/scenarios-daq-dcw.mjs +222 -222
  852. package/scripts/e2e-closedloop/scenarios-plugins.mjs +169 -169
  853. package/scripts/e2e-closedloop/state.mjs +10 -10
  854. package/scripts/e2e-config-groups.mjs +238 -238
  855. package/scripts/e2e-crash-cycle.mjs +108 -108
  856. package/scripts/e2e-eda-pipeline.mjs +286 -0
  857. package/scripts/e2e-full-closedloop.mjs +16 -16
  858. package/scripts/e2e-hil-multi-user.mjs +307 -307
  859. package/scripts/e2e-hil-restart.mjs +339 -339
  860. package/scripts/e2e-injection-recipe-closedloop.mjs +203 -203
  861. package/scripts/e2e-line-governance.mjs +352 -352
  862. package/scripts/e2e-ontology.mjs +393 -393
  863. package/scripts/e2e-plc-plugin-closedloop.mjs +549 -549
  864. package/scripts/e2e-resume-crash.mjs +20 -6
  865. package/scripts/e2e-timezone-settings.mjs +59 -57
  866. package/scripts/full-stack-shots.mjs +145 -145
  867. package/scripts/full-tool-injection-harness-e2e.mjs +214 -214
  868. package/scripts/hitl-reject-e2e.mjs +131 -131
  869. package/scripts/line-log-smoke.mjs +260 -260
  870. package/scripts/live-aml-mockomp.mjs +304 -304
  871. package/scripts/live-aml-optloop-resume.mjs +322 -322
  872. package/scripts/live-aml-optloop.mjs +588 -588
  873. package/scripts/live-aml-stage9.mjs +169 -169
  874. package/scripts/live-aml-two-goals.mjs +315 -315
  875. package/scripts/live-optloop-two-modes.mjs +857 -857
  876. package/scripts/mes-agent-integration-e2e.mjs +361 -361
  877. package/scripts/ops-plugins-e2e.mjs +85 -85
  878. package/scripts/proof-omp-real.ts +189 -189
  879. package/scripts/scenario-suite-setup.mjs +337 -337
  880. package/scripts/scenario-suite-stability.mjs +144 -144
  881. package/scripts/smoke-optimization-verify.ts +72 -72
  882. package/scripts/team-coordination-e2e.mjs +96 -96
  883. package/scripts/test-agentteam-task-chat-flow.ts +420 -420
  884. package/scripts/test-agentteam-workflow.ts +472 -472
  885. package/scripts/test-aw-skills.mjs +102 -102
  886. package/scripts/test-cli-exit.mjs +343 -343
  887. package/scripts/test-daq-frame-race.mjs +358 -358
  888. package/scripts/test-data-root.mjs +208 -208
  889. package/scripts/test-events-index.mjs +176 -176
  890. package/scripts/test-group-chat-hardening.ts +265 -265
  891. package/scripts/test-group-chat-unit/lib.ts +186 -186
  892. package/scripts/test-group-chat-unit/main.ts +45 -45
  893. package/scripts/test-group-chat-unit/section-a-migration.ts +75 -75
  894. package/scripts/test-group-chat-unit/section-b-permission-matrix.ts +88 -88
  895. package/scripts/test-group-chat-unit/section-c-member-lifecycle.ts +64 -64
  896. package/scripts/test-group-chat-unit/section-d-mention-resolution.ts +36 -36
  897. package/scripts/test-group-chat-unit/section-e-chat-facts.ts +97 -97
  898. package/scripts/test-group-chat-unit/section-f-user-notifications.ts +52 -52
  899. package/scripts/test-group-chat-unit/section-g-member-projection.ts +44 -44
  900. package/scripts/test-group-chat-unit/section-h-outbox-consistency.ts +30 -30
  901. package/scripts/test-group-chat-unit/section-i-read-idempotency.ts +24 -24
  902. package/scripts/test-group-chat-unit/section-j-permission-scope.ts +150 -150
  903. package/scripts/test-group-chat-unit.ts +35 -35
  904. package/scripts/test-hitl-decision.ts +526 -526
  905. package/scripts/test-hitl-legacy-channel-auth.ts +143 -143
  906. package/scripts/test-hitl-registry.ts +112 -112
  907. package/scripts/test-log-flooding.mjs +160 -160
  908. package/scripts/test-lru.mjs +101 -101
  909. package/scripts/test-memory-month-query.mjs +70 -70
  910. package/scripts/test-plugin-hardening.mjs +90 -90
  911. package/scripts/test-plugin-lifecycle.mjs +173 -173
  912. package/scripts/test-rollback-index.mjs +137 -137
  913. package/scripts/test-schedule-runtime.ts +309 -309
  914. package/scripts/test-scheduler-loop/scenarios-supervise.ts +25 -25
  915. package/scripts/test-sdk-surface.mjs +158 -158
  916. package/scripts/test-serial-bridge.mjs +418 -418
  917. package/scripts/test-tui-commands.mjs +148 -148
  918. package/scripts/test-tui-reducers.mjs +72 -72
  919. package/scripts/three-system-e2e/lib.mjs +79 -79
  920. package/scripts/three-system-e2e/main.mjs +40 -40
  921. package/scripts/three-system-e2e/phases/phase-0-user-token.mjs +42 -42
  922. package/scripts/three-system-e2e/phases/phase-0a2-line-autoselect.mjs +35 -35
  923. package/scripts/three-system-e2e/phases/phase-0b-fixture-grants.mjs +39 -39
  924. package/scripts/three-system-e2e/phases/phase-0c-plugin-outbound-auth.mjs +95 -95
  925. package/scripts/three-system-e2e/phases/stage-1-health.mjs +47 -47
  926. package/scripts/three-system-e2e/phases/stage-2-5-team-plugins.mjs +84 -84
  927. package/scripts/three-system-e2e/phases/stage-2-teams-tools-hitl.mjs +184 -184
  928. package/scripts/three-system-e2e/phases/stage-3-diag.mjs +73 -73
  929. package/scripts/three-system-e2e/phases/stage-4-plugin-toggle.mjs +53 -53
  930. package/scripts/three-system-e2e/state.mjs +87 -87
  931. package/scripts/three-system-e2e.mjs +40 -40
  932. package/scripts/tool-face-batch-identity-e2e.mjs +222 -222
  933. package/scripts/tsconfig.json +14 -14
  934. package/scripts/tui-smoke.mjs +100 -100
  935. package/scripts/typecheck.mjs +75 -75
  936. package/scripts/ui/admin-shots.mjs +46 -46
  937. package/scripts/ui/bump-microfont.mjs +39 -39
  938. package/scripts/ui/linkcheck2.mjs +37 -37
  939. package/scripts/ui/live-render-check.mjs +72 -72
  940. package/scripts/ui/md-lint.mjs +80 -80
  941. package/scripts/ui/perf-audit.mjs +132 -132
  942. package/scripts/ui/readme-assets.mjs +30 -30
  943. package/scripts/ui/readme-shots.mjs +42 -42
  944. package/scripts/ui/record-demo.mjs +557 -557
  945. package/scripts/ui/record.mjs +225 -225
  946. package/scripts/ui/seed-admin.mjs +68 -68
  947. package/scripts/ui/seed-demo.mjs +83 -83
  948. package/scripts/ui/seed-industrial-demo.mjs +171 -171
  949. package/scripts/ui/shot-hero.mjs +25 -25
  950. package/scripts/ui/shots.mjs +75 -75
  951. package/scripts/ui/sim-ui-shot.mjs +16 -16
  952. package/scripts/ui/smoke-refactor.mjs +258 -258
  953. package/scripts/ui/verify-nav.mjs +51 -51
  954. package/scripts/ui/verify-responsive.mjs +285 -285
  955. package/sdk/client.d.mts +110 -110
  956. package/sdk/examples/line-sentinel/index.mjs +105 -105
  957. package/sdk/examples/ops-notifier/index.mjs +34 -34
  958. package/sdk/examples/sample-insight/index.mjs +39 -39
  959. package/server/api/plugins/client/[name].get.ts +18 -18
  960. package/server/api/plugins/i18n.get.ts +12 -12
  961. package/server/api/plugins/manifest.get.ts +10 -10
  962. package/server/api/system/backup/list.get.ts +32 -32
  963. package/server/api/system/backup/run.post.ts +21 -21
  964. package/server/api/system/config-groups/[id].delete.ts +21 -21
  965. package/server/api/system/config-groups/[id].patch.ts +26 -26
  966. package/server/api/system/config-groups/index.get.ts +21 -21
  967. package/server/api/system/config-groups/index.post.ts +33 -33
  968. package/server/api/system/timezone.get.ts +20 -20
  969. package/server/api/users/tokens/[id]/token.get.ts +11 -11
  970. package/server/api/workshop/[...path].ts +13 -13
  971. package/server/api/workshop/agent-tools/approvals/index.get.ts +43 -43
  972. package/server/api/workshop/agent-tools/bindings/[id].delete.ts +26 -26
  973. package/server/api/workshop/agent-tools/bindings/grant.post.ts +45 -45
  974. package/server/api/workshop/agent-tools/bindings/index.get.ts +41 -41
  975. package/server/api/workshop/agent-tools/bindings/revoke.post.ts +42 -42
  976. package/server/api/workshop/aml/datasets/[id]/preview.get.ts +68 -68
  977. package/server/api/workshop/aml/datasets/[id].delete.ts +39 -39
  978. package/server/api/workshop/aml/datasets/[id].get.ts +53 -53
  979. package/server/api/workshop/aml/datasets/[id].patch.ts +30 -30
  980. package/server/api/workshop/aml/datasets/index.get.ts +20 -20
  981. package/server/api/workshop/aml/datasets/index.post.ts +27 -27
  982. package/server/api/workshop/aml/entities/index.get.ts +13 -13
  983. package/server/api/workshop/aml/entities/prune.post.ts +28 -28
  984. package/server/api/workshop/aml/env/index.get.ts +13 -13
  985. package/server/api/workshop/aml/env/recheck.post.ts +14 -14
  986. package/server/api/workshop/aml/env/uv.post.ts +21 -21
  987. package/server/api/workshop/aml/env/venv.post.ts +24 -24
  988. package/server/api/workshop/aml/experiments/index.get.ts +35 -35
  989. package/server/api/workshop/aml/index.get.ts +37 -37
  990. package/server/api/workshop/aml/jobs/[id]/cancel.post.ts +21 -21
  991. package/server/api/workshop/aml/jobs/[id]/logs.get.ts +23 -23
  992. package/server/api/workshop/aml/jobs/[id]/retry.post.ts +20 -20
  993. package/server/api/workshop/aml/jobs/[id].delete.ts +44 -44
  994. package/server/api/workshop/aml/jobs/[id].get.ts +23 -23
  995. package/server/api/workshop/aml/jobs/index.get.ts +26 -26
  996. package/server/api/workshop/aml/models/[id]/predict.post.ts +24 -24
  997. package/server/api/workshop/aml/models/[id]/promote.post.ts +30 -30
  998. package/server/api/workshop/aml/models/index.get.ts +48 -48
  999. package/server/api/workshop/aml/training-plans/[id]/train.post.ts +18 -18
  1000. package/server/api/workshop/aml/training-plans/[id].delete.ts +18 -18
  1001. package/server/api/workshop/aml/training-plans/[id].patch.ts +30 -30
  1002. package/server/api/workshop/aml/training-plans/index.get.ts +9 -9
  1003. package/server/api/workshop/aml/training-plans/index.post.ts +43 -43
  1004. package/server/api/workshop/analysis/index.post.ts +54 -0
  1005. package/server/api/workshop/approvals/[id]/decide.post.ts +30 -30
  1006. package/server/api/workshop/approvals/index.get.ts +22 -22
  1007. package/server/api/workshop/audit.get.ts +43 -43
  1008. package/server/api/workshop/channels/[id]/chat/messages/[messageId]/read.post.ts +22 -22
  1009. package/server/api/workshop/channels/[id]/chat/messages/index.get.ts +29 -29
  1010. package/server/api/workshop/channels/[id]/chat/messages/index.post.ts +51 -51
  1011. package/server/api/workshop/channels/[id]/chat/permissions.get.ts +35 -35
  1012. package/server/api/workshop/channels/[id]/index.patch.ts +64 -64
  1013. package/server/api/workshop/channels/[id]/members/[userId]/approve.post.ts +20 -20
  1014. package/server/api/workshop/channels/[id]/members/[userId].delete.ts +21 -21
  1015. package/server/api/workshop/channels/[id]/members/index.get.ts +23 -23
  1016. package/server/api/workshop/channels/[id]/members/leave.post.ts +20 -20
  1017. package/server/api/workshop/channels/[id]/twin-profile.get.ts +45 -45
  1018. package/server/api/workshop/channels/[id]/twin-profile.patch.ts +72 -72
  1019. package/server/api/workshop/daq/[id]/test.post.ts +1 -1
  1020. package/server/api/workshop/daq/alarms.get.ts +16 -16
  1021. package/server/api/workshop/dcw/[id]/write.post.ts +4 -4
  1022. package/server/api/workshop/dcw/[id].delete.ts +41 -41
  1023. package/server/api/workshop/dcw/[id].patch.ts +40 -40
  1024. package/server/api/workshop/dcw/mes-test-read.post.ts +24 -24
  1025. package/server/api/workshop/dcw/params/[id]/read.post.ts +17 -17
  1026. package/server/api/workshop/dcw/params/[id]/write.post.ts +21 -21
  1027. package/server/api/workshop/dcw/params/[id].delete.ts +19 -19
  1028. package/server/api/workshop/dcw/params/[id].patch.ts +23 -23
  1029. package/server/api/workshop/dcw/params/index.get.ts +27 -27
  1030. package/server/api/workshop/dcw/params/index.post.ts +25 -25
  1031. package/server/api/workshop/dcw/products/[id].delete.ts +16 -16
  1032. package/server/api/workshop/dcw/products/[id].patch.ts +17 -17
  1033. package/server/api/workshop/dcw/recipes/[id]/index.patch.ts +22 -22
  1034. package/server/api/workshop/dcw/recipes/[id]/versions.get.ts +14 -14
  1035. package/server/api/workshop/dcw/recipes/[id].delete.ts +25 -25
  1036. package/server/api/workshop/dcw/recipes/index.get.ts +12 -12
  1037. package/server/api/workshop/dcw/runs/[id]/close.post.ts +15 -15
  1038. package/server/api/workshop/dcw/templates/[key].delete.ts +14 -14
  1039. package/server/api/workshop/dcw/templates/[key].patch.ts +16 -16
  1040. package/server/api/workshop/dcw/templates/index.post.ts +15 -15
  1041. package/server/api/workshop/dcw/test-driver.post.ts +16 -16
  1042. package/server/api/workshop/device-twins/[id].delete.ts +25 -25
  1043. package/server/api/workshop/eda/runs/[id]/labels.patch.ts +25 -25
  1044. package/server/api/workshop/eda/templates/[id].delete.ts +14 -0
  1045. package/server/api/workshop/eda/templates/[id].get.ts +15 -0
  1046. package/server/api/workshop/eda/templates/[id].patch.ts +20 -0
  1047. package/server/api/workshop/eda/templates/index.get.ts +11 -0
  1048. package/server/api/workshop/eda/templates/index.post.ts +20 -0
  1049. package/server/api/workshop/exp/confirmations/[id]/decide.post.ts +41 -41
  1050. package/server/api/workshop/exp/confirmations/index.get.ts +25 -25
  1051. package/server/api/workshop/harnesses/[id]/providers.get.ts +16 -16
  1052. package/server/api/workshop/hitl/respond.post.ts +94 -94
  1053. package/server/api/workshop/notifications/index.get.ts +60 -60
  1054. package/server/api/workshop/notifications/read.post.ts +31 -31
  1055. package/server/api/workshop/ontology/drafts/[draftId]/subgraph.ts +24 -24
  1056. package/server/api/workshop/plugins/[name]/disable.post.ts +21 -21
  1057. package/server/api/workshop/plugins/[name]/enable.post.ts +21 -21
  1058. package/server/api/workshop/plugins/[name]/index.get.ts +14 -14
  1059. package/server/api/workshop/schedules/[id]/run.post.ts +15 -15
  1060. package/server/api/workshop/schedules/[id]/runs.get.ts +15 -15
  1061. package/server/api/workshop/schedules/[id].delete.ts +14 -14
  1062. package/server/api/workshop/schedules/[id].get.ts +13 -13
  1063. package/server/api/workshop/schedules/[id].patch.ts +29 -29
  1064. package/server/api/workshop/schedules/index.get.ts +12 -12
  1065. package/server/api/workshop/schedules/index.post.ts +32 -32
  1066. package/server/api/workshop/tasks/[id]/reassign.post.ts +32 -32
  1067. package/server/api/workshop/tasks/[id]/update.post.ts +35 -35
  1068. package/server/api/workshop/teams/[id]/plugins/index.get.ts +36 -36
  1069. package/server/api/workshop/teams/[id]/plugins/index.put.ts +42 -42
  1070. package/server/api/workshop/ws/audience.ts +56 -56
  1071. package/server/api/workshop/ws/db-buffer.ts +68 -68
  1072. package/server/api/workshop/ws/event-mapping.ts +47 -47
  1073. package/server/api/workshop/ws/handlers.ts +132 -132
  1074. package/server/api/workshop/ws/hub.ts +133 -133
  1075. package/server/api/workshop/ws/index.ts +23 -23
  1076. package/server/api/workshop/ws/notification-uplink.ts +77 -77
  1077. package/server/api/workshop/ws/shared.ts +94 -94
  1078. package/server/api/workshop/ws/streams.ts +146 -146
  1079. package/server/middleware/00-security-headers.ts +38 -38
  1080. package/server/middleware/01-rate-guard.ts +101 -101
  1081. package/server/plugins/aml-twin-worker.ts +32 -32
  1082. package/server/plugins/dev-stability-guard.ts +42 -42
  1083. package/server/plugins-builtin/diag-bridge/host/constants.mjs +25 -25
  1084. package/server/plugins-builtin/diag-bridge/host/exports.mjs +104 -104
  1085. package/server/plugins-builtin/diag-bridge/host/helpers.mjs +2 -2
  1086. package/server/plugins-builtin/diag-bridge/host/index.mjs +15 -15
  1087. package/server/plugins-builtin/diag-bridge/host/intents.mjs +62 -62
  1088. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +5 -3
  1089. package/server/plugins-builtin/diag-bridge/host/snapshot.mjs +93 -93
  1090. package/server/plugins-builtin/diag-bridge/index.mjs +9 -9
  1091. package/server/plugins-builtin/serial-bridge/client.mjs +211 -211
  1092. package/server/plugins-builtin/serial-bridge/drivers.mjs +409 -409
  1093. package/server/plugins-builtin/serial-bridge/i18n.json +62 -62
  1094. package/server/plugins-builtin/serial-bridge/index.mjs +247 -247
  1095. package/server/plugins-builtin/serial-bridge/lib.mjs +208 -208
  1096. package/server/plugins-builtin/serial-bridge/rtu.mjs +168 -168
  1097. package/server/services/system-config/contracts.ts +29 -29
  1098. package/server/services/system-config/dispose.ts +19 -19
  1099. package/server/services/system-config/facade.ts +26 -26
  1100. package/server/services/system-config/groups.ts +108 -108
  1101. package/server/services/system-config/index.ts +21 -21
  1102. package/server/services/system-config/init.ts +26 -26
  1103. package/server/services/system-config/mutate.ts +103 -103
  1104. package/server/services/system-config/plugins.ts +104 -104
  1105. package/server/services/system-config/snapshot.ts +59 -59
  1106. package/server/services/system-config/state.ts +79 -79
  1107. package/server/services/system-config/types.ts +58 -58
  1108. package/server/services/workshop/agents/adapters/omp-rpc-client/api.ts +111 -111
  1109. package/server/services/workshop/agents/adapters/omp-rpc-client/contracts.ts +22 -22
  1110. package/server/services/workshop/agents/adapters/omp-rpc-client/facade.ts +7 -7
  1111. package/server/services/workshop/agents/adapters/omp-rpc-client/frames.ts +0 -18
  1112. package/server/services/workshop/agents/adapters/omp-rpc-client/helpers.ts +38 -38
  1113. package/server/services/workshop/agents/adapters/omp-rpc-client/index.ts +25 -25
  1114. package/server/services/workshop/agents/adapters/omp-rpc-client/start.ts +70 -70
  1115. package/server/services/workshop/agents/adapters/omp-rpc-client/state.ts +65 -65
  1116. package/server/services/workshop/agents/adapters/omp-rpc-client/stdout.ts +92 -92
  1117. package/server/services/workshop/agents/adapters/omp-rpc-client/usage.ts +47 -47
  1118. package/server/services/workshop/agents/agent-badge.ts +38 -38
  1119. package/server/services/workshop/agents/binding-authz.ts +60 -60
  1120. package/server/services/workshop/agents/binding-mode.ts +51 -51
  1121. package/server/services/workshop/agents/codex-agent/client.ts +170 -170
  1122. package/server/services/workshop/agents/codex-agent/core.ts +119 -119
  1123. package/server/services/workshop/agents/codex-agent/facade.ts +8 -8
  1124. package/server/services/workshop/agents/codex-agent/helpers.ts +13 -13
  1125. package/server/services/workshop/agents/codex-agent/hitl.ts +138 -138
  1126. package/server/services/workshop/agents/codex-agent/index.ts +14 -14
  1127. package/server/services/workshop/agents/codex-agent/turn.ts +367 -367
  1128. package/server/services/workshop/agents/codex-agent/types.ts +42 -42
  1129. package/server/services/workshop/agents/harness-process.ts +3 -3
  1130. package/server/services/workshop/agents/harness-terminal/api.ts +197 -197
  1131. package/server/services/workshop/agents/harness-terminal/index.ts +17 -17
  1132. package/server/services/workshop/agents/harness-terminal/io.ts +120 -120
  1133. package/server/services/workshop/agents/harness-terminal/park.ts +55 -55
  1134. package/server/services/workshop/agents/harness-terminal/sanitize.ts +98 -98
  1135. package/server/services/workshop/agents/harness-terminal/session.ts +124 -124
  1136. package/server/services/workshop/agents/harness-terminal/shared.ts +74 -74
  1137. package/server/services/workshop/agents/hitl-capabilities.ts +312 -312
  1138. package/server/services/workshop/agents/hitl-decision/answers.ts +32 -32
  1139. package/server/services/workshop/agents/hitl-decision/decide.ts +268 -268
  1140. package/server/services/workshop/agents/hitl-decision/payload.ts +45 -45
  1141. package/server/services/workshop/agents/hitl-decision/shared.ts +108 -108
  1142. package/server/services/workshop/agents/hitl-decision/visibility.ts +94 -94
  1143. package/server/services/workshop/agents/host-tool-bridge/tools/progress.ts +84 -84
  1144. package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +104 -104
  1145. package/server/services/workshop/agents/host-tool-bridge/tools/team.ts +70 -70
  1146. package/server/services/workshop/agents/industrial/aml-activity.ts +131 -131
  1147. package/server/services/workshop/agents/industrial/audit-query.ts +66 -66
  1148. package/server/services/workshop/agents/industrial/daq-tools.ts +352 -352
  1149. package/server/services/workshop/agents/industrial/exp-tools.ts +104 -104
  1150. package/server/services/workshop/agents/industrial/ops-tools.ts +16 -54
  1151. package/server/services/workshop/agents/industrial/param-tools.ts +69 -69
  1152. package/server/services/workshop/agents/industrial/recipe-gate.ts +6 -19
  1153. package/server/services/workshop/agents/industrial/recipe-propose-tools.ts +1 -1
  1154. package/server/services/workshop/agents/node-bindings.repo.ts +207 -207
  1155. package/server/services/workshop/agents/node-delegation.ts +159 -159
  1156. package/server/services/workshop/agents/omp-agent/core.ts +146 -146
  1157. package/server/services/workshop/agents/omp-agent/facade.ts +8 -8
  1158. package/server/services/workshop/agents/omp-agent/helpers.ts +37 -37
  1159. package/server/services/workshop/agents/omp-agent/index.ts +16 -16
  1160. package/server/services/workshop/agents/omp-agent/tools-steer.ts +1 -18
  1161. package/server/services/workshop/agents/omp-agent/types.ts +45 -45
  1162. package/server/services/workshop/agents/opencode-agent/core.ts +77 -77
  1163. package/server/services/workshop/agents/opencode-agent/facade.ts +8 -8
  1164. package/server/services/workshop/agents/opencode-agent/helpers.ts +29 -29
  1165. package/server/services/workshop/agents/opencode-agent/hitl.ts +113 -113
  1166. package/server/services/workshop/agents/opencode-agent/index.ts +16 -16
  1167. package/server/services/workshop/agents/opencode-agent/lifecycle.ts +44 -44
  1168. package/server/services/workshop/agents/opencode-agent/server.ts +244 -244
  1169. package/server/services/workshop/agents/opencode-agent/turn.ts +278 -278
  1170. package/server/services/workshop/agents/opencode-agent/types.ts +54 -54
  1171. package/server/services/workshop/agents/tool-classes.ts +44 -44
  1172. package/server/services/workshop/aml/clean.ts +120 -120
  1173. package/server/services/workshop/aml/entity.ts +367 -367
  1174. package/server/services/workshop/aml/job-orchestrator/broadcast.ts +37 -37
  1175. package/server/services/workshop/aml/job-orchestrator/control.ts +94 -94
  1176. package/server/services/workshop/aml/job-orchestrator/failure.ts +96 -96
  1177. package/server/services/workshop/aml/job-orchestrator/index.ts +22 -22
  1178. package/server/services/workshop/aml/job-orchestrator/process.ts +101 -101
  1179. package/server/services/workshop/aml/job-orchestrator/shared.ts +53 -53
  1180. package/server/services/workshop/aml/job-orchestrator/status.ts +20 -20
  1181. package/server/services/workshop/aml/job-orchestrator/tick.ts +37 -37
  1182. package/server/services/workshop/aml/python/train-example.py +92 -92
  1183. package/server/services/workshop/aml/runtime.ts +137 -137
  1184. package/server/services/workshop/aml/stats.ts +140 -140
  1185. package/server/services/workshop/aml/twin/calibration-worker.ts +150 -150
  1186. package/server/services/workshop/aml/twin/model-backed-provider.ts +332 -332
  1187. package/server/services/workshop/aml/twin/physics-spec-draft.ts +185 -185
  1188. package/server/services/workshop/aml/twin/prompt-composer.ts +143 -143
  1189. package/server/services/workshop/aml/twin/training-plans.ts +260 -260
  1190. package/server/services/workshop/aml/twin/write-guard.ts +19 -19
  1191. package/server/services/workshop/assets/character-asset.repo.ts +1 -1
  1192. package/server/services/workshop/assets/device-twin.repo.ts +1 -1
  1193. package/server/services/workshop/daq/bus/index.ts +5 -12
  1194. package/server/services/workshop/daq/daq-controller/contracts.ts +39 -39
  1195. package/server/services/workshop/daq/daq-controller/facade.ts +28 -28
  1196. package/server/services/workshop/daq/daq-controller/frames.ts +137 -137
  1197. package/server/services/workshop/daq/daq-controller/helpers.ts +52 -52
  1198. package/server/services/workshop/daq/daq-controller/index.ts +22 -22
  1199. package/server/services/workshop/daq/daq-controller/runtime-control.ts +72 -72
  1200. package/server/services/workshop/daq/daq-controller/sweep-alarms.ts +176 -176
  1201. package/server/services/workshop/daq/daq-controller/tsdb-twin.ts +138 -138
  1202. package/server/services/workshop/daq/drivers/http.ts +95 -95
  1203. package/server/services/workshop/daq/drivers/mock.ts +130 -130
  1204. package/server/services/workshop/daq/drivers/modbus-rtu.ts +67 -67
  1205. package/server/services/workshop/daq/drivers/modbus-tcp.ts +307 -307
  1206. package/server/services/workshop/daq/drivers/opcua.ts +227 -227
  1207. package/server/services/workshop/daq/drivers/s7-stub.ts +29 -29
  1208. package/server/services/workshop/daq/host-bindings.ts +71 -71
  1209. package/server/services/workshop/daq/host-ports.ts +65 -65
  1210. package/server/services/workshop/db/aml-team-seeds.ts +118 -118
  1211. package/server/services/workshop/db/backup-registry.ts +33 -33
  1212. package/server/services/workshop/db/channel-member.repo.ts +122 -122
  1213. package/server/services/workshop/db/channel.repo.ts +203 -203
  1214. package/server/services/workshop/db/chat-message.repo.ts +233 -233
  1215. package/server/services/workshop/db/database/index.ts +18 -18
  1216. package/server/services/workshop/db/database/json.ts +14 -14
  1217. package/server/services/workshop/db/database/open.ts +97 -97
  1218. package/server/services/workshop/db/database/seed-data.ts +60 -60
  1219. package/server/services/workshop/db/hitl-request.repo.ts +221 -221
  1220. package/server/services/workshop/db/notification.repo.ts +199 -199
  1221. package/server/services/workshop/db/readonly.ts +30 -30
  1222. package/server/services/workshop/db/scheduled-task.repo.ts +235 -235
  1223. package/server/services/workshop/db/transaction.ts +72 -72
  1224. package/server/services/workshop/dcw/dcw-controller/contracts.ts +16 -16
  1225. package/server/services/workshop/dcw/dcw-controller/control.ts +78 -78
  1226. package/server/services/workshop/dcw/dcw-controller/facade.ts +19 -19
  1227. package/server/services/workshop/dcw/dcw-controller/index.ts +22 -22
  1228. package/server/services/workshop/dcw/dcw-controller/params.ts +97 -97
  1229. package/server/services/workshop/dcw/dcw-controller/products.ts +103 -103
  1230. package/server/services/workshop/dcw/dcw-controller/write-audit.ts +49 -49
  1231. package/server/services/workshop/dcw/dcw-templates.ts +136 -136
  1232. package/server/services/workshop/dcw/param-conversion.ts +78 -78
  1233. package/server/services/workshop/dcw/param-map.repo.ts +349 -349
  1234. package/server/services/workshop/dcw/plugin-bridge.ts +45 -45
  1235. package/server/services/workshop/dcw/recipe-rollback-manager/contracts.ts +26 -26
  1236. package/server/services/workshop/dcw/recipe-rollback-manager/facade.ts +13 -13
  1237. package/server/services/workshop/dcw/recipe-rollback-manager/helpers.ts +30 -30
  1238. package/server/services/workshop/dcw/recipe-rollback-manager/index.ts +17 -17
  1239. package/server/services/workshop/dcw/recipe-rollback-manager/internal.ts +33 -33
  1240. package/server/services/workshop/dcw/recipe-rollback-manager/judge.ts +52 -52
  1241. package/server/services/workshop/dcw/recipe-rollback-manager/lock.ts +137 -137
  1242. package/server/services/workshop/dcw/recipe-rollback-manager/rollback.ts +190 -190
  1243. package/server/services/workshop/dcw/recipe-rollback-manager/state.ts +21 -21
  1244. package/server/services/workshop/dcw/recipe-rollback-manager/sweep.ts +77 -77
  1245. package/server/services/workshop/dcw/recipe-rollback-manager/types.ts +3 -3
  1246. package/server/services/workshop/dcw/recipe-rollback-manager/views.ts +214 -214
  1247. package/server/services/workshop/eda/chart-repo.ts +1 -1
  1248. package/server/services/workshop/eda/eda-db.ts +13 -0
  1249. package/server/services/workshop/eda/template-repo.ts +101 -0
  1250. package/server/services/workshop/exp/exp-collector.ts +275 -275
  1251. package/server/services/workshop/exp/exp-state.repo.ts +339 -339
  1252. package/server/services/workshop/mes/mes-controller.ts +1155 -1155
  1253. package/server/services/workshop/mes/mes-hook.ts +567 -567
  1254. package/server/services/workshop/ontology/subgraph.core.ts +300 -300
  1255. package/server/services/workshop/ontology/subgraph.service.ts +113 -113
  1256. package/server/services/workshop/plugins/host/api.mjs +90 -90
  1257. package/server/services/workshop/plugins/host/config.mjs +135 -135
  1258. package/server/services/workshop/plugins/host/index.mjs +23 -23
  1259. package/server/services/workshop/plugins/host/init.mjs +109 -109
  1260. package/server/services/workshop/plugins/host/load.mjs +321 -321
  1261. package/server/services/workshop/plugins/host/reload.mjs +94 -94
  1262. package/server/services/workshop/plugins/host/rollback.mjs +72 -72
  1263. package/server/services/workshop/plugins/host/state.mjs +54 -54
  1264. package/server/services/workshop/plugins/host/toggle.mjs +64 -64
  1265. package/server/services/workshop/plugins/host.mjs +9 -9
  1266. package/server/services/workshop/runtime/agent-runtime/facade.ts +7 -7
  1267. package/server/services/workshop/runtime/agent-runtime/helpers.ts +18 -18
  1268. package/server/services/workshop/runtime/agent-runtime/index.ts +19 -19
  1269. package/server/services/workshop/runtime/agent-runtime/lifecycle.ts +137 -137
  1270. package/server/services/workshop/runtime/chat-mention.ts +164 -164
  1271. package/server/services/workshop/runtime/chat-projection.ts +246 -246
  1272. package/server/services/workshop/runtime/manager/admin-agents.ts +268 -268
  1273. package/server/services/workshop/runtime/manager/bus.ts +182 -182
  1274. package/server/services/workshop/runtime/manager/channel-template-constants.ts +20 -20
  1275. package/server/services/workshop/runtime/manager/chat-reply.ts +181 -181
  1276. package/server/services/workshop/runtime/manager/chat.ts +384 -384
  1277. package/server/services/workshop/runtime/manager/facade.ts +24 -24
  1278. package/server/services/workshop/runtime/manager/helpers.ts +119 -119
  1279. package/server/services/workshop/runtime/manager/index.ts +42 -42
  1280. package/server/services/workshop/runtime/manager/internal.ts +73 -73
  1281. package/server/services/workshop/runtime/manager/notifications.ts +108 -108
  1282. package/server/services/workshop/runtime/manager/teams.ts +148 -148
  1283. package/server/services/workshop/runtime/memory/contracts.ts +18 -18
  1284. package/server/services/workshop/runtime/memory/facade.ts +10 -10
  1285. package/server/services/workshop/runtime/memory/helpers.ts +196 -196
  1286. package/server/services/workshop/runtime/memory/index.ts +27 -27
  1287. package/server/services/workshop/runtime/memory/score.ts +33 -33
  1288. package/server/services/workshop/runtime/memory/state.ts +40 -40
  1289. package/server/services/workshop/runtime/monitor.ts +3 -3
  1290. package/server/services/workshop/runtime/platform-notice.ts +113 -113
  1291. package/server/services/workshop/runtime/schedule-runtime.ts +347 -347
  1292. package/server/services/workshop/runtime/scheduler-loop/contracts.ts +29 -29
  1293. package/server/services/workshop/runtime/scheduler-loop/facade.ts +7 -7
  1294. package/server/services/workshop/runtime/scheduler-loop/helpers.ts +14 -14
  1295. package/server/services/workshop/runtime/scheduler-loop/index.ts +16 -16
  1296. package/server/services/workshop/runtime/task-engine/facade.ts +7 -7
  1297. package/server/services/workshop/runtime/task-engine/index.ts +15 -15
  1298. package/server/services/workshop/runtime/task-engine/types.ts +3 -3
  1299. package/server/services/workshop/runtime/user-notification-hub.ts +192 -192
  1300. package/server/types/pg.d.ts +49 -49
  1301. package/server/utils/approval-gate.ts +67 -67
  1302. package/server/utils/mojibake-guard.ts +29 -29
  1303. package/server/utils/stability-severity.ts +77 -77
  1304. package/shared/config/groups.mjs +241 -241
  1305. package/shared/dcw-protocol/catalog.ts +232 -232
  1306. package/shared/dcw-protocol/closed-loop.ts +137 -137
  1307. package/shared/lru.mjs +97 -97
  1308. package/tui/README.md +74 -74
  1309. package/tui/aw-tui.mjs +445 -445
  1310. package/tui/commands/index.mjs +287 -287
  1311. package/tui/components/chat-log.mjs +42 -42
  1312. package/tui/components/monitor-pane.mjs +39 -39
  1313. package/tui/components/root.mjs +53 -53
  1314. package/tui/components/status-bar.mjs +33 -33
  1315. package/tui/lib/api.mjs +82 -82
  1316. package/tui/lib/pickers.mjs +121 -121
  1317. package/tui/lib/reducers.mjs +218 -218
  1318. package/tui/lib/state.mjs +86 -86
  1319. package/tui/lib/virtual-terminal.mjs +48 -48
  1320. package/tui/lib/ws.mjs +125 -125
  1321. package/tui/theme.mjs +38 -38
  1322. package/.output/.AgentWorkShop/aml-python/__pycache__/aml_eval.cpython-312.pyc +0 -0
  1323. package/.output/.AgentWorkShop/aml-python/__pycache__/amlkit.cpython-312.pyc +0 -0
  1324. package/.output/.AgentWorkShop/aml-python/__pycache__/train-example.cpython-312.pyc +0 -0
  1325. package/.output/.AgentWorkShop/aml-python/__pycache__/train-hybrid-example.cpython-312.pyc +0 -0
  1326. package/.output/public/_nuxt/BRYBzVMJ.js +0 -1
  1327. package/.output/public/_nuxt/BW2uTUx52.js +0 -2
  1328. package/.output/public/_nuxt/BtZKe9ZV.js +0 -1
  1329. package/.output/public/_nuxt/CfFUK6932.js +0 -2
  1330. package/.output/public/_nuxt/D6FhDrYe2.js +0 -1
  1331. package/.output/public/_nuxt/DF9ETYJ32.js +0 -1
  1332. package/.output/public/_nuxt/DGu_fna7.js +0 -1
  1333. package/.output/public/_nuxt/D_59BNP1.js +0 -14
  1334. package/.output/public/_nuxt/DhW7cFOa.js +0 -1
  1335. package/.output/public/_nuxt/Dz9C2pTa.js +0 -1
  1336. package/.output/public/_nuxt/OmpTerminalPanel.ComMDrA8.css +0 -1
  1337. package/.output/public/_nuxt/PluginSlot.CGH0vb95.css +0 -1
  1338. package/.output/public/_nuxt/TownView.CC3t-Dte.css +0 -1
  1339. package/.output/public/_nuxt/YNhAoK-R2.js +0 -1
  1340. package/.output/public/_nuxt/aml.PalMp-5n.css +0 -1
  1341. package/.output/public/_nuxt/builds/meta/20934eea-96ab-412d-b0cd-0061716d8cc4.json +0 -1
  1342. package/.output/public/_nuxt/ontology.B_3Wn907.css +0 -1
  1343. package/.output/public/_nuxt/permissions.DxuOOIqQ.css +0 -1
  1344. package/.output/public/_nuxt/schedules.BXNJ9q_I.css +0 -1
  1345. package/.output/public/_nuxt/tools.BwXFAb-X.css +0 -1
  1346. package/.output/server/chunks/build/AuthGate-nF1evO4v.mjs +0 -716
  1347. package/.output/server/chunks/build/AuthGate-nF1evO4v.mjs.map +0 -1
  1348. package/.output/server/chunks/build/FormItemContext-BlyzocS0.mjs +0 -72
  1349. package/.output/server/chunks/build/FormItemContext-BlyzocS0.mjs.map +0 -1
  1350. package/.output/server/chunks/build/OmpTerminalPanel-BhvhQ1gG.mjs +0 -942
  1351. package/.output/server/chunks/build/OmpTerminalPanel-BhvhQ1gG.mjs.map +0 -1
  1352. package/.output/server/chunks/build/PluginSlot-BUKXwV2X.mjs +0 -141
  1353. package/.output/server/chunks/build/PluginSlot-BUKXwV2X.mjs.map +0 -1
  1354. package/.output/server/chunks/build/TownView-BWMDbosY.mjs +0 -6489
  1355. package/.output/server/chunks/build/TownView-BWMDbosY.mjs.map +0 -1
  1356. package/.output/server/chunks/build/_id_-BK-t8nRG.mjs +0 -392
  1357. package/.output/server/chunks/build/_id_-BK-t8nRG.mjs.map +0 -1
  1358. package/.output/server/chunks/build/_id_-CZPlPDm4.mjs +0 -2045
  1359. package/.output/server/chunks/build/_id_-CZPlPDm4.mjs.map +0 -1
  1360. package/.output/server/chunks/build/_wsId_-BPy-Aj9L.mjs +0 -14297
  1361. package/.output/server/chunks/build/_wsId_-BPy-Aj9L.mjs.map +0 -1
  1362. package/.output/server/chunks/build/agents-CpNLdI8E.mjs +0 -1078
  1363. package/.output/server/chunks/build/agents-CpNLdI8E.mjs.map +0 -1
  1364. package/.output/server/chunks/build/alert-D0ivtTGy.mjs +0 -263
  1365. package/.output/server/chunks/build/alert-D0ivtTGy.mjs.map +0 -1
  1366. package/.output/server/chunks/build/aml-DRAFRcGU.mjs +0 -814
  1367. package/.output/server/chunks/build/aml-DRAFRcGU.mjs.map +0 -1
  1368. package/.output/server/chunks/build/analysis-p-dBkjoK.mjs +0 -533
  1369. package/.output/server/chunks/build/analysis-p-dBkjoK.mjs.map +0 -1
  1370. package/.output/server/chunks/build/api-B4Om0mEc.mjs.map +0 -1
  1371. package/.output/server/chunks/build/api-BEW_ebY_.mjs.map +0 -1
  1372. package/.output/server/chunks/build/api-BsAgXWxi.mjs.map +0 -1
  1373. package/.output/server/chunks/build/api-error-BwAQLw44.mjs +0 -47
  1374. package/.output/server/chunks/build/api-error-BwAQLw44.mjs.map +0 -1
  1375. package/.output/server/chunks/build/apiClient-BvXtNzC8.mjs +0 -81
  1376. package/.output/server/chunks/build/apiClient-BvXtNzC8.mjs.map +0 -1
  1377. package/.output/server/chunks/build/board-Dl2Ar22r.mjs +0 -178
  1378. package/.output/server/chunks/build/board-Dl2Ar22r.mjs.map +0 -1
  1379. package/.output/server/chunks/build/card-Cqk0Ur-L.mjs +0 -953
  1380. package/.output/server/chunks/build/card-Cqk0Ur-L.mjs.map +0 -1
  1381. package/.output/server/chunks/build/channel-templates-ByHOQQkO.mjs +0 -942
  1382. package/.output/server/chunks/build/channel-templates-ByHOQQkO.mjs.map +0 -1
  1383. package/.output/server/chunks/build/checkbox-CrT4cnfu.mjs +0 -439
  1384. package/.output/server/chunks/build/checkbox-CrT4cnfu.mjs.map +0 -1
  1385. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs +0 -43
  1386. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs.map +0 -1
  1387. package/.output/server/chunks/build/core-CgTOPS4t.mjs +0 -294
  1388. package/.output/server/chunks/build/core-CgTOPS4t.mjs.map +0 -1
  1389. package/.output/server/chunks/build/daq-CdxcfY_G.mjs +0 -1266
  1390. package/.output/server/chunks/build/daq-CdxcfY_G.mjs.map +0 -1
  1391. package/.output/server/chunks/build/data-D8uX1dnm.mjs +0 -481
  1392. package/.output/server/chunks/build/data-D8uX1dnm.mjs.map +0 -1
  1393. package/.output/server/chunks/build/dcw-BlDQtS4q.mjs +0 -505
  1394. package/.output/server/chunks/build/dcw-BlDQtS4q.mjs.map +0 -1
  1395. package/.output/server/chunks/build/default-CNWS6NUw.mjs +0 -2353
  1396. package/.output/server/chunks/build/default-CNWS6NUw.mjs.map +0 -1
  1397. package/.output/server/chunks/build/descriptions-BNlfKG9y.mjs +0 -406
  1398. package/.output/server/chunks/build/descriptions-BNlfKG9y.mjs.map +0 -1
  1399. package/.output/server/chunks/build/drawer-Caji0PLs.mjs +0 -834
  1400. package/.output/server/chunks/build/drawer-Caji0PLs.mjs.map +0 -1
  1401. package/.output/server/chunks/build/dropdown-BNwTVGde.mjs +0 -14
  1402. package/.output/server/chunks/build/dropdown-BNwTVGde.mjs.map +0 -1
  1403. package/.output/server/chunks/build/dropdown-Cd-xPhR6.mjs +0 -540
  1404. package/.output/server/chunks/build/dropdown-Cd-xPhR6.mjs.map +0 -1
  1405. package/.output/server/chunks/build/es-Bxu10NJ2.mjs.map +0 -1
  1406. package/.output/server/chunks/build/firstNotUndefined-8H5_qHUu.mjs +0 -2448
  1407. package/.output/server/chunks/build/firstNotUndefined-8H5_qHUu.mjs.map +0 -1
  1408. package/.output/server/chunks/build/form-D_UpWPN4.mjs +0 -4712
  1409. package/.output/server/chunks/build/form-D_UpWPN4.mjs.map +0 -1
  1410. package/.output/server/chunks/build/hasIn-DBdElbjM.mjs +0 -553
  1411. package/.output/server/chunks/build/hasIn-DBdElbjM.mjs.map +0 -1
  1412. package/.output/server/chunks/build/hitl-Bd30yr1J.mjs +0 -132
  1413. package/.output/server/chunks/build/hitl-Bd30yr1J.mjs.map +0 -1
  1414. package/.output/server/chunks/build/input-GtPuSEgt.mjs +0 -2181
  1415. package/.output/server/chunks/build/input-GtPuSEgt.mjs.map +0 -1
  1416. package/.output/server/chunks/build/input-number-BNlNDK7H.mjs +0 -1120
  1417. package/.output/server/chunks/build/input-number-BNlNDK7H.mjs.map +0 -1
  1418. package/.output/server/chunks/build/interval-DvHBIIZh.mjs +0 -9
  1419. package/.output/server/chunks/build/interval-DvHBIIZh.mjs.map +0 -1
  1420. package/.output/server/chunks/build/isNumeric-CP7q_yhz.mjs +0 -7
  1421. package/.output/server/chunks/build/isNumeric-CP7q_yhz.mjs.map +0 -1
  1422. package/.output/server/chunks/build/logs-pRb-TMWa.mjs +0 -427
  1423. package/.output/server/chunks/build/logs-pRb-TMWa.mjs.map +0 -1
  1424. package/.output/server/chunks/build/menu-BXt-X0dt.mjs +0 -1952
  1425. package/.output/server/chunks/build/menu-BXt-X0dt.mjs.map +0 -1
  1426. package/.output/server/chunks/build/monitor-Cq6hRFeQ.mjs +0 -2253
  1427. package/.output/server/chunks/build/monitor-Cq6hRFeQ.mjs.map +0 -1
  1428. package/.output/server/chunks/build/ontology-DK0Mf0zT.mjs +0 -1406
  1429. package/.output/server/chunks/build/ontology-DK0Mf0zT.mjs.map +0 -1
  1430. package/.output/server/chunks/build/operations-SMQrRAcr.mjs +0 -311
  1431. package/.output/server/chunks/build/operations-SMQrRAcr.mjs.map +0 -1
  1432. package/.output/server/chunks/build/optimizer-BlWTsM-W.mjs +0 -202
  1433. package/.output/server/chunks/build/optimizer-BlWTsM-W.mjs.map +0 -1
  1434. package/.output/server/chunks/build/pages-AFRP4-EL.mjs +0 -542
  1435. package/.output/server/chunks/build/pages-AFRP4-EL.mjs.map +0 -1
  1436. package/.output/server/chunks/build/pagination-DTAconUo.mjs +0 -1346
  1437. package/.output/server/chunks/build/pagination-DTAconUo.mjs.map +0 -1
  1438. package/.output/server/chunks/build/permissions-DgXQZSyx.mjs +0 -637
  1439. package/.output/server/chunks/build/permissions-DgXQZSyx.mjs.map +0 -1
  1440. package/.output/server/chunks/build/plugins-LRjaSEZy.mjs +0 -272
  1441. package/.output/server/chunks/build/plugins-LRjaSEZy.mjs.map +0 -1
  1442. package/.output/server/chunks/build/popconfirm-DxYPGRgS.mjs +0 -340
  1443. package/.output/server/chunks/build/popconfirm-DxYPGRgS.mjs.map +0 -1
  1444. package/.output/server/chunks/build/responsiveObserve-DM3hpzhU.mjs +0 -78
  1445. package/.output/server/chunks/build/responsiveObserve-DM3hpzhU.mjs.map +0 -1
  1446. package/.output/server/chunks/build/schedules-dSnr8url.mjs +0 -7172
  1447. package/.output/server/chunks/build/schedules-dSnr8url.mjs.map +0 -1
  1448. package/.output/server/chunks/build/segmented-D3HWtHPw.mjs +0 -341
  1449. package/.output/server/chunks/build/segmented-D3HWtHPw.mjs.map +0 -1
  1450. package/.output/server/chunks/build/select-B3Dsb9yq.mjs +0 -3923
  1451. package/.output/server/chunks/build/select-B3Dsb9yq.mjs.map +0 -1
  1452. package/.output/server/chunks/build/settings-BrIhnS2Z.mjs +0 -1014
  1453. package/.output/server/chunks/build/settings-BrIhnS2Z.mjs.map +0 -1
  1454. package/.output/server/chunks/build/space-Dwu2Skt8.mjs +0 -110
  1455. package/.output/server/chunks/build/space-Dwu2Skt8.mjs.map +0 -1
  1456. package/.output/server/chunks/build/spin-C2cuvGth.mjs +0 -357
  1457. package/.output/server/chunks/build/spin-C2cuvGth.mjs.map +0 -1
  1458. package/.output/server/chunks/build/studio-cdoNCfyy.mjs +0 -332
  1459. package/.output/server/chunks/build/studio-cdoNCfyy.mjs.map +0 -1
  1460. package/.output/server/chunks/build/switch-CyR-H6Fb.mjs +0 -377
  1461. package/.output/server/chunks/build/switch-CyR-H6Fb.mjs.map +0 -1
  1462. package/.output/server/chunks/build/table-CmVD-cA9.mjs +0 -7546
  1463. package/.output/server/chunks/build/table-CmVD-cA9.mjs.map +0 -1
  1464. package/.output/server/chunks/build/tabs-Vg0e7cZE.mjs +0 -1924
  1465. package/.output/server/chunks/build/tabs-Vg0e7cZE.mjs.map +0 -1
  1466. package/.output/server/chunks/build/tag-y0sn-xv9.mjs +0 -1156
  1467. package/.output/server/chunks/build/tag-y0sn-xv9.mjs.map +0 -1
  1468. package/.output/server/chunks/build/teams-B1d32eHK.mjs +0 -1203
  1469. package/.output/server/chunks/build/teams-B1d32eHK.mjs.map +0 -1
  1470. package/.output/server/chunks/build/tokens-GYaGJ35Z.mjs +0 -1062
  1471. package/.output/server/chunks/build/tokens-GYaGJ35Z.mjs.map +0 -1
  1472. package/.output/server/chunks/build/tools-s_9U1Djj.mjs +0 -487
  1473. package/.output/server/chunks/build/tools-s_9U1Djj.mjs.map +0 -1
  1474. package/.output/server/chunks/build/tooltip-C2n2nNiQ.mjs +0 -920
  1475. package/.output/server/chunks/build/tooltip-C2n2nNiQ.mjs.map +0 -1
  1476. package/.output/server/chunks/build/town-B5aoiG98.mjs +0 -133
  1477. package/.output/server/chunks/build/town-B5aoiG98.mjs.map +0 -1
  1478. package/.output/server/chunks/build/useAgentHarnessOptions-DOrQHeBh.mjs +0 -124
  1479. package/.output/server/chunks/build/useAgentHarnessOptions-DOrQHeBh.mjs.map +0 -1
  1480. package/.output/server/chunks/build/useAgentTemplateActions-CzlplRWh.mjs +0 -77
  1481. package/.output/server/chunks/build/useAgentTemplateActions-CzlplRWh.mjs.map +0 -1
  1482. package/.output/server/chunks/build/useAgentTemplateForm-DQo1enf2.mjs +0 -117
  1483. package/.output/server/chunks/build/useAgentTemplateForm-DQo1enf2.mjs.map +0 -1
  1484. package/.output/server/chunks/build/useAgentTemplatesCatalog-DP-iMmqz.mjs +0 -133
  1485. package/.output/server/chunks/build/useAgentTemplatesCatalog-DP-iMmqz.mjs.map +0 -1
  1486. package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs +0 -92
  1487. package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs.map +0 -1
  1488. package/.output/server/chunks/build/useAmlEntities-BJhvdqHJ.mjs +0 -86
  1489. package/.output/server/chunks/build/useAmlEntities-BJhvdqHJ.mjs.map +0 -1
  1490. package/.output/server/chunks/build/useAmlEnv-CDIZ6xTe.mjs +0 -194
  1491. package/.output/server/chunks/build/useAmlEnv-CDIZ6xTe.mjs.map +0 -1
  1492. package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs +0 -89
  1493. package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs.map +0 -1
  1494. package/.output/server/chunks/build/useAmlJobs-BF9LpwXz.mjs +0 -267
  1495. package/.output/server/chunks/build/useAmlJobs-BF9LpwXz.mjs.map +0 -1
  1496. package/.output/server/chunks/build/useAmlModels-_bweOr3R.mjs +0 -93
  1497. package/.output/server/chunks/build/useAmlModels-_bweOr3R.mjs.map +0 -1
  1498. package/.output/server/chunks/build/useAmlNotes-DQj980iX.mjs +0 -86
  1499. package/.output/server/chunks/build/useAmlNotes-DQj980iX.mjs.map +0 -1
  1500. package/.output/server/chunks/build/useAmlPredict-DHNgDSJn.mjs +0 -130
  1501. package/.output/server/chunks/build/useAmlPredict-DHNgDSJn.mjs.map +0 -1
  1502. package/.output/server/chunks/build/useAnalysisFeed-BrEGV_9x.mjs +0 -129
  1503. package/.output/server/chunks/build/useAnalysisFeed-BrEGV_9x.mjs.map +0 -1
  1504. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs +0 -142
  1505. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs.map +0 -1
  1506. package/.output/server/chunks/build/useDaqDetailBinding-DCWaLKXT.mjs +0 -70
  1507. package/.output/server/chunks/build/useDaqDetailBinding-DCWaLKXT.mjs.map +0 -1
  1508. package/.output/server/chunks/build/useDaqDetailFrames-BOIcOJRB.mjs +0 -79
  1509. package/.output/server/chunks/build/useDaqDetailFrames-BOIcOJRB.mjs.map +0 -1
  1510. package/.output/server/chunks/build/useDaqDetailHistory-D6WulPVs.mjs +0 -176
  1511. package/.output/server/chunks/build/useDaqDetailHistory-D6WulPVs.mjs.map +0 -1
  1512. package/.output/server/chunks/build/useDaqDetailNode-DeOsDxK5.mjs +0 -99
  1513. package/.output/server/chunks/build/useDaqDetailNode-DeOsDxK5.mjs.map +0 -1
  1514. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs +0 -159
  1515. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs.map +0 -1
  1516. package/.output/server/chunks/build/useDaqFilters-CctmO03p.mjs +0 -222
  1517. package/.output/server/chunks/build/useDaqFilters-CctmO03p.mjs.map +0 -1
  1518. package/.output/server/chunks/build/useDaqOptimizations-CmX_dpBc.mjs +0 -136
  1519. package/.output/server/chunks/build/useDaqOptimizations-CmX_dpBc.mjs.map +0 -1
  1520. package/.output/server/chunks/build/useDaqStream-B9ZBVQrI.mjs +0 -395
  1521. package/.output/server/chunks/build/useDaqStream-B9ZBVQrI.mjs.map +0 -1
  1522. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs +0 -187
  1523. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs.map +0 -1
  1524. package/.output/server/chunks/build/useDashboardData-B36wVWo2.mjs +0 -153
  1525. package/.output/server/chunks/build/useDashboardData-B36wVWo2.mjs.map +0 -1
  1526. package/.output/server/chunks/build/useDcwAddNode-DACVcEHs.mjs +0 -219
  1527. package/.output/server/chunks/build/useDcwAddNode-DACVcEHs.mjs.map +0 -1
  1528. package/.output/server/chunks/build/useDcwCards-SaiImIYQ.mjs.map +0 -1
  1529. package/.output/server/chunks/build/useDcwDetailScope-DLOklSMO.mjs +0 -184
  1530. package/.output/server/chunks/build/useDcwDetailScope-DLOklSMO.mjs.map +0 -1
  1531. package/.output/server/chunks/build/useDcwDetailTemplates-ClmIdZ40.mjs +0 -148
  1532. package/.output/server/chunks/build/useDcwDetailTemplates-ClmIdZ40.mjs.map +0 -1
  1533. package/.output/server/chunks/build/useDcwFilter-CPMyCltx.mjs +0 -71
  1534. package/.output/server/chunks/build/useDcwFilter-CPMyCltx.mjs.map +0 -1
  1535. package/.output/server/chunks/build/useDcwLedger-0ie-0WTc.mjs.map +0 -1
  1536. package/.output/server/chunks/build/useDcwLineMutations-DNxo66yM.mjs +0 -137
  1537. package/.output/server/chunks/build/useDcwLineMutations-DNxo66yM.mjs.map +0 -1
  1538. package/.output/server/chunks/build/useDcwLineRun-CHskwscT.mjs +0 -104
  1539. package/.output/server/chunks/build/useDcwLineRun-CHskwscT.mjs.map +0 -1
  1540. package/.output/server/chunks/build/useDcwParamApprovals-DtScUc-W.mjs +0 -121
  1541. package/.output/server/chunks/build/useDcwParamApprovals-DtScUc-W.mjs.map +0 -1
  1542. package/.output/server/chunks/build/useDcwProducts-BMaxzLu6.mjs +0 -93
  1543. package/.output/server/chunks/build/useDcwProducts-BMaxzLu6.mjs.map +0 -1
  1544. package/.output/server/chunks/build/useDcwQuery-TVU3Eo0M.mjs +0 -98
  1545. package/.output/server/chunks/build/useDcwQuery-TVU3Eo0M.mjs.map +0 -1
  1546. package/.output/server/chunks/build/useDcwQuickActions-BREFmR9T.mjs +0 -88
  1547. package/.output/server/chunks/build/useDcwQuickActions-BREFmR9T.mjs.map +0 -1
  1548. package/.output/server/chunks/build/useDcwRecipes-Bc9urA1N.mjs +0 -258
  1549. package/.output/server/chunks/build/useDcwRecipes-Bc9urA1N.mjs.map +0 -1
  1550. package/.output/server/chunks/build/useDcwStream-Dir5ufAU.mjs +0 -452
  1551. package/.output/server/chunks/build/useDcwStream-Dir5ufAU.mjs.map +0 -1
  1552. package/.output/server/chunks/build/useDcwTemplates-BzagZztS.mjs +0 -91
  1553. package/.output/server/chunks/build/useDcwTemplates-BzagZztS.mjs.map +0 -1
  1554. package/.output/server/chunks/build/useDcwWrites-BROwTLCn.mjs +0 -140
  1555. package/.output/server/chunks/build/useDcwWrites-BROwTLCn.mjs.map +0 -1
  1556. package/.output/server/chunks/build/useDeviceTwins-BqwVJaZg.mjs +0 -128
  1557. package/.output/server/chunks/build/useDeviceTwins-BqwVJaZg.mjs.map +0 -1
  1558. package/.output/server/chunks/build/useExpConfirmations-BM626N4p.mjs +0 -107
  1559. package/.output/server/chunks/build/useExpConfirmations-BM626N4p.mjs.map +0 -1
  1560. package/.output/server/chunks/build/useLocalTime-uVSM44Um.mjs +0 -55
  1561. package/.output/server/chunks/build/useLocalTime-uVSM44Um.mjs.map +0 -1
  1562. package/.output/server/chunks/build/useLogsManual-cVBZQ_Mt.mjs +0 -88
  1563. package/.output/server/chunks/build/useLogsManual-cVBZQ_Mt.mjs.map +0 -1
  1564. package/.output/server/chunks/build/useLogsQuery-D7hrJ3yn.mjs +0 -150
  1565. package/.output/server/chunks/build/useLogsQuery-D7hrJ3yn.mjs.map +0 -1
  1566. package/.output/server/chunks/build/useLogsScope-aaPQeTRm.mjs +0 -83
  1567. package/.output/server/chunks/build/useLogsScope-aaPQeTRm.mjs.map +0 -1
  1568. package/.output/server/chunks/build/useMonitorData-DIkiLr_h.mjs +0 -135
  1569. package/.output/server/chunks/build/useMonitorData-DIkiLr_h.mjs.map +0 -1
  1570. package/.output/server/chunks/build/useMonitorFormat-CyURtH8N.mjs +0 -91
  1571. package/.output/server/chunks/build/useMonitorFormat-CyURtH8N.mjs.map +0 -1
  1572. package/.output/server/chunks/build/useOperationsFeed-Ci4mZAn_.mjs +0 -195
  1573. package/.output/server/chunks/build/useOperationsFeed-Ci4mZAn_.mjs.map +0 -1
  1574. package/.output/server/chunks/build/useOpsLog-C-M6Eace.mjs +0 -149
  1575. package/.output/server/chunks/build/useOpsLog-C-M6Eace.mjs.map +0 -1
  1576. package/.output/server/chunks/build/useRecipeDispatchApprovals-BYtiqfeb.mjs +0 -156
  1577. package/.output/server/chunks/build/useRecipeDispatchApprovals-BYtiqfeb.mjs.map +0 -1
  1578. package/.output/server/chunks/build/useTeamActions-I_8QWp9w.mjs +0 -79
  1579. package/.output/server/chunks/build/useTeamActions-I_8QWp9w.mjs.map +0 -1
  1580. package/.output/server/chunks/build/useTeamAddMemberDialog-BLn4nTuy.mjs +0 -84
  1581. package/.output/server/chunks/build/useTeamAddMemberDialog-BLn4nTuy.mjs.map +0 -1
  1582. package/.output/server/chunks/build/useTeamCreateDialog-Bp5qKtpI.mjs +0 -97
  1583. package/.output/server/chunks/build/useTeamCreateDialog-Bp5qKtpI.mjs.map +0 -1
  1584. package/.output/server/chunks/build/useTeamDeployDialog-DwIaz6Cx.mjs +0 -80
  1585. package/.output/server/chunks/build/useTeamDeployDialog-DwIaz6Cx.mjs.map +0 -1
  1586. package/.output/server/chunks/build/useTeamPluginDialog-B932gZOI.mjs +0 -103
  1587. package/.output/server/chunks/build/useTeamPluginDialog-B932gZOI.mjs.map +0 -1
  1588. package/.output/server/chunks/build/useTeamsCatalog-DBwaLQBw.mjs +0 -123
  1589. package/.output/server/chunks/build/useTeamsCatalog-DBwaLQBw.mjs.map +0 -1
  1590. package/.output/server/chunks/build/useTokenCreate-Ctl0YGhL.mjs +0 -115
  1591. package/.output/server/chunks/build/useTokenCreate-Ctl0YGhL.mjs.map +0 -1
  1592. package/.output/server/chunks/build/useTokenRename-Cm3ypSfN.mjs +0 -87
  1593. package/.output/server/chunks/build/useTokenRename-Cm3ypSfN.mjs.map +0 -1
  1594. package/.output/server/chunks/build/useTokenReveal-CeoWL5Mt.mjs +0 -118
  1595. package/.output/server/chunks/build/useTokenReveal-CeoWL5Mt.mjs.map +0 -1
  1596. package/.output/server/chunks/build/useTokensList-CNIzON3u.mjs +0 -92
  1597. package/.output/server/chunks/build/useTokensList-CNIzON3u.mjs.map +0 -1
  1598. package/.output/server/chunks/build/useWorkbenchAuth-CY-bVFMu.mjs +0 -141
  1599. package/.output/server/chunks/build/useWorkbenchAuth-CY-bVFMu.mjs.map +0 -1
  1600. package/.output/server/chunks/build/useWorkbenchWorkspaces-DhZQFss9.mjs +0 -138
  1601. package/.output/server/chunks/build/useWorkbenchWorkspaces-DhZQFss9.mjs.map +0 -1
  1602. package/.output/server/chunks/build/useWorkshopApi-CaSItJVq.mjs +0 -119
  1603. package/.output/server/chunks/build/useWorkshopApi-CaSItJVq.mjs.map +0 -1
  1604. package/.output/server/chunks/build/useWorkshopWs-YQ5URrbt.mjs +0 -1659
  1605. package/.output/server/chunks/build/useWorkshopWs-YQ5URrbt.mjs.map +0 -1
  1606. package/.output/server/chunks/build/useWorkspaceAuth-Dlvj9csD.mjs.map +0 -1
  1607. package/.output/server/chunks/build/useWorkspaceChannels-CPFepxTN.mjs +0 -92
  1608. package/.output/server/chunks/build/useWorkspaceChannels-CPFepxTN.mjs.map +0 -1
  1609. package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs +0 -168
  1610. package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs.map +0 -1
  1611. package/.output/server/chunks/build/users-DjiVC_tS.mjs +0 -569
  1612. package/.output/server/chunks/build/users-DjiVC_tS.mjs.map +0 -1
  1613. package/.output/server/chunks/build/workshop-1gKeDASV.mjs +0 -546
  1614. package/.output/server/chunks/build/workshop-1gKeDASV.mjs.map +0 -1
  1615. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.json +0 -1
  1616. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/1459e6269990a5d229b9228c8b2f62ffaa7d350068380ae8b875fee0db45cca6.source +0 -180
  1617. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/c2991e909c70c5c12b90a407c7adcf63384c51668a2b334e6e047fa675c268fe.source +0 -305
  1618. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/e09129039d1e27e3fac24becc9bdafd2d1a7c8049bff24173df007be865f0165.source +0 -264
  1619. package/app/.mimosa/hook-status/sess_05189059-e42d-4188-8911-4f7baabe009b-28ef7c75ea.json +0 -14
  1620. package/scripts/e2e-direct-rest-simulator-paper.mjs +0 -624
  1621. package/scripts/e2e-pi-simulator-paper.mjs +0 -2316
  1622. package/scripts/e2e-registered-harness-simulator-paper.mjs +0 -1926
  1623. package/scripts/e2e-simulator-optimizer-paper.mjs +0 -264
  1624. package/scripts/fixtures/omp-paper-harness.mjs +0 -163
  1625. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.json +0 -1
  1626. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.mvhn1irp-99488-e3fdc1cbfc.baseline/942d2679b87b96c612b4f2a425c3ccc5b6f3234f0cf589a8441602f866fbe277.source +0 -41
  1627. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.mvhn1irp-99488-e3fdc1cbfc.baseline/dd617a82339d2c61e49e28e416aabeb2fc100fb3cb1beca18d02dfb833214af6.source +0 -51
  1628. package/server/.mimosa/hook-status/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2-e67b6b91bf.json +0 -14
  1629. package/server/services/workshop/.mimosa/hook-state/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f.json +0 -1
  1630. package/server/services/workshop/.mimosa/hook-status/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f-e6b75bbfe6.json +0 -14
  1631. package/server/services/workshop/agents/omp-agent/supervision-history.ts +0 -38
  1632. package/server/services/workshop/aml/python/__pycache__/aml_eval.cpython-312.pyc +0 -0
  1633. package/server/services/workshop/aml/python/__pycache__/amlkit.cpython-312.pyc +0 -0
  1634. package/server/services/workshop/aml/python/__pycache__/train-example.cpython-312.pyc +0 -0
  1635. package/server/services/workshop/aml/python/__pycache__/train-hybrid-example.cpython-312.pyc +0 -0
  1636. package/server/services/workshop/optimization/python/.mimosa/hook-state/session_187ec97f45d4bd02369bbe94da527cf1.json +0 -1
  1637. package/server/services/workshop/optimization/python/.mimosa/hook-state/session_187ec97f45d4bd02369bbe94da527cf1.mvjqkcs6-68688-fb7131a89c.baseline/190a6772a4e43801737b4ba6072eb9d53d3099b5d8a9e6f57bc5e8592a26a6c4.source +0 -274
  1638. package/server/services/workshop/optimization/python/.mimosa/hook-status/session_187ec97f45d4bd02369bbe94da527cf1-01ed7f04fa.json +0 -14
  1639. package/server/services/workshop/optimization/python/__pycache__/problems.cpython-312.pyc +0 -0
  1640. /package/.output/public/_nuxt/{9j2J4k4w.js → 9j2J4k4w2.js} +0 -0
  1641. /package/.output/public/_nuxt/{BY3Lbz3h2.js → BY3Lbz3h.js} +0 -0
  1642. /package/.output/public/_nuxt/{DgrK8UCQ.js → BvRk9kiK2.js} +0 -0
  1643. /package/.output/public/_nuxt/{Iub61dX92.js → Iub61dX9.js} +0 -0
  1644. /package/.output/public/_nuxt/{Q-JpBT032.js → Q-JpBT03.js} +0 -0
  1645. /package/.output/public/_nuxt/{dVw8IHY62.js → dVw8IHY6.js} +0 -0
  1646. /package/.output/public/_nuxt/{k9b520K-.js → k9b520K-2.js} +0 -0
@@ -1,657 +1,657 @@
1
- # HTTP API authz / read-path / perf audit — agents + runtime + industrial nodes
2
-
3
- Read-only audit. Every claim cites `file:line` with verbatim code. No source file was modified.
4
-
5
- Scope read in full: `server/api/workshop/agent-tools/**`, `agents/**`, `channels/**`, `dcw/**`, `daq/**`,
6
- `runtime.get.ts`, `tasks.get.ts`, `mailbox.get.ts`, `caller.ts`, `server/services/workshop/scene-events.ts`,
7
- `server/services/workshop/agents/agent-badge.ts`, plus the guards they delegate to
8
- (`permissions.ts`, `runtime/manager.ts`, `agents/tool-approvals.ts`, `agents/node-bindings.repo.ts`,
9
- `agents/host-tool-bridge.ts`, `agents/industrial-tools.ts`, `dcw/dcw-controller.ts`, `daq/daq-controller.ts`,
10
- `aml/job-orchestrator.ts`, `aml/python-runtime.ts`).
11
-
12
- ---
13
-
14
- ## 1. AUTHZ AUDIT
15
-
16
- ### 0. Global facts
17
-
18
- * No global auth middleware exists. The only middleware is `server/middleware/request-log.ts:7` — logging only.
19
- * Unmatched `/api/workshop/**` paths hit `server/api/workshop/[...path].ts:12` → static 404.
20
- * Auth primitives (`server/api/workshop/caller.ts`):
21
- * `resolveUser` (`:71-79`) — Bearer **user** token, else 401.
22
- * `resolveCaller` (`:16-24`) — Bearer **agent instance** token, else 401.
23
- * `resolveAgentOrUser` (`:45-54`) — either domain.
24
- * `requireAdmin` (`:82-88`), `requireRole` (`:91-97`).
25
- * Line-grant model (`server/services/workshop/permissions.ts`): `isPrivilegedRole` (`:26-28`),
26
- `lineMode` (`:31-36`), `visibleLineIds` (`:39-42`), `filterByLine` (`:45-52`),
27
- `requireLineMode` (`:55-62`). admin/editor bypass everything.
28
-
29
- ### 1.1 [P0] `agent-tools/invoke.post.ts` — user token + client-supplied `agentId` = full agent impersonation
30
-
31
- The whole handler (27 lines):
32
-
33
- ```ts
34
- // server/api/workshop/agent-tools/invoke.post.ts:16-27
35
- export default defineApiHandler(async (event) => {
36
- const agentToken = getHeader(event, 'x-aw-agent-token')
37
- if (!agentToken) resolveUser(event) // 桥路径免用户鉴权,由 token 校验兜底
38
- const body = await readBody<{ agentId?: string, tool?: string, args?: Record<string, unknown> }>(event) ?? {}
39
- const agentId = String(body.agentId ?? '')
40
- const tool = String(body.tool ?? '')
41
- const args = body.args ?? {}
42
- if (!agentId) throw createError({ statusCode: 400, statusMessage: 'agentId required' })
43
- if (!tool) throw createError({ statusCode: 400, statusMessage: 'tool required' })
44
- const result = await getWorkshopManager().invokeHostTool({ agentId, tool, args, token: agentToken || undefined })
45
- return { result }
46
- })
47
- ```
48
-
49
- Note `invoke.post.ts:18`: `resolveUser(event)`'s **return value is discarded** — the authenticated user is never
50
- passed downstream. `agentId` comes only from the request body (`:20`).
51
-
52
- The guard it delegates to:
53
-
54
- ```ts
55
- // server/services/workshop/runtime/manager.ts:2746-2752
56
- async invokeHostTool(input: { agentId: string, token?: string, tool: string, args?: Record<string, unknown> }): Promise<{ text: string, isError?: boolean }> {
57
- const row = this.deps.repos.channelAgents.findById(input.agentId)
58
- if (!row || row.enabled !== 1) throw new AppError(404, 'NOT_FOUND', `agent 不存在或已停用: ${input.agentId}`)
59
- // token 鉴权(MCP 桥路径必带;缺省视为服务端内部调用,走 REST 已有用户鉴权)
60
- if (input.token !== undefined && input.token !== row.token) {
61
- throw new AppError(401, 'UNAUTHORIZED', 'agent token 校验失败')
62
- }
63
- ```
64
-
65
- `invoke.post.ts:25` passes `token: agentToken || undefined`. **Consequences, exactly:**
66
-
67
- | Request | `agentToken` | `input.token` | `manager.ts:2750` | Result |
68
- |---|---|---|---|---|
69
- | valid **user** Bearer, **no** `x-aw-agent-token`, `agentId` = any other agent | undefined | `undefined` | `input.token !== undefined` is **false** → check **skipped** | **Executes any tool as that agent** |
70
- | **no** `Authorization` at all, no `x-aw-agent-token` | undefined | — never reached | — | `resolveUser` at `invoke.post.ts:18` throws `AppError(401,'USER_UNAUTHORIZED')` (`caller.ts:76`) → **blocked** |
71
- | own agent token in `x-aw-agent-token`, `agentId` = another agent | own token | own token | `!== row.token` → true | 401 — **blocked** |
72
- | valid agent token, matching `agentId` | token | `=== row.token` | passes | legitimate |
73
-
74
- So the hole is exactly: **valid user token + arbitrary body `agentId` + absent `x-aw-agent-token`.** No ownership,
75
- membership or role check exists anywhere on this path. The authenticated `ResolvedUser` never reaches `manager`.
76
-
77
- After the guard, the impersonated identity drives every downstream authorization:
78
-
79
- ```ts
80
- // server/services/workshop/runtime/manager.ts:2769-2775
81
- const identity = {
82
- agentId: row.id,
83
- channelId: row.channelId,
84
- role: (row.role === 'lead' ? 'lead' : 'worker') as 'lead' | 'worker',
85
- name: row.name,
86
- }
87
- return await pluginTool.handler(input.args ?? {}, identity)
88
- ```
89
-
90
- ```ts
91
- // server/services/workshop/runtime/manager.ts:2777-2783
92
- const runtime = this.ensureAgentRuntime(row.channelId, input.agentId)
93
- if (runtime) {
94
- const viaImpl = await runtime.dispatchHostTool(input.tool, input.args ?? {})
95
- if (viaImpl) return viaImpl
96
- }
97
- // 回退:impl 未实现工具面(如 mock)→ 协作工具族直调
98
- return await this.invokeAgentWorkspaceTool(input.agentId, input.tool, input.args ?? {})
99
- ```
100
-
101
- `invokeHostTool` also applies **no role/tool filtering** — unlike `hostToolsForRole`
102
- (`host-tool-bridge.ts:70-87`) it never consults `LEAD_ONLY_TOOL_NAMES` (`host-tool-bridge.ts:33-43`).
103
- Every tool is dispatchable for any named agent that exists and is enabled.
104
-
105
- **Which tool classes are reachable, by whom**
106
-
107
- Reachable by *any* authenticated user token of *any* role (including a plain `user` with zero line grants):
108
- pick any lead/worker agent id.
109
-
110
- * **Read-only** (dispatch table `host-tool-bridge.ts:162-211` + `:219+`):
111
- `my_industrial_nodes`, `aml_node_catalog`, `aml_dataset_stats`, `aml_job_status`, `aml_job_logs`,
112
- `aml_leaderboard`, `aml_model_reference`, `dcw_read`, `daq_query`, `daq_frames`, `dcw_journal`, `ops_log`,
113
- `recipe_log`, `recipe_versions`, `line_context`, `list_other_teams`, `search_other_teams_memory`,
114
- mailbox/list-mail/memory tools.
115
- * **Mutating / control-plane**:
116
- * `dcw_control` — real PLC write. Its only authz is the *impersonated agent's* binding:
117
- ```ts
118
- // server/services/workshop/agents/industrial-tools.ts:99-108
119
- const repo = getAgentNodeBindingRepo()
120
- const binding: AgentNodeBinding | undefined = nodeId ? repo.find(agentId, nodeId, 'dcw') : undefined
121
- if (!binding) {
122
- ```
123
- HITL applies only when `binding.mode === 'manual'` (`industrial-tools.ts:128`); with `mode:'auto'`
124
- the write executes immediately (`industrial-tools.ts:157`).
125
- * `recipe_update` (`host-tool-bridge.ts:207-208`), `recipe_rollback` (`:209-210`), `dcw_judge` (`:193-194`),
126
- `dcw_rollback` (`:195-196`), `aml_dataset_build` (`:167-168`), `aml_job_cancel` (`:177-178`),
127
- `send_cross_channel_message` (`manager.ts:2725-2734`), `dispatch_task`, `create_team_agent`,
128
- `update_team_agent`, `remove_team_agent`, `complete_task`, `report_progress`.
129
- * `aml_model_promote` — nominally lead-only; its check is against the **DB role of the supplied agentId**:
130
- ```ts
131
- // server/services/workshop/agents/industrial-tools.ts:1290-1294
132
- // 治理硬守卫:晋升仅限 lead 实例(注入层过滤 + 分发层双重校验,HTTP 直调不可绕过)
133
- const roleRow = getAmlRuntime().db.prepare('SELECT role FROM channel_agents WHERE id = ? AND enabled = 1').get(agentId) as { role?: string } | undefined
134
- if (roleRow?.role !== 'lead') {
135
- return amlErr(`aml_model_promote 为 lead 专属工具:实例 ${agentId}(role=${roleRow?.role ?? '未知'})无权晋升模型。请由团队 lead 发起,晋升需人工 HITL 批准。`)
136
- }
137
- ```
138
- Naming a lead's `agentId` satisfies it (then HITL approval at `industrial-tools.ts:1316`).
139
- * `aml_job_submit` — **arbitrary Python execution on the server host.** The tool takes up to 500 KB of code:
140
- ```ts
141
- // server/services/workshop/agents/industrial-tools.ts:1152-1156
142
- if (!code.trim()) return amlErr('code 必填:train.py 全文(单文件;契约见工具说明)。')
143
- if (code.length > 512_000) return amlErr(`code 过大(${Math.round(code.length / 1024)}KB),上限 500KB;精简训练代码(模型定义/训练循环拆薄)后重试。`)
144
- if (!/\bimport\s+amlkit\b/.test(code)) {
145
- ```
146
- It is written to disk and executed:
147
- ```ts
148
- // server/services/workshop/aml/job-orchestrator.ts:285-287
149
- if (typeof inline === 'string' && inline.length > 0 && inline.length <= 512_000) {
150
- writeFileSync(join(workspace, 'train.py'), inline)
151
- trainFile = 'train.py'
152
- ```
153
- ```ts
154
- // server/services/workshop/aml/job-orchestrator.ts:328
155
- const exit1 = await runPython(run, vpy, [join(workspace, trainFile)], workspace)
156
- ```
157
- No container/OS sandbox; the only mitigation is a scrubbed env
158
- (`aml/python-runtime.ts:186-214`, `jobEnv` whitelist, "服务器 secrets … 一律不可见").
159
- The `import amlkit` requirement is a regex (`industrial-tools.ts:1154`), trivially satisfied.
160
- * Plugin tools: identity is the impersonated agent (`manager.ts:2769-2775`), no independent check —
161
- e.g. `diag_run` (`server/plugins-builtin/diag-bridge/index.mjs:449-450`) exports line DAQ snapshots,
162
- `kb_store`/`kb_index` (`server/plugins-builtin/rag-bridge/index.mjs:199,259`) mutate the knowledge base.
163
-
164
- **Contrast with the sibling endpoint, which does it right:**
165
-
166
- ```ts
167
- // server/api/workshop/agent-tools/list.get.ts:17-22
168
- if (agentToken) {
169
- const resolved = getWorkshopManager().resolveAgentByToken(String(agentToken))
170
- if (!resolved || resolved.agentId !== agentId) {
171
- throw createError({ statusCode: 401, statusMessage: 'agent token 校验失败' })
172
- }
173
- }
174
- ```
175
-
176
- **Enumeration is trivial**, so no guessing is needed: `agent-tools/bindings/index.get.ts:13` returns
177
- `{ bindings: agentId ? getAgentNodeBindingRepo().byAgent(agentId) : getAgentNodeBindingRepo().all() }` — with no
178
- `agentId` query param, **every** binding of every agent (agentId + nodeId + kind + mode) is returned to any
179
- authenticated user.
180
-
181
- ⚠UNVERIFIED: I did not execute a live exploit; the conclusion is from the code paths above (all read directly).
182
- Corroboration: the same finding is already written up at `docs/audit/audit-agents.md:186-249` ("the manager's
183
- token check is **skipped entirely** when no token is supplied … Minimal hardening: in `invokeHostTool` change the
184
- token check to `if (input.token !== row.token)`") — and the code is **unchanged**, i.e. unfixed.
185
-
186
- ### 1.2 `bindings/index.post.ts` — permission check quoted; **target agent ownership NOT verified**
187
-
188
- ```ts
189
- // server/api/workshop/agent-tools/bindings/index.post.ts:16-39
190
- export default defineApiHandler(async (event) => {
191
- const user = resolveUser(event)
192
- const body = await readBody<{ agentId?: string, nodeId?: string, kind?: 'dcw' | 'daq', mode?: 'auto' | 'manual' }>(event) ?? {}
193
- const kind = body.kind ?? 'dcw'
194
- const nodeId = String(body.nodeId ?? '')
195
- // 绑定前置:节点必须存在,且用户对其所属产线有足额权限
196
- const lineId = kind === 'daq'
197
- ? getDaqController().byId(nodeId)?.lineId
198
- : getDcwController().byId(nodeId)?.lineId
199
- if (!lineId) {
200
- throw new AppError(404, ErrorCodes.NOT_FOUND, `${kind === 'daq' ? '数采' : '写控'}节点不存在: ${nodeId}`)
201
- }
202
- const mode = lineMode(user, lineId)
203
- const needOperate = kind === 'dcw'
204
- if (mode === 'none' || (needOperate && mode !== 'operate')) {
205
- throw new AppError(403, 'LINE_FORBIDDEN', `无该产线权限:绑定${kind === 'daq' ? '数采' : '写控'}节点需对产线「${lineId}」拥有${needOperate ? '可操控' : '仅查看'}及以上权限`)
206
- }
207
- const binding = getAgentNodeBindingRepo().bind(
208
- String(body.agentId ?? ''),
209
- nodeId,
210
- kind,
211
- body.mode ?? 'auto',
212
- )
213
- return { binding }
214
- })
215
- ```
216
-
217
- The check at `:28-32` covers **the node's line only**. `body.agentId` is never resolved, never checked for
218
- existence, never checked for ownership/membership:
219
-
220
- ```ts
221
- // server/services/workshop/agents/node-bindings.repo.ts:73-78
222
- bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode): AgentNodeBinding {
223
- if (!agentId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'agentId 必填')
224
- if (!nodeId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'nodeId 必填')
225
- if (kind !== 'dcw' && kind !== 'daq') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知节点类型: ${kind}`)
226
- if (mode !== 'auto' && mode !== 'manual') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知控制模式: ${mode}`)
227
- ```
228
-
229
- Effect: **any** authenticated user with `operate` on one line can grant that control right to **any** agent id —
230
- their own, another user's agent, or a lead in an unrelated channel — or re-bind an existing agent with
231
- `"mode":"auto"` to strip HITL, because `bind()` updates the mode of an existing row
232
- (`node-bindings.repo.ts:79-83`: `if (prev) { prev.mode = mode; this.flush(); return prev }`).
233
- The granting user need not own, belong to, or even know anything about that agent.
234
-
235
- ### 1.3 Handlers that authenticate but never authorize the resource (IDOR)
236
-
237
- All of these call `resolveUser` and **discard the result** or use it only for logging — no ownership/role/line check:
238
-
239
- | Handler | Auth | Missing check | Impact |
240
- |---|---|---|---|
241
- | `agent-tools/bindings/[id].patch.ts:10-13` | `resolveUser(event)` (`:10`) | owner / role / line | Any user flips **any** binding's mode: `getAgentNodeBindingRepo().setMode(id, body.mode ?? 'auto')` → `"auto"` **disables HITL** for another team's writes (`node-bindings.repo.ts:97-104`) |
242
- | `agent-tools/bindings/[id].delete.ts:11-17` | `resolveUser(event)` (`:11`) | owner / role / line | Any user unbinds any agent↔node pair (`:17 !repo.unbind(id)`), also cancels that agent's pending approvals (`:19 getToolApprovals().cancelPendingFor(...)`) |
243
- | `agent-tools/bindings/index.get.ts:10-13` | `resolveUser(event)` (`:10`) | any scope filter | Full cross-tenant binding dump (see 1.1) |
244
- | `agent-tools/approvals/index.get.ts:11-16` | `resolveUser(event)` (`:11`) | ownership of `agentId` | Any user lists pending approvals of any agent: `getToolApprovals().listPending(agentId)`; history via `scope=history` |
245
- | `agent-tools/list.get.ts:13-23` | user token path (`:13`) | `agentId` ownership | Tool-schema disclosure for any agent |
246
- | `dcw/[id]/read.post.ts:13-16` | `resolveUser(event)` (`:13`) | **`requireLineMode` absent** | Any user triggers a real driver read on **any** dcw node id: `await getDcwController().readNow(id)` (`:16`) — cross-line data read |
247
- | `dcw/[id].patch.ts:12-16` | `resolveUser(event)` (`:12`) | role / line | Any user patches **any** dcw node: name/driver/range/enabled/position — `getDcwController().patch(id, body)` (`:16`). Widening `min/max` weakens the write interlock that `dcw_control` depends on |
248
- | `dcw/index.post.ts:13-16` | `resolveUser(event)` (`:13`) | role / line | Any user creates a write-control node (the comment at `:17` calls it "获得直写物理设备能力的入口") |
249
- | `dcw/lines/[id].delete.ts:15-21` | `resolveUser(event)` (`:15`) | role / line | Any user deletes **any** line; `?purge=1` cascades nodes/products/recipes (`:19-21`). The sibling create is admin/editor-gated (`dcw/lines/index.post.ts:14`) |
250
- | `dcw/lines/[id].patch.ts:11-14` | `resolveUser(event)` (`:11`) | role / line | Any user renames/recolors any line |
251
- | `dcw/recipes/[id].delete.ts:10-12` | `resolveUser(event)` (`:10`) | role | Any user deletes any recipe |
252
- | `dcw/recipes/index.post.ts:11-13` | `resolveUser(event)` (`:11`) | role | Any user creates recipes |
253
- | `dcw/recipes/[id]/index.patch.ts:12` , `[id]/revert.post.ts:12` | `resolveUser` | role | Any user edits/rewrites any recipe version history |
254
- | `dcw/products/[id].delete.ts:11-14`, `[id].patch.ts:12-16` | `resolveUser` | role | Any user deletes/edits any product (create requires admin/editor, `products/index.post.ts:12`) |
255
- | `dcw/runs/[id]/close.post.ts:11-14` | `resolveUser(event)` (`:11`) | role | Any user closes any production run window |
256
- | `dcw/templates/index.post.ts:11-13`, `[key].patch.ts:11-14`, `[key].delete.ts:10-12` | `resolveUser` | role | Any user mutates control templates (driver configs) |
257
- | `dcw/test-driver.post.ts:12-15` | `resolveUser(event)` (`:12`) | role | Any user makes the server open outbound connections with a caller-supplied `driverConfig`: `getDcwController().testDriver(body.driver ?? 'mock', body.driverConfig ?? {})` |
258
- | `daq/test-driver.post.ts:17-21` | `resolveUser(event)` (`:17`) | role | Same SSRF-ish connect primitive for DAQ protocols |
259
- | `daq/[id]/test.post.ts:12-15` | `resolveUser(event)` (`:12`) | **`requireLineMode` absent** | Any user triggers a real connection test on any DAQ node (`:15 testNode(id)`); the dcw twin requires `operate` (`dcw/[id]/test.post.ts:16`) |
260
- | `daq/[id].delete.ts:13-17` | `resolveUser(event)` (`:13`) | **`requireLineMode` absent** | Any user deletes any DAQ node; the patch twin requires `operate` (`daq/[id].patch.ts:19`) |
261
- | `daq/infra/reconnect.post.ts:9-15` | `resolveUser(event)` (`:9`) | role | Any user triggers infra bring-up: `await apply(daqInfraConfig())` → `__daqApplyInfra` runs `docker compose -f … up -d …` (`server/services/workshop/daq/infra.ts:85`) |
262
- | `daq/alarms.get.ts:11-15` | `resolveUser(event)` (`:11`) | line filter | Any user reads **all** alarms of **all** lines (`:15 listAlarms(scope, limit)`); `daq/index.get.ts:27` filters by line, this one does not |
263
- | `daq/templates/*` (`index.post.ts:12`, `[key].patch.ts:12`, `[key].delete.ts:12`) | `resolveUser` | role | Any user mutates signal templates |
264
- | `dcw/journal/index.get.ts:11-19` | `resolveUser(event)` (`:11`) | line scope | Any user reads the full parameter ledger for any `lineId`/`nodeId` supplied in the query |
265
- | `dcw/[id]/param-ledger.get.ts:11-13` | `resolveUser(event)` (`:11`) | **`requireLineMode` absent** | Any user reads any node's setpoints/targets/last-good values |
266
- | `dcw/optimizations/index.get.ts:11-21`, `[id].get.ts:11-16`, `[id]/series.get.ts:12-17` | `resolveUser` | line scope | Any user reads any line's optimization records + raw DAQ series |
267
- | `dcw/recipes/index.get.ts:9-11` | `resolveUser(event)` (`:9`) | line scope | Returns `repo.list()`/`listRuns()` with **no** `visibleLineIds` filter (contrast `dcw/index.get.ts:29-30`, `dcw/runs/index.get.ts:12`) |
268
- | `dcw/recipes/[id]/versions.get.ts:11-13` | `resolveUser` | line scope | Any user reads any recipe's full parameter version history |
269
- | `server/api/workshop/runtime.get.ts:9-10` | `resolveUser(event)` (`:9`) | role | Any user enumerates wired harness agent ids + active channels |
270
- | `server/api/workshop/daq/infra.get.ts:9` | `resolveUser` | role | Infra status disclosure (low) |
271
-
272
- ### 1.4 Handlers that ARE correctly guarded (control set)
273
-
274
- * `agents/[id].get.ts:16-17` → `manager.requireTemplateReadable`; `agents/[id].patch.ts:28`, `[id].delete.ts:17` → `requireWritable` (`manager.ts:1083-1090`).
275
- * `channels/[id].delete.ts:14-15`, `index.patch.ts:35-36`, `agents/index.post.ts:32-33`, `agents/[agentId].delete.ts:17-18`, `[agentId].patch.ts:18-19`, `model.patch.ts:20-21`, `position.patch.ts:19-20`, `range.patch.ts:19-20`, `stop.post.ts:18-19` → `getChannelForUser` + `requireWritable` + membership check (`manager.ts:1103-1110`, `:1067-1074`).
276
- * `channels/[id]/messages/index.post.ts:38-39`, `tasks/index.post.ts:67-68`, `tasks/index.get.ts:22`, `queue.get.ts:17`, `events.get.ts:28`, `terminals.get.ts:19`, `messages/index.get.ts:21`, `channels/[id]/index.get.ts:13` → `getChannelForUser` (owner-or-legacy-public read).
277
- * Memory planes: `channels/[id]/memories/**` and `channels/[id]/agents/[agentId]/memories/**` → `resolveAgentOrUser` + same-channel or `getChannelForUser`+`requireOwned`, and the manager re-checks role: `manager.ts:1508` (`仅本人或 lead 可策展 Agent 记忆`), `:1463` (`仅 lead 可写团队记忆`), `:1487`, `:1548`.
278
- ⚠ Note (by design, not a bug): `manager.searchAgentMemories` (`manager.ts:1441-1446`) only calls `requireMember(channelId, callerAgentId)` — **any teammate agent in the channel can search another agent's private memory** by passing that agent's id in the URL with `scope:'private'`.
279
- * `agents/subscribe.post.ts:17-19` → `resolveCaller` + `manager.subscribe` → `requireMember` + same-channel target check (`manager.ts:2884-2893`).
280
- * `tasks.get.ts:11-12` / `mailbox.get.ts:10-13` → `resolveCaller`, scope forced to `caller.channelId`/`caller.id`.
281
- * Role-gated: `dcw/controller.post.ts:15`, `dcw/[id].delete.ts:14`, `dcw/lines/index.post.ts:14`, `dcw/journal/node/[nodeId]/rollback.post.ts:15`, `dcw/optimizations/[id]/judge.post.ts:15`, `[id]/rollback.post.ts:17`, `dcw/products/index.post.ts:12`, `dcw/recipes/[id]/apply.post.ts:15`, `[id]/mark-good.post.ts:13`, `[id]/rollback-good.post.ts:13`, `dcw/runs/[id]/rollback.post.ts:14`, `daq/controller.post.ts:29,49`, `daq/index.post.ts:16` (all `requireRole`/`gateDangerous`).
282
- * `agent-tools/approvals/[id]/decide.post.ts:12-19` — `resolveUser` **used** (decider recorded + `audit`).
283
-
284
- ### 1.5 `requireLineMode` / `lineMode` audit for daq/dcw handlers
285
-
286
- **Called (correct):**
287
-
288
- | Handler | Line | Quote |
289
- |---|---|---|
290
- | `dcw/[id]/write.post.ts` | `:19` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
291
- | `dcw/[id]/test.post.ts` | `:16` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
292
- | `dcw/[id]/bind.post.ts` | `:16` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
293
- | `dcw/[id]/bindings.put.ts` | `:17` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
294
- | `dcw/lines/[id]/start.post.ts` | `:20` | `requireLineMode(user, id, 'operate')` |
295
- | `dcw/lines/[id]/stop.post.ts` | `:20` | `requireLineMode(user, id, 'operate')` |
296
- | `dcw/runs/[id]/data.get.ts` | `:18` | `requireLineMode(user, run?.lineId, 'readonly')` |
297
- | `daq/[id].patch.ts` | `:19` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'operate')` |
298
- | `daq/[id]/bind.post.ts` | `:18`, `daq/[id]/bindings.put.ts:18` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'operate')` |
299
- | `daq/[id]/samples.get.ts` | `:16`, `daq/[id]/frames.get.ts:16`, `daq/[id]/frames/content.get.ts:17` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'readonly')` |
300
- | `daq/alarms/[id]/ack.post.ts` | `:17` | `requireLineMode(user, alarmNodeId ? getDaqController().byId(alarmNodeId)?.lineId : undefined, 'operate')` |
301
- | `dcw/index.get.ts` | `:18-36` | `visibleLineIds` + `filterByLine` (+ per-line `.filter`) |
302
- | `dcw/lines/index.get.ts` | `:15-18`, `dcw/line/query.get.ts:18-21`, `dcw/runs/index.get.ts:12`, `daq/index.get.ts:27` | `visibleLineIds`/`filterByLine`; `dcw/line/query.get.ts:19-21` throws `403 LINE_FORBIDDEN` when `lineId` is outside the visible set |
303
- | `agent-tools/bindings/index.post.ts` | `:28-32` | `lineMode(user, lineId)` (node line only — see 1.2) |
304
-
305
- **NOT called, where a line-scoped resource is addressed** (all cited in §1.3 with their guards):
306
- `dcw/[id]/read.post.ts` (no line check on a real driver read — worst of these),
307
- `dcw/[id].patch.ts`, `dcw/[id]/param-ledger.get.ts`, `dcw/journal/index.get.ts`,
308
- `dcw/optimizations/index.get.ts`, `dcw/optimizations/[id].get.ts`, `dcw/optimizations/[id]/series.get.ts`,
309
- `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`, `dcw/recipes/[id].delete.ts`,
310
- `dcw/recipes/[id]/index.patch.ts`, `dcw/recipes/[id]/revert.post.ts`, `dcw/products/[id].patch.ts`,
311
- `dcw/products/[id].delete.ts`, `dcw/runs/[id]/close.post.ts`, `dcw/lines/[id].patch.ts`,
312
- `dcw/lines/[id].delete.ts`, `dcw/index.post.ts`, `dcw/templates/*`,
313
- `daq/[id].delete.ts`, `daq/[id]/test.post.ts`, `daq/alarms.get.ts`, `daq/templates/*`,
314
- `daq/test-driver.post.ts`, `dcw/test-driver.post.ts`.
315
-
316
- ---
317
-
318
- ## 2. READ-PATH WRITES (`*.get.ts` that mutate)
319
-
320
- | GET handler | Write / side effect | Quote |
321
- |---|---|---|
322
- | `server/api/workshop/daq/index.get.ts:22` | **DB insert + runtime creation + 250 ms timer**: `provisionLegacyTwins()` → `this.repo.insert(node)` | `ctrl.provisionLegacyTwins()` (`index.get.ts:22`); `daq-controller.ts:1142-1159`: `provisionLegacyTwins(): void {` … `this.repo.insert(node)` (`:1157`) … `this.syncRuntimes()` (`:1159`); `ensureLoop()` at `:1143` starts `this.timer = setInterval(() => this.sweep(), 250)` (`:191`) |
323
- | `server/api/workshop/daq/index.get.ts:20` | Pipeline power-on: queue consumer + TSDB init | `await Promise.all([tsdbReady, getDaqQueue()])` (`:20`); comment `:18` `// ws.ts 出口装配 + 管线上电(幂等;路由模块加载即绑定)` |
324
- | `server/api/workshop/daq/[id]/samples.get.ts:23` (via `:16` guard) | **Starts acquisition**: `samples()` → `ensureLoop()` | route `:23 const points = await getDaqController().samples(id, {...})`; `daq-controller.ts:793-795`: `async samples(id, opts) {` / `this.ensureLoop()` / `await tsdbReady` |
325
- | `server/api/workshop/daq/[id]/frames.get.ts:20` | same | route `:20 const frames = await getDaqController().frames(id, {...})`; `daq-controller.ts:835 this.ensureLoop()` |
326
- | `server/api/workshop/daq/[id]/frames/content.get.ts:23` | same | route `:23 const { data, mime } = await getDaqController().frameContent(...)`; `daq-controller.ts:854 this.ensureLoop()` |
327
- | `server/api/workshop/channels/[id]/index.get.ts:16` | **Assembles lead runtime + starts SchedulerLoop (timer + loop resubmit callback)** | `ensureLeadSchedulerLoop(manager, channelId)` (`:16`), comment `:15` `// 兜底:详情请求时确保 lead 的调度循环已装配(如启动恢复遗漏)`; → `plugins/workshop.ts:73 manager.ensureChannelActive(channelId, options)` → `manager.ts:697-719` `const cr = this.ensureChannelRuntime(channelId)` … `cr.scheduler = loop` / `loop.start()` ⚠(whether `wireMember` immediately spawns a harness subprocess was not traced) |
328
- | `server/api/workshop/dcw/index.get.ts:13`, `dcw/lines/index.get.ts:12`, `dcw/line/query.get.ts:15`, `dcw/runs/[id]/data.get.ts:14` | Global binding mutation: repoints the controller's broadcast sink each request | `bindDcwBroadcast(broadcastSceneEvent)` → `dcw-controller.ts` `setBroadcast(fn)`; `daq/index.get.ts:19`, `dcw/[id]/read.post.ts:14` etc. use `bindDaqHost(broadcastSceneEvent)` |
329
- | `server/api/workshop/dcw/index.get.ts:32` | Over-fetch then JS trim (not a write, but a read amplification) | `ctrl.listHistory(400).filter(h => inLine(nodeLine(h.nodeId))).slice(0, 60)` |
330
-
331
- **Purely read-only GETs (verified line by line):** `agent-tools/list.get.ts`, `agent-tools/approvals/index.get.ts`,
332
- `agent-tools/bindings/index.get.ts`, `agents/index.get.ts`, `agents/[id].get.ts`,
333
- `channels/[id]/events.get.ts`, `channels/[id]/queue.get.ts`, `channels/[id]/tasks/index.get.ts`,
334
- `channels/[id]/terminals.get.ts` (`harness-terminal.ts:451-466` pure map over a Map),
335
- `channels/[id]/messages/index.get.ts`, `channels/[id]/agents/index.get.ts`,
336
- `channels/[id]/memories/index.get.ts`, `channels/[id]/agents/[agentId]/memories/index.get.ts`,
337
- `channels/[id]/plugins/index.get.ts`, `dcw/index.get.ts` (only the binding call above),
338
- `dcw/lines/index.get.ts`, `dcw/line/query.get.ts`, `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`,
339
- `dcw/runs/index.get.ts`, `dcw/runs/[id]/data.get.ts` (`dcw-controller.ts:964-999` queries only),
340
- `dcw/journal/index.get.ts` (`recipe-rollback-manager.ts:652-654`), `dcw/[id]/param-ledger.get.ts` (`:627-649`),
341
- `dcw/optimizations/index.get.ts` (`:656-658`), `dcw/optimizations/[id].get.ts`,
342
- `dcw/optimizations/[id]/series.get.ts` (`:602-623` read-only), `daq/alarms.get.ts` (`daq-controller.ts:600-604`),
343
- `daq/infra.get.ts`, `runtime.get.ts` (`manager.ts:803-808`), `tasks.get.ts`, `mailbox.get.ts`
344
- (`manager.ts:2834-2840`; the query has no LIMIT — see §3).
345
-
346
- Note the memory list GET `channels/[id]/agents/[agentId]/memories/index.get.ts:28` calls `manager.listMemories`
347
- which is a pure read (`manager.ts:1421-1426`).
348
-
349
- ---
350
-
351
- ## 3. UNBOUNDED STATE + PERF
352
-
353
- ### 3.1 Module-level maps/sets/arrays in scope
354
-
355
- 1. **`server/api/workshop/caller.ts:122` — unbounded, no eviction.**
356
- ```ts
357
- const nameCache = new Map<string, { name: string | null, at: number }>()
358
- ```
359
- Writes (all writes in the file):
360
- ```ts
361
- // caller.ts:124-134
362
- const hit = nameCache.get(userId)
363
- if (hit && Date.now() - hit.at < 60_000) return hit.name
364
- ...
365
- nameCache.set(userId, { name, at: Date.now() })
366
- ```
367
- The 60 s TTL is consulted only when the **same** key is read again; there is **no eviction found** (no sweep,
368
- no size cap, no `delete`). Every distinct `ownerUserId` ever rendered by `withOwnerNames` stays for the process
369
- lifetime. `withOwnerNames` (`caller.ts:105-119`) creates a per-call `Map` (`:106`) which is request-scoped (fine).
370
- 2. **`server/services/workshop/scene-events.ts:20-27` — unbounded, no cap.**
371
- ```ts
372
- const g = globalThis as typeof globalThis & {
373
- __sceneEventPeers?: Set<WsPeer>
374
- }
375
-
376
- /** 在线 peer 注册表(ws 路由 sub 成功时登记,断开/退订移除) */
377
- function peers(): Set<WsPeer> {
378
- return g.__sceneEventPeers ??= new Set()
379
- }
380
- ```
381
- Write: `scene-events.ts:50-52 export function registerScenePeer(peer: WsPeer): void { peers().add(peer) }`.
382
- Full analysis in §5.
383
- 3. **`server/services/workshop/runtime/manager.ts:329` — in the invoke path, unbounded, no eviction.**
384
- ```ts
385
- private readonly lastToolInvokeAt = new Map<string, number>()
386
- ```
387
- Writes: `manager.ts:2757 this.lastToolInvokeAt.set(input.agentId, Date.now())` (every `invokeHostTool` call);
388
- reads: `manager.ts:704 toolActivityOf: (agentId: string) => this.lastToolInvokeAt.get(agentId) ?? null`.
389
- No `delete`/cap → one entry per distinct agentId ever invoked, forever (small, but unbounded and attacker-reachable
390
- via §1.1, e.g. spraying `agentId` values that exist).
391
- 4. **`server/services/workshop/agents/tool-approvals.ts:37-43` — bounded.**
392
- ```ts
393
- private pending = new Map<string, { approval: ToolApproval, resolve: ..., timer: NodeJS.Timeout }>()
394
- ...
395
- private history: ToolApproval[] = []
396
- ```
397
- Eviction exists: timeout deletes (`:75 this.pending.delete(approval.id)`), decide deletes (`:92`),
398
- cancel deletes (`:117`), history capped (`:162 if (this.history.length > HISTORY_CAP) this.history.splice(HISTORY_CAP)`).
399
- 5. `scene-events.ts` per-peer visible-lines is stashed on the peer object (`:35`), no separate collection.
400
- 6. Request-scoped only (not leaks): `harnesses.get.ts:18`, `channels/[id]/plugins/index.put.ts:30`,
401
- `channels.post.ts:51`, `daq/alarms/[id]/ack.post.ts` (no map), `ws.ts:188 peerBudget = new WeakMap(...)` (GC-safe).
402
- `harness-terminal.ts` `sessions` Map has a sweep — `harness-terminal.ts:469-479 sweepTerminalSessions(...)`
403
- (`sessions.delete(pid)`), invoked from `manager.ts:816`.
404
-
405
- ### 3.2 Full-table fetch + JS filtering
406
-
407
- * `server/api/workshop/dcw/index.get.ts:29-36` — five full arrays filtered in JS:
408
- `recipes: visible ? ctrl.listRecipes().filter(r => inLine(r.lineId)) : ctrl.listRecipes()`, likewise `runs`,
409
- `products`, `lines`, `lineStates`.
410
- * `server/api/workshop/dcw/index.get.ts:31-33` — **N+1 in JS**: `ctrl.listHistory(400).filter(h => inLine(nodeLine(h.nodeId))).slice(0, 60)`
411
- where `nodeLine = (nodeId: string): string | undefined => ctrl.byId(nodeId)?.lineId` (`:22`) and
412
- `byId` is a linear scan: `dcw-node.repo.ts:40-42 byId(id: string): DcwNode | undefined { return this.list.find(n => n.id === id) }`
413
- → up to 400 × nodeCount comparisons per request.
414
- * `server/api/workshop/agent-tools/bindings/index.get.ts:13` — `getAgentNodeBindingRepo().all()` returns the whole JSON list (`node-bindings.repo.ts:48-50`).
415
- * `server/api/workshop/dcw/recipes/index.get.ts:11` — `{ recipes: repo.list(), runs: repo.listRuns() }`, no filter/limit.
416
- * `server/api/workshop/channels/[id]/tasks/index.get.ts:23` — `taskEngineOf(manager).list(channelId)` →
417
- `task.repo.ts:67 SELECT ${COLS} FROM tasks WHERE channel_id = ? ORDER BY createdAt ASC, rowid ASC` — **no LIMIT**; every task row of the channel is returned.
418
- * `server/api/workshop/mailbox.get.ts:12-13` — client `limit` (uncapped) then fetch-all-and-slice:
419
- `manager.ts:2834-2839 pollMailbox(...) { this.requireMember(...); return this.deps.repos.messages.listPendingByChannelAgent(channelId, callerAgentId).slice(0, limit).map(rowToMessage) }` — the repo query at that call site passes no limit (`message.repo.ts:91-95` has a `LIMIT ?` variant, unused here).
420
- * `manager.ts:1552 listByAgent(targetAgentId, 10_000)` (delete memory path) and
421
- `manager.ts:1489 listByAgentChannel(channelId, TEAM_AGENT_ID, 1_000_000)` (delete team memory) — huge limits.
422
- * Member lookups fetch the whole roster then search: `channels/[id]/agents/[agentId].patch.ts:20-21`,
423
- `[agentId].delete.ts:19-20`, `[agentId]/stop.post.ts:20-21`, `model.patch.ts:22-23`, `position.patch.ts:21-22`,
424
- `range.patch.ts:21-22` all do `const members = await manager.listChannelAgents(channelId)` + `.some(...)`/`.find(...)`.
425
- * `dcw/line/query.get.ts:26` → `dcw-controller.ts:888 getDaqNodeRepo().all().filter(...)`, then one TSDB round trip.
426
- * `dcw/runs/[id]/data.get.ts:19` → `dcw-controller.ts:979-986`: `getDaqNodeRepo().all().filter(...)` then
427
- `await Promise.all(lineNodes.map(async (node) => ... getTsdb().query(node.id, ...)))` — one TSDB query **per node**
428
- (documented as intentional at `:977`).
429
- * `channels/[id]/agents/[agentId]/model.patch.ts:34` — `for (const a of repo.listAll())` full asset list per request.
430
- * `agents/index.get.ts:12` → `withOwnerNames(templates)` does one user lookup per template, 60 s-cached, never evicted (`caller.ts:105-135`).
431
-
432
- ### 3.3 Limits
433
-
434
- Huge / unbounded as passed from the route:
435
-
436
- * `mailbox.get.ts:12-13` — no upper bound: `const limit = Number.parseInt(url.searchParams.get('limit') ?? '50', 10)` … `limit > 0 ? limit : 50`.
437
- * `channels/[id]/tasks/index.get.ts:23` — no limit parameter at all.
438
- * `dcw/index.get.ts:32` — `listHistory(400)` (then slices to 60).
439
- * `dcw/line/query.get.ts:35`, `dcw/[id]/param-ledger.get.ts` (`limit: 30`/`20` internal), `dcw/[id]/samples`:
440
- `limit: num(q.limit)` passed raw, clamped only downstream at the adapter:
441
- `timescale.adapter.ts:109 const limit = Math.min(opts.limit ?? 500, 5000)` / `:157 Math.min(q.limit ?? 2000, 10_000)`;
442
- `sqlite.adapter.ts:128`, `:182` identical.
443
- * Properly capped: `audit.get.ts:15 Math.min(500, Math.max(1, Number(q.limit) || 100))`,
444
- `dcw/journal/index.get.ts:18 Math.min(limit, 500)`, `dcw/optimizations/index.get.ts:20`, `events.get.ts:18 limit: z.coerce.number().int().min(1).max(1000)`,
445
- `messages/index.get.ts:13 max(500)`, `daq/alarms.get.ts:14 Math.min(500, ...)`, `daq/[id]/frames` clamp at
446
- `daq-controller.ts:849 Math.min(Math.max(opts.limit ?? 100, 1), 1000)`, `manager.listChannelMail` `Math.min(500, ...)` (`manager.ts:2874`).
447
-
448
- ---
449
-
450
- ## 4. ERROR PROPAGATION
451
-
452
- ### 4.1 Swallowed errors that hide failures
453
-
454
- * `server/api/workshop/caller.ts:127-132` — user-name resolution failure is invisible:
455
- ```ts
456
- try {
457
- name = userRepository.findById(userId)?.name ?? null
458
- }
459
- catch {
460
- name = null
461
- }
462
- ```
463
- `withOwnerNames` then renders `ownerName: null` (`caller.ts:113-118`) with no log — a broken `users.sqlite`
464
- looks like "no owner" in every list that uses it (`agents/index.get.ts:12`).
465
- * `server/api/workshop/caller.ts:28-33` — `resolveCallerOrNull` swallows every error including 401:
466
- ```ts
467
- try {
468
- return resolveCaller(event)
469
- }
470
- catch {
471
- return null
472
- }
473
- ```
474
- Consumed at `channels/[id]/agents/index.get.ts:20-23`, where a genuine failure of the user path is silently
475
- downgraded to the agent-token path.
476
- * `server/api/workshop/audit.get.ts:24-29` — corrupt audit detail is silently replaced by `{}`:
477
- ```ts
478
- try {
479
- detail = JSON.parse(String(r.detailJson ?? '{}'))
480
- }
481
- catch {
482
- detail = {}
483
- }
484
- ```
485
- * `server/api/workshop/dcw/[id].delete.ts:18` — `const body = await readBody<{ approvalId?: string }>(event).catch(() => ({})) ?? {}` (deliberate, DELETE-with-empty-body).
486
- * Sanctioned-but-opaque fire-and-forget in the memory write paths: `manager.ts:1478`,
487
- `manager.ts:1515-1521`, `manager.ts:1540` — `void vectorizeMemory(...).catch(() => {})` and
488
- `.then(...).catch(() => {})` (vectorization failures never surface).
489
- * `server/services/workshop/permissions.ts:70` and `:76` — `}).catch(() => {})` on both broadcast paths
490
- (`broadcastSceneEvent('permissions.changed')`, `emitPluginEvent('permissions:changed')`): a failed permission-change
491
- broadcast means clients keep stale grants with no log.
492
- * `server/services/workshop/scene-events.ts:74-79` — send failures delete the peer silently (see §5).
493
- * `server/services/workshop/daq/daq-controller.ts:1189` — `.catch(() => {})` on queue start;
494
- `dcw-controller.ts:836` — `.catch(() => {})` on `markLineOffline`.
495
-
496
- ### 4.2 Internal error messages returned to the client (info leak)
497
-
498
- * `server/services/workshop/runtime/manager.ts:2785-2788` — raw internal `Error.message` is returned to the HTTP
499
- caller as tool output (this is the endpoint of §1.1):
500
- ```ts
501
- catch (err) {
502
- const reason = err instanceof Error ? err.message : String(err)
503
- return { text: `工具「${input.tool}」调用失败: ${reason}`, isError: true }
504
- }
505
- ```
506
- e.g. SQLite constraint text, filesystem paths from `saveJsonFileAtomic`, driver/Modbus errors.
507
- * `server/api/workshop/ws.ts:739` — `message: error instanceof Error ? error.message : 'workshop 未初始化'` is sent
508
- to the client in an `error` control frame.
509
- * Generic 500 path is clean: `server/utils/response.ts:44-46` logs the error and returns
510
- `{ code: 'INTERNAL_ERROR', message: '服务器内部错误' }` — no stack, no message.
511
-
512
- ### 4.3 Status-code mis-mapping (failures reported as 500)
513
-
514
- `server/api/workshop/daq/[id]/samples.get.ts` / `frames.get.ts` / `frames/content.get.ts` call controller methods
515
- that throw a **plain** `Error` carrying a non-standard `status` property:
516
-
517
- ```ts
518
- // server/services/workshop/daq/daq-controller.ts:797
519
- if (!node) throw Object.assign(new Error(`数采节点不存在: ${id}`), { status: 404 })
520
- ```
521
- ```ts
522
- // server/services/workshop/daq/daq-controller.ts:857, :862
523
- if (!node) throw Object.assign(new Error(`数采节点不存在: ${id}`), { status: 404 })
524
- ...
525
- if (!row || row.kind !== 'image') throw Object.assign(new Error(`帧不存在: ${id}@${tsMs}`), { status: 404 })
526
- ```
527
-
528
- `defineApiHandler` only honors `AppError` (`response.ts:30-33`) and `H3Error` (`:34-43`); a plain `Error` falls to
529
- `console.error('[api] unhandled error:', error)` + HTTP 500 (`response.ts:44-46`). So "node not found" surfaces to
530
- the UI as a 500, and the internal process is logged as an unhandled error.
531
-
532
- ---
533
-
534
- ## 5. SCENE EVENTS (`server/services/workshop/scene-events.ts`)
535
-
536
- **Subscriber tracking** — a `globalThis`-backed `Set` of duck-typed peers:
537
-
538
- ```ts
539
- // scene-events.ts:14-18
540
- interface WsPeer {
541
- send(data: string | Uint8Array): void
542
- close(code?: number, reason?: string): void
543
- }
544
- ```
545
- ```ts
546
- // scene-events.ts:20-27
547
- const g = globalThis as typeof globalThis & {
548
- __sceneEventPeers?: Set<WsPeer>
549
- }
550
-
551
- /** 在线 peer 注册表(ws 路由 sub 成功时登记,断开/退订移除) */
552
- function peers(): Set<WsPeer> {
553
- return g.__sceneEventPeers ??= new Set()
554
- }
555
- ```
556
-
557
- **Subscribe path** (only after user auth; a per-peer line-visibility set is stamped on the peer object):
558
-
559
- ```ts
560
- // server/api/workshop/ws.ts:174-177
561
- function attachScenePeer(peer: WsPeer, user: { id: string, role: string }): void {
562
- setPeerVisibleLines(peer, visibleLineIds(user))
563
- registerScenePeer(peer)
564
- }
565
- ```
566
- ```ts
567
- // scene-events.ts:34-36
568
- export function setPeerVisibleLines(peer: WsPeer, visible: Set<string> | null): void {
569
- (peer as WsPeer & { __awVisibleLines?: Set<string> | null }).__awVisibleLines = visible
570
- }
571
- ```
572
- ```ts
573
- // scene-events.ts:50-52
574
- export function registerScenePeer(peer: WsPeer): void {
575
- peers().add(peer)
576
- }
577
- ```
578
- Call sites: `ws.ts:176` only (grep: `registerScenePeer` appears in `scene-events.ts:50` and `ws.ts:176`).
579
-
580
- **Unsubscribe path — exists, on socket close and error:**
581
-
582
- ```ts
583
- // server/api/workshop/ws.ts:753-762
584
- close(peer) {
585
- unsubscribePeer(peer)
586
- unregisterScenePeer(peer)
587
- },
588
-
589
- error(peer, error) {
590
- console.error('[workshop-ws] connection error:', error)
591
- unsubscribePeer(peer)
592
- unregisterScenePeer(peer)
593
- },
594
- ```
595
- ```ts
596
- // scene-events.ts:54-56
597
- export function unregisterScenePeer(peer: WsPeer): void {
598
- peers().delete(peer)
599
- }
600
- ```
601
-
602
- **Max subscriber count: NONE.** There is no cap anywhere — grep for `__sceneEventPeers` yields only `scene-events.ts:21,26`;
603
- `registerScenePeer` (`:50-52`) performs an unconditional `add` with no size check, and `sceneEventPeerCount()`
604
- (`:58-60`) is exported but never called by any handler (grep: only its own declaration).
605
-
606
- **Dead-subscriber removal (two mechanisms, both partial):**
607
-
608
- 1. Close/error hooks above.
609
- 2. Lazy removal when a send throws:
610
- ```ts
611
- // scene-events.ts:72-80
612
- for (const peer of peers()) {
613
- if (lineId !== undefined && !peerSeesLine(peer, lineId)) continue
614
- try {
615
- peer.send(frame)
616
- }
617
- catch {
618
- peers().delete(peer)
619
- }
620
- }
621
- ```
622
- same pattern in `broadcastPeerEvent` (`:92-99`).
623
-
624
- **Can a subscriber leak? Yes — with the caveat that the primary paths are covered.**
625
- * The removal depends entirely on the ws route's `close`/`error` hooks firing (`ws.ts:753-762`). There is **no
626
- heartbeat/liveness timeout and no size cap** in the scene-peer set itself: a peer whose `send()` never throws
627
- (e.g. half-open TCP where the write lands in the kernel buffer) and whose close hook never fires stays registered
628
- for the process lifetime. The slow-consumer guard at `ws.ts:199-206` (`peer.close(1013, 'slow consumer')` +
629
- `stream.peers.delete(peer)`) exists but only bounds *stream* fan-out, and relies on that same close hook to reach
630
- `unregisterScenePeer`.
631
- * The registry lives on `globalThis` (`scene-events.ts:20-22`) while peers are created per module instance, so any
632
- module re-evaluation (dev HMR / nitro re-import) keeps the old peer objects in the same Set until their close hook
633
- fires; nothing prunes stale entries.
634
- * Broadcast cost is unbounded per frame: `broadcastSceneEvent` (`:66-81`) serializes once (`:71`) then loops all
635
- peers and `send`s synchronously — with N pages open, every scene event costs N sends (by design per the comment at
636
- `:62-65`), so a subscriber-count leak degrades CPU linearly with no ceiling.
637
-
638
- ---
639
-
640
- ## Priority summary
641
-
642
- 1. **P0** `agent-tools/invoke.post.ts:18+25` + `manager.ts:2750` — any user token + arbitrary `agentId` ⇒ act as any
643
- agent (PLC writes, recipe writes, model promotion, arbitrary training Python). Unfixed; previously documented at
644
- `docs/audit/audit-agents.md:186-249`.
645
- 2. **P0** `bindings/[id].patch.ts` — any user can flip any binding to `mode:'auto'`, silently removing HITL from
646
- another team's control path.
647
- 3. **P1** `dcw/[id]/read.post.ts`, `dcw/[id].patch.ts`, `dcw/index.post.ts`, `dcw/lines/[id].delete.ts`,
648
- `daq/[id].delete.ts`, `daq/[id]/test.post.ts`, `daq/alarms.get.ts`, `dcw/journal/*`, `dcw/optimizations/*`,
649
- `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`, `dcw/[id]/param-ledger.get.ts` — authenticated
650
- but unscoped access to industrial data/control.
651
- 4. **P1** `bindings/index.post.ts:33-38` — binds any `agentId` without resolving or authorizing it.
652
- 5. **P2** GET handlers that start acquisition/pipelines and insert rows (`daq/index.get.ts:20-22`,
653
- `daq/[id]/samples.get.ts`→`daq-controller.ts:794`, `channels/[id]/index.get.ts:16`).
654
- 6. **P2** `daq/test-driver.post.ts` / `dcw/test-driver.post.ts` — caller-controlled outbound connect primitive.
655
- 7. **P3** `caller.ts:122` uncapped `nameCache`; `manager.ts:329` uncapped `lastToolInvokeAt`; no scene-peer cap.
656
- 8. **P3** `daq` 404s surface as 500 (`daq-controller.ts:797,838,857,862` vs `response.ts:29-47`).
657
- 9. **P3** swaggered error text: `manager.ts:2787` returns raw `err.message` to callers.
1
+ # HTTP API authz / read-path / perf audit — agents + runtime + industrial nodes
2
+
3
+ Read-only audit. Every claim cites `file:line` with verbatim code. No source file was modified.
4
+
5
+ Scope read in full: `server/api/workshop/agent-tools/**`, `agents/**`, `channels/**`, `dcw/**`, `daq/**`,
6
+ `runtime.get.ts`, `tasks.get.ts`, `mailbox.get.ts`, `caller.ts`, `server/services/workshop/scene-events.ts`,
7
+ `server/services/workshop/agents/agent-badge.ts`, plus the guards they delegate to
8
+ (`permissions.ts`, `runtime/manager.ts`, `agents/tool-approvals.ts`, `agents/node-bindings.repo.ts`,
9
+ `agents/host-tool-bridge.ts`, `agents/industrial-tools.ts`, `dcw/dcw-controller.ts`, `daq/daq-controller.ts`,
10
+ `aml/job-orchestrator.ts`, `aml/python-runtime.ts`).
11
+
12
+ ---
13
+
14
+ ## 1. AUTHZ AUDIT
15
+
16
+ ### 0. Global facts
17
+
18
+ * No global auth middleware exists. The only middleware is `server/middleware/request-log.ts:7` — logging only.
19
+ * Unmatched `/api/workshop/**` paths hit `server/api/workshop/[...path].ts:12` → static 404.
20
+ * Auth primitives (`server/api/workshop/caller.ts`):
21
+ * `resolveUser` (`:71-79`) — Bearer **user** token, else 401.
22
+ * `resolveCaller` (`:16-24`) — Bearer **agent instance** token, else 401.
23
+ * `resolveAgentOrUser` (`:45-54`) — either domain.
24
+ * `requireAdmin` (`:82-88`), `requireRole` (`:91-97`).
25
+ * Line-grant model (`server/services/workshop/permissions.ts`): `isPrivilegedRole` (`:26-28`),
26
+ `lineMode` (`:31-36`), `visibleLineIds` (`:39-42`), `filterByLine` (`:45-52`),
27
+ `requireLineMode` (`:55-62`). admin/editor bypass everything.
28
+
29
+ ### 1.1 [P0] `agent-tools/invoke.post.ts` — user token + client-supplied `agentId` = full agent impersonation
30
+
31
+ The whole handler (27 lines):
32
+
33
+ ```ts
34
+ // server/api/workshop/agent-tools/invoke.post.ts:16-27
35
+ export default defineApiHandler(async (event) => {
36
+ const agentToken = getHeader(event, 'x-aw-agent-token')
37
+ if (!agentToken) resolveUser(event) // 桥路径免用户鉴权,由 token 校验兜底
38
+ const body = await readBody<{ agentId?: string, tool?: string, args?: Record<string, unknown> }>(event) ?? {}
39
+ const agentId = String(body.agentId ?? '')
40
+ const tool = String(body.tool ?? '')
41
+ const args = body.args ?? {}
42
+ if (!agentId) throw createError({ statusCode: 400, statusMessage: 'agentId required' })
43
+ if (!tool) throw createError({ statusCode: 400, statusMessage: 'tool required' })
44
+ const result = await getWorkshopManager().invokeHostTool({ agentId, tool, args, token: agentToken || undefined })
45
+ return { result }
46
+ })
47
+ ```
48
+
49
+ Note `invoke.post.ts:18`: `resolveUser(event)`'s **return value is discarded** — the authenticated user is never
50
+ passed downstream. `agentId` comes only from the request body (`:20`).
51
+
52
+ The guard it delegates to:
53
+
54
+ ```ts
55
+ // server/services/workshop/runtime/manager.ts:2746-2752
56
+ async invokeHostTool(input: { agentId: string, token?: string, tool: string, args?: Record<string, unknown> }): Promise<{ text: string, isError?: boolean }> {
57
+ const row = this.deps.repos.channelAgents.findById(input.agentId)
58
+ if (!row || row.enabled !== 1) throw new AppError(404, 'NOT_FOUND', `agent 不存在或已停用: ${input.agentId}`)
59
+ // token 鉴权(MCP 桥路径必带;缺省视为服务端内部调用,走 REST 已有用户鉴权)
60
+ if (input.token !== undefined && input.token !== row.token) {
61
+ throw new AppError(401, 'UNAUTHORIZED', 'agent token 校验失败')
62
+ }
63
+ ```
64
+
65
+ `invoke.post.ts:25` passes `token: agentToken || undefined`. **Consequences, exactly:**
66
+
67
+ | Request | `agentToken` | `input.token` | `manager.ts:2750` | Result |
68
+ |---|---|---|---|---|
69
+ | valid **user** Bearer, **no** `x-aw-agent-token`, `agentId` = any other agent | undefined | `undefined` | `input.token !== undefined` is **false** → check **skipped** | **Executes any tool as that agent** |
70
+ | **no** `Authorization` at all, no `x-aw-agent-token` | undefined | — never reached | — | `resolveUser` at `invoke.post.ts:18` throws `AppError(401,'USER_UNAUTHORIZED')` (`caller.ts:76`) → **blocked** |
71
+ | own agent token in `x-aw-agent-token`, `agentId` = another agent | own token | own token | `!== row.token` → true | 401 — **blocked** |
72
+ | valid agent token, matching `agentId` | token | `=== row.token` | passes | legitimate |
73
+
74
+ So the hole is exactly: **valid user token + arbitrary body `agentId` + absent `x-aw-agent-token`.** No ownership,
75
+ membership or role check exists anywhere on this path. The authenticated `ResolvedUser` never reaches `manager`.
76
+
77
+ After the guard, the impersonated identity drives every downstream authorization:
78
+
79
+ ```ts
80
+ // server/services/workshop/runtime/manager.ts:2769-2775
81
+ const identity = {
82
+ agentId: row.id,
83
+ channelId: row.channelId,
84
+ role: (row.role === 'lead' ? 'lead' : 'worker') as 'lead' | 'worker',
85
+ name: row.name,
86
+ }
87
+ return await pluginTool.handler(input.args ?? {}, identity)
88
+ ```
89
+
90
+ ```ts
91
+ // server/services/workshop/runtime/manager.ts:2777-2783
92
+ const runtime = this.ensureAgentRuntime(row.channelId, input.agentId)
93
+ if (runtime) {
94
+ const viaImpl = await runtime.dispatchHostTool(input.tool, input.args ?? {})
95
+ if (viaImpl) return viaImpl
96
+ }
97
+ // 回退:impl 未实现工具面(如 mock)→ 协作工具族直调
98
+ return await this.invokeAgentWorkspaceTool(input.agentId, input.tool, input.args ?? {})
99
+ ```
100
+
101
+ `invokeHostTool` also applies **no role/tool filtering** — unlike `hostToolsForRole`
102
+ (`host-tool-bridge.ts:70-87`) it never consults `LEAD_ONLY_TOOL_NAMES` (`host-tool-bridge.ts:33-43`).
103
+ Every tool is dispatchable for any named agent that exists and is enabled.
104
+
105
+ **Which tool classes are reachable, by whom**
106
+
107
+ Reachable by *any* authenticated user token of *any* role (including a plain `user` with zero line grants):
108
+ pick any lead/worker agent id.
109
+
110
+ * **Read-only** (dispatch table `host-tool-bridge.ts:162-211` + `:219+`):
111
+ `my_industrial_nodes`, `aml_node_catalog`, `aml_dataset_stats`, `aml_job_status`, `aml_job_logs`,
112
+ `aml_leaderboard`, `aml_model_reference`, `dcw_read`, `daq_query`, `daq_frames`, `dcw_journal`, `ops_log`,
113
+ `recipe_log`, `recipe_versions`, `line_context`, `list_other_teams`, `search_other_teams_memory`,
114
+ mailbox/list-mail/memory tools.
115
+ * **Mutating / control-plane**:
116
+ * `dcw_control` — real PLC write. Its only authz is the *impersonated agent's* binding:
117
+ ```ts
118
+ // server/services/workshop/agents/industrial-tools.ts:99-108
119
+ const repo = getAgentNodeBindingRepo()
120
+ const binding: AgentNodeBinding | undefined = nodeId ? repo.find(agentId, nodeId, 'dcw') : undefined
121
+ if (!binding) {
122
+ ```
123
+ HITL applies only when `binding.mode === 'manual'` (`industrial-tools.ts:128`); with `mode:'auto'`
124
+ the write executes immediately (`industrial-tools.ts:157`).
125
+ * `recipe_update` (`host-tool-bridge.ts:207-208`), `recipe_rollback` (`:209-210`), `dcw_judge` (`:193-194`),
126
+ `dcw_rollback` (`:195-196`), `aml_dataset_build` (`:167-168`), `aml_job_cancel` (`:177-178`),
127
+ `send_cross_channel_message` (`manager.ts:2725-2734`), `dispatch_task`, `create_team_agent`,
128
+ `update_team_agent`, `remove_team_agent`, `complete_task`, `report_progress`.
129
+ * `aml_model_promote` — nominally lead-only; its check is against the **DB role of the supplied agentId**:
130
+ ```ts
131
+ // server/services/workshop/agents/industrial-tools.ts:1290-1294
132
+ // 治理硬守卫:晋升仅限 lead 实例(注入层过滤 + 分发层双重校验,HTTP 直调不可绕过)
133
+ const roleRow = getAmlRuntime().db.prepare('SELECT role FROM channel_agents WHERE id = ? AND enabled = 1').get(agentId) as { role?: string } | undefined
134
+ if (roleRow?.role !== 'lead') {
135
+ return amlErr(`aml_model_promote 为 lead 专属工具:实例 ${agentId}(role=${roleRow?.role ?? '未知'})无权晋升模型。请由团队 lead 发起,晋升需人工 HITL 批准。`)
136
+ }
137
+ ```
138
+ Naming a lead's `agentId` satisfies it (then HITL approval at `industrial-tools.ts:1316`).
139
+ * `aml_job_submit` — **arbitrary Python execution on the server host.** The tool takes up to 500 KB of code:
140
+ ```ts
141
+ // server/services/workshop/agents/industrial-tools.ts:1152-1156
142
+ if (!code.trim()) return amlErr('code 必填:train.py 全文(单文件;契约见工具说明)。')
143
+ if (code.length > 512_000) return amlErr(`code 过大(${Math.round(code.length / 1024)}KB),上限 500KB;精简训练代码(模型定义/训练循环拆薄)后重试。`)
144
+ if (!/\bimport\s+amlkit\b/.test(code)) {
145
+ ```
146
+ It is written to disk and executed:
147
+ ```ts
148
+ // server/services/workshop/aml/job-orchestrator.ts:285-287
149
+ if (typeof inline === 'string' && inline.length > 0 && inline.length <= 512_000) {
150
+ writeFileSync(join(workspace, 'train.py'), inline)
151
+ trainFile = 'train.py'
152
+ ```
153
+ ```ts
154
+ // server/services/workshop/aml/job-orchestrator.ts:328
155
+ const exit1 = await runPython(run, vpy, [join(workspace, trainFile)], workspace)
156
+ ```
157
+ No container/OS sandbox; the only mitigation is a scrubbed env
158
+ (`aml/python-runtime.ts:186-214`, `jobEnv` whitelist, "服务器 secrets … 一律不可见").
159
+ The `import amlkit` requirement is a regex (`industrial-tools.ts:1154`), trivially satisfied.
160
+ * Plugin tools: identity is the impersonated agent (`manager.ts:2769-2775`), no independent check —
161
+ e.g. `diag_run` (`server/plugins-builtin/diag-bridge/index.mjs:449-450`) exports line DAQ snapshots,
162
+ `kb_store`/`kb_index` (`server/plugins-builtin/rag-bridge/index.mjs:199,259`) mutate the knowledge base.
163
+
164
+ **Contrast with the sibling endpoint, which does it right:**
165
+
166
+ ```ts
167
+ // server/api/workshop/agent-tools/list.get.ts:17-22
168
+ if (agentToken) {
169
+ const resolved = getWorkshopManager().resolveAgentByToken(String(agentToken))
170
+ if (!resolved || resolved.agentId !== agentId) {
171
+ throw createError({ statusCode: 401, statusMessage: 'agent token 校验失败' })
172
+ }
173
+ }
174
+ ```
175
+
176
+ **Enumeration is trivial**, so no guessing is needed: `agent-tools/bindings/index.get.ts:13` returns
177
+ `{ bindings: agentId ? getAgentNodeBindingRepo().byAgent(agentId) : getAgentNodeBindingRepo().all() }` — with no
178
+ `agentId` query param, **every** binding of every agent (agentId + nodeId + kind + mode) is returned to any
179
+ authenticated user.
180
+
181
+ ⚠UNVERIFIED: I did not execute a live exploit; the conclusion is from the code paths above (all read directly).
182
+ Corroboration: the same finding is already written up at `docs/audit/audit-agents.md:186-249` ("the manager's
183
+ token check is **skipped entirely** when no token is supplied … Minimal hardening: in `invokeHostTool` change the
184
+ token check to `if (input.token !== row.token)`") — and the code is **unchanged**, i.e. unfixed.
185
+
186
+ ### 1.2 `bindings/index.post.ts` — permission check quoted; **target agent ownership NOT verified**
187
+
188
+ ```ts
189
+ // server/api/workshop/agent-tools/bindings/index.post.ts:16-39
190
+ export default defineApiHandler(async (event) => {
191
+ const user = resolveUser(event)
192
+ const body = await readBody<{ agentId?: string, nodeId?: string, kind?: 'dcw' | 'daq', mode?: 'auto' | 'manual' }>(event) ?? {}
193
+ const kind = body.kind ?? 'dcw'
194
+ const nodeId = String(body.nodeId ?? '')
195
+ // 绑定前置:节点必须存在,且用户对其所属产线有足额权限
196
+ const lineId = kind === 'daq'
197
+ ? getDaqController().byId(nodeId)?.lineId
198
+ : getDcwController().byId(nodeId)?.lineId
199
+ if (!lineId) {
200
+ throw new AppError(404, ErrorCodes.NOT_FOUND, `${kind === 'daq' ? '数采' : '写控'}节点不存在: ${nodeId}`)
201
+ }
202
+ const mode = lineMode(user, lineId)
203
+ const needOperate = kind === 'dcw'
204
+ if (mode === 'none' || (needOperate && mode !== 'operate')) {
205
+ throw new AppError(403, 'LINE_FORBIDDEN', `无该产线权限:绑定${kind === 'daq' ? '数采' : '写控'}节点需对产线「${lineId}」拥有${needOperate ? '可操控' : '仅查看'}及以上权限`)
206
+ }
207
+ const binding = getAgentNodeBindingRepo().bind(
208
+ String(body.agentId ?? ''),
209
+ nodeId,
210
+ kind,
211
+ body.mode ?? 'auto',
212
+ )
213
+ return { binding }
214
+ })
215
+ ```
216
+
217
+ The check at `:28-32` covers **the node's line only**. `body.agentId` is never resolved, never checked for
218
+ existence, never checked for ownership/membership:
219
+
220
+ ```ts
221
+ // server/services/workshop/agents/node-bindings.repo.ts:73-78
222
+ bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode): AgentNodeBinding {
223
+ if (!agentId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'agentId 必填')
224
+ if (!nodeId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'nodeId 必填')
225
+ if (kind !== 'dcw' && kind !== 'daq') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知节点类型: ${kind}`)
226
+ if (mode !== 'auto' && mode !== 'manual') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知控制模式: ${mode}`)
227
+ ```
228
+
229
+ Effect: **any** authenticated user with `operate` on one line can grant that control right to **any** agent id —
230
+ their own, another user's agent, or a lead in an unrelated channel — or re-bind an existing agent with
231
+ `"mode":"auto"` to strip HITL, because `bind()` updates the mode of an existing row
232
+ (`node-bindings.repo.ts:79-83`: `if (prev) { prev.mode = mode; this.flush(); return prev }`).
233
+ The granting user need not own, belong to, or even know anything about that agent.
234
+
235
+ ### 1.3 Handlers that authenticate but never authorize the resource (IDOR)
236
+
237
+ All of these call `resolveUser` and **discard the result** or use it only for logging — no ownership/role/line check:
238
+
239
+ | Handler | Auth | Missing check | Impact |
240
+ |---|---|---|---|
241
+ | `agent-tools/bindings/[id].patch.ts:10-13` | `resolveUser(event)` (`:10`) | owner / role / line | Any user flips **any** binding's mode: `getAgentNodeBindingRepo().setMode(id, body.mode ?? 'auto')` → `"auto"` **disables HITL** for another team's writes (`node-bindings.repo.ts:97-104`) |
242
+ | `agent-tools/bindings/[id].delete.ts:11-17` | `resolveUser(event)` (`:11`) | owner / role / line | Any user unbinds any agent↔node pair (`:17 !repo.unbind(id)`), also cancels that agent's pending approvals (`:19 getToolApprovals().cancelPendingFor(...)`) |
243
+ | `agent-tools/bindings/index.get.ts:10-13` | `resolveUser(event)` (`:10`) | any scope filter | Full cross-tenant binding dump (see 1.1) |
244
+ | `agent-tools/approvals/index.get.ts:11-16` | `resolveUser(event)` (`:11`) | ownership of `agentId` | Any user lists pending approvals of any agent: `getToolApprovals().listPending(agentId)`; history via `scope=history` |
245
+ | `agent-tools/list.get.ts:13-23` | user token path (`:13`) | `agentId` ownership | Tool-schema disclosure for any agent |
246
+ | `dcw/[id]/read.post.ts:13-16` | `resolveUser(event)` (`:13`) | **`requireLineMode` absent** | Any user triggers a real driver read on **any** dcw node id: `await getDcwController().readNow(id)` (`:16`) — cross-line data read |
247
+ | `dcw/[id].patch.ts:12-16` | `resolveUser(event)` (`:12`) | role / line | Any user patches **any** dcw node: name/driver/range/enabled/position — `getDcwController().patch(id, body)` (`:16`). Widening `min/max` weakens the write interlock that `dcw_control` depends on |
248
+ | `dcw/index.post.ts:13-16` | `resolveUser(event)` (`:13`) | role / line | Any user creates a write-control node (the comment at `:17` calls it "获得直写物理设备能力的入口") |
249
+ | `dcw/lines/[id].delete.ts:15-21` | `resolveUser(event)` (`:15`) | role / line | Any user deletes **any** line; `?purge=1` cascades nodes/products/recipes (`:19-21`). The sibling create is admin/editor-gated (`dcw/lines/index.post.ts:14`) |
250
+ | `dcw/lines/[id].patch.ts:11-14` | `resolveUser(event)` (`:11`) | role / line | Any user renames/recolors any line |
251
+ | `dcw/recipes/[id].delete.ts:10-12` | `resolveUser(event)` (`:10`) | role | Any user deletes any recipe |
252
+ | `dcw/recipes/index.post.ts:11-13` | `resolveUser(event)` (`:11`) | role | Any user creates recipes |
253
+ | `dcw/recipes/[id]/index.patch.ts:12` , `[id]/revert.post.ts:12` | `resolveUser` | role | Any user edits/rewrites any recipe version history |
254
+ | `dcw/products/[id].delete.ts:11-14`, `[id].patch.ts:12-16` | `resolveUser` | role | Any user deletes/edits any product (create requires admin/editor, `products/index.post.ts:12`) |
255
+ | `dcw/runs/[id]/close.post.ts:11-14` | `resolveUser(event)` (`:11`) | role | Any user closes any production run window |
256
+ | `dcw/templates/index.post.ts:11-13`, `[key].patch.ts:11-14`, `[key].delete.ts:10-12` | `resolveUser` | role | Any user mutates control templates (driver configs) |
257
+ | `dcw/test-driver.post.ts:12-15` | `resolveUser(event)` (`:12`) | role | Any user makes the server open outbound connections with a caller-supplied `driverConfig`: `getDcwController().testDriver(body.driver ?? 'mock', body.driverConfig ?? {})` |
258
+ | `daq/test-driver.post.ts:17-21` | `resolveUser(event)` (`:17`) | role | Same SSRF-ish connect primitive for DAQ protocols |
259
+ | `daq/[id]/test.post.ts:12-15` | `resolveUser(event)` (`:12`) | **`requireLineMode` absent** | Any user triggers a real connection test on any DAQ node (`:15 testNode(id)`); the dcw twin requires `operate` (`dcw/[id]/test.post.ts:16`) |
260
+ | `daq/[id].delete.ts:13-17` | `resolveUser(event)` (`:13`) | **`requireLineMode` absent** | Any user deletes any DAQ node; the patch twin requires `operate` (`daq/[id].patch.ts:19`) |
261
+ | `daq/infra/reconnect.post.ts:9-15` | `resolveUser(event)` (`:9`) | role | Any user triggers infra bring-up: `await apply(daqInfraConfig())` → `__daqApplyInfra` runs `docker compose -f … up -d …` (`server/services/workshop/daq/infra.ts:85`) |
262
+ | `daq/alarms.get.ts:11-15` | `resolveUser(event)` (`:11`) | line filter | Any user reads **all** alarms of **all** lines (`:15 listAlarms(scope, limit)`); `daq/index.get.ts:27` filters by line, this one does not |
263
+ | `daq/templates/*` (`index.post.ts:12`, `[key].patch.ts:12`, `[key].delete.ts:12`) | `resolveUser` | role | Any user mutates signal templates |
264
+ | `dcw/journal/index.get.ts:11-19` | `resolveUser(event)` (`:11`) | line scope | Any user reads the full parameter ledger for any `lineId`/`nodeId` supplied in the query |
265
+ | `dcw/[id]/param-ledger.get.ts:11-13` | `resolveUser(event)` (`:11`) | **`requireLineMode` absent** | Any user reads any node's setpoints/targets/last-good values |
266
+ | `dcw/optimizations/index.get.ts:11-21`, `[id].get.ts:11-16`, `[id]/series.get.ts:12-17` | `resolveUser` | line scope | Any user reads any line's optimization records + raw DAQ series |
267
+ | `dcw/recipes/index.get.ts:9-11` | `resolveUser(event)` (`:9`) | line scope | Returns `repo.list()`/`listRuns()` with **no** `visibleLineIds` filter (contrast `dcw/index.get.ts:29-30`, `dcw/runs/index.get.ts:12`) |
268
+ | `dcw/recipes/[id]/versions.get.ts:11-13` | `resolveUser` | line scope | Any user reads any recipe's full parameter version history |
269
+ | `server/api/workshop/runtime.get.ts:9-10` | `resolveUser(event)` (`:9`) | role | Any user enumerates wired harness agent ids + active channels |
270
+ | `server/api/workshop/daq/infra.get.ts:9` | `resolveUser` | role | Infra status disclosure (low) |
271
+
272
+ ### 1.4 Handlers that ARE correctly guarded (control set)
273
+
274
+ * `agents/[id].get.ts:16-17` → `manager.requireTemplateReadable`; `agents/[id].patch.ts:28`, `[id].delete.ts:17` → `requireWritable` (`manager.ts:1083-1090`).
275
+ * `channels/[id].delete.ts:14-15`, `index.patch.ts:35-36`, `agents/index.post.ts:32-33`, `agents/[agentId].delete.ts:17-18`, `[agentId].patch.ts:18-19`, `model.patch.ts:20-21`, `position.patch.ts:19-20`, `range.patch.ts:19-20`, `stop.post.ts:18-19` → `getChannelForUser` + `requireWritable` + membership check (`manager.ts:1103-1110`, `:1067-1074`).
276
+ * `channels/[id]/messages/index.post.ts:38-39`, `tasks/index.post.ts:67-68`, `tasks/index.get.ts:22`, `queue.get.ts:17`, `events.get.ts:28`, `terminals.get.ts:19`, `messages/index.get.ts:21`, `channels/[id]/index.get.ts:13` → `getChannelForUser` (owner-or-legacy-public read).
277
+ * Memory planes: `channels/[id]/memories/**` and `channels/[id]/agents/[agentId]/memories/**` → `resolveAgentOrUser` + same-channel or `getChannelForUser`+`requireOwned`, and the manager re-checks role: `manager.ts:1508` (`仅本人或 lead 可策展 Agent 记忆`), `:1463` (`仅 lead 可写团队记忆`), `:1487`, `:1548`.
278
+ ⚠ Note (by design, not a bug): `manager.searchAgentMemories` (`manager.ts:1441-1446`) only calls `requireMember(channelId, callerAgentId)` — **any teammate agent in the channel can search another agent's private memory** by passing that agent's id in the URL with `scope:'private'`.
279
+ * `agents/subscribe.post.ts:17-19` → `resolveCaller` + `manager.subscribe` → `requireMember` + same-channel target check (`manager.ts:2884-2893`).
280
+ * `tasks.get.ts:11-12` / `mailbox.get.ts:10-13` → `resolveCaller`, scope forced to `caller.channelId`/`caller.id`.
281
+ * Role-gated: `dcw/controller.post.ts:15`, `dcw/[id].delete.ts:14`, `dcw/lines/index.post.ts:14`, `dcw/journal/node/[nodeId]/rollback.post.ts:15`, `dcw/optimizations/[id]/judge.post.ts:15`, `[id]/rollback.post.ts:17`, `dcw/products/index.post.ts:12`, `dcw/recipes/[id]/apply.post.ts:15`, `[id]/mark-good.post.ts:13`, `[id]/rollback-good.post.ts:13`, `dcw/runs/[id]/rollback.post.ts:14`, `daq/controller.post.ts:29,49`, `daq/index.post.ts:16` (all `requireRole`/`gateDangerous`).
282
+ * `agent-tools/approvals/[id]/decide.post.ts:12-19` — `resolveUser` **used** (decider recorded + `audit`).
283
+
284
+ ### 1.5 `requireLineMode` / `lineMode` audit for daq/dcw handlers
285
+
286
+ **Called (correct):**
287
+
288
+ | Handler | Line | Quote |
289
+ |---|---|---|
290
+ | `dcw/[id]/write.post.ts` | `:19` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
291
+ | `dcw/[id]/test.post.ts` | `:16` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
292
+ | `dcw/[id]/bind.post.ts` | `:16` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
293
+ | `dcw/[id]/bindings.put.ts` | `:17` | `requireLineMode(user, getDcwController().byId(id)?.lineId, 'operate')` |
294
+ | `dcw/lines/[id]/start.post.ts` | `:20` | `requireLineMode(user, id, 'operate')` |
295
+ | `dcw/lines/[id]/stop.post.ts` | `:20` | `requireLineMode(user, id, 'operate')` |
296
+ | `dcw/runs/[id]/data.get.ts` | `:18` | `requireLineMode(user, run?.lineId, 'readonly')` |
297
+ | `daq/[id].patch.ts` | `:19` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'operate')` |
298
+ | `daq/[id]/bind.post.ts` | `:18`, `daq/[id]/bindings.put.ts:18` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'operate')` |
299
+ | `daq/[id]/samples.get.ts` | `:16`, `daq/[id]/frames.get.ts:16`, `daq/[id]/frames/content.get.ts:17` | `requireLineMode(user, getDaqController().byId(id)?.lineId, 'readonly')` |
300
+ | `daq/alarms/[id]/ack.post.ts` | `:17` | `requireLineMode(user, alarmNodeId ? getDaqController().byId(alarmNodeId)?.lineId : undefined, 'operate')` |
301
+ | `dcw/index.get.ts` | `:18-36` | `visibleLineIds` + `filterByLine` (+ per-line `.filter`) |
302
+ | `dcw/lines/index.get.ts` | `:15-18`, `dcw/line/query.get.ts:18-21`, `dcw/runs/index.get.ts:12`, `daq/index.get.ts:27` | `visibleLineIds`/`filterByLine`; `dcw/line/query.get.ts:19-21` throws `403 LINE_FORBIDDEN` when `lineId` is outside the visible set |
303
+ | `agent-tools/bindings/index.post.ts` | `:28-32` | `lineMode(user, lineId)` (node line only — see 1.2) |
304
+
305
+ **NOT called, where a line-scoped resource is addressed** (all cited in §1.3 with their guards):
306
+ `dcw/[id]/read.post.ts` (no line check on a real driver read — worst of these),
307
+ `dcw/[id].patch.ts`, `dcw/[id]/param-ledger.get.ts`, `dcw/journal/index.get.ts`,
308
+ `dcw/optimizations/index.get.ts`, `dcw/optimizations/[id].get.ts`, `dcw/optimizations/[id]/series.get.ts`,
309
+ `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`, `dcw/recipes/[id].delete.ts`,
310
+ `dcw/recipes/[id]/index.patch.ts`, `dcw/recipes/[id]/revert.post.ts`, `dcw/products/[id].patch.ts`,
311
+ `dcw/products/[id].delete.ts`, `dcw/runs/[id]/close.post.ts`, `dcw/lines/[id].patch.ts`,
312
+ `dcw/lines/[id].delete.ts`, `dcw/index.post.ts`, `dcw/templates/*`,
313
+ `daq/[id].delete.ts`, `daq/[id]/test.post.ts`, `daq/alarms.get.ts`, `daq/templates/*`,
314
+ `daq/test-driver.post.ts`, `dcw/test-driver.post.ts`.
315
+
316
+ ---
317
+
318
+ ## 2. READ-PATH WRITES (`*.get.ts` that mutate)
319
+
320
+ | GET handler | Write / side effect | Quote |
321
+ |---|---|---|
322
+ | `server/api/workshop/daq/index.get.ts:22` | **DB insert + runtime creation + 250 ms timer**: `provisionLegacyTwins()` → `this.repo.insert(node)` | `ctrl.provisionLegacyTwins()` (`index.get.ts:22`); `daq-controller.ts:1142-1159`: `provisionLegacyTwins(): void {` … `this.repo.insert(node)` (`:1157`) … `this.syncRuntimes()` (`:1159`); `ensureLoop()` at `:1143` starts `this.timer = setInterval(() => this.sweep(), 250)` (`:191`) |
323
+ | `server/api/workshop/daq/index.get.ts:20` | Pipeline power-on: queue consumer + TSDB init | `await Promise.all([tsdbReady, getDaqQueue()])` (`:20`); comment `:18` `// ws.ts 出口装配 + 管线上电(幂等;路由模块加载即绑定)` |
324
+ | `server/api/workshop/daq/[id]/samples.get.ts:23` (via `:16` guard) | **Starts acquisition**: `samples()` → `ensureLoop()` | route `:23 const points = await getDaqController().samples(id, {...})`; `daq-controller.ts:793-795`: `async samples(id, opts) {` / `this.ensureLoop()` / `await tsdbReady` |
325
+ | `server/api/workshop/daq/[id]/frames.get.ts:20` | same | route `:20 const frames = await getDaqController().frames(id, {...})`; `daq-controller.ts:835 this.ensureLoop()` |
326
+ | `server/api/workshop/daq/[id]/frames/content.get.ts:23` | same | route `:23 const { data, mime } = await getDaqController().frameContent(...)`; `daq-controller.ts:854 this.ensureLoop()` |
327
+ | `server/api/workshop/channels/[id]/index.get.ts:16` | **Assembles lead runtime + starts SchedulerLoop (timer + loop resubmit callback)** | `ensureLeadSchedulerLoop(manager, channelId)` (`:16`), comment `:15` `// 兜底:详情请求时确保 lead 的调度循环已装配(如启动恢复遗漏)`; → `plugins/workshop.ts:73 manager.ensureChannelActive(channelId, options)` → `manager.ts:697-719` `const cr = this.ensureChannelRuntime(channelId)` … `cr.scheduler = loop` / `loop.start()` ⚠(whether `wireMember` immediately spawns a harness subprocess was not traced) |
328
+ | `server/api/workshop/dcw/index.get.ts:13`, `dcw/lines/index.get.ts:12`, `dcw/line/query.get.ts:15`, `dcw/runs/[id]/data.get.ts:14` | Global binding mutation: repoints the controller's broadcast sink each request | `bindDcwBroadcast(broadcastSceneEvent)` → `dcw-controller.ts` `setBroadcast(fn)`; `daq/index.get.ts:19`, `dcw/[id]/read.post.ts:14` etc. use `bindDaqHost(broadcastSceneEvent)` |
329
+ | `server/api/workshop/dcw/index.get.ts:32` | Over-fetch then JS trim (not a write, but a read amplification) | `ctrl.listHistory(400).filter(h => inLine(nodeLine(h.nodeId))).slice(0, 60)` |
330
+
331
+ **Purely read-only GETs (verified line by line):** `agent-tools/list.get.ts`, `agent-tools/approvals/index.get.ts`,
332
+ `agent-tools/bindings/index.get.ts`, `agents/index.get.ts`, `agents/[id].get.ts`,
333
+ `channels/[id]/events.get.ts`, `channels/[id]/queue.get.ts`, `channels/[id]/tasks/index.get.ts`,
334
+ `channels/[id]/terminals.get.ts` (`harness-terminal.ts:451-466` pure map over a Map),
335
+ `channels/[id]/messages/index.get.ts`, `channels/[id]/agents/index.get.ts`,
336
+ `channels/[id]/memories/index.get.ts`, `channels/[id]/agents/[agentId]/memories/index.get.ts`,
337
+ `channels/[id]/plugins/index.get.ts`, `dcw/index.get.ts` (only the binding call above),
338
+ `dcw/lines/index.get.ts`, `dcw/line/query.get.ts`, `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`,
339
+ `dcw/runs/index.get.ts`, `dcw/runs/[id]/data.get.ts` (`dcw-controller.ts:964-999` queries only),
340
+ `dcw/journal/index.get.ts` (`recipe-rollback-manager.ts:652-654`), `dcw/[id]/param-ledger.get.ts` (`:627-649`),
341
+ `dcw/optimizations/index.get.ts` (`:656-658`), `dcw/optimizations/[id].get.ts`,
342
+ `dcw/optimizations/[id]/series.get.ts` (`:602-623` read-only), `daq/alarms.get.ts` (`daq-controller.ts:600-604`),
343
+ `daq/infra.get.ts`, `runtime.get.ts` (`manager.ts:803-808`), `tasks.get.ts`, `mailbox.get.ts`
344
+ (`manager.ts:2834-2840`; the query has no LIMIT — see §3).
345
+
346
+ Note the memory list GET `channels/[id]/agents/[agentId]/memories/index.get.ts:28` calls `manager.listMemories`
347
+ which is a pure read (`manager.ts:1421-1426`).
348
+
349
+ ---
350
+
351
+ ## 3. UNBOUNDED STATE + PERF
352
+
353
+ ### 3.1 Module-level maps/sets/arrays in scope
354
+
355
+ 1. **`server/api/workshop/caller.ts:122` — unbounded, no eviction.**
356
+ ```ts
357
+ const nameCache = new Map<string, { name: string | null, at: number }>()
358
+ ```
359
+ Writes (all writes in the file):
360
+ ```ts
361
+ // caller.ts:124-134
362
+ const hit = nameCache.get(userId)
363
+ if (hit && Date.now() - hit.at < 60_000) return hit.name
364
+ ...
365
+ nameCache.set(userId, { name, at: Date.now() })
366
+ ```
367
+ The 60 s TTL is consulted only when the **same** key is read again; there is **no eviction found** (no sweep,
368
+ no size cap, no `delete`). Every distinct `ownerUserId` ever rendered by `withOwnerNames` stays for the process
369
+ lifetime. `withOwnerNames` (`caller.ts:105-119`) creates a per-call `Map` (`:106`) which is request-scoped (fine).
370
+ 2. **`server/services/workshop/scene-events.ts:20-27` — unbounded, no cap.**
371
+ ```ts
372
+ const g = globalThis as typeof globalThis & {
373
+ __sceneEventPeers?: Set<WsPeer>
374
+ }
375
+
376
+ /** 在线 peer 注册表(ws 路由 sub 成功时登记,断开/退订移除) */
377
+ function peers(): Set<WsPeer> {
378
+ return g.__sceneEventPeers ??= new Set()
379
+ }
380
+ ```
381
+ Write: `scene-events.ts:50-52 export function registerScenePeer(peer: WsPeer): void { peers().add(peer) }`.
382
+ Full analysis in §5.
383
+ 3. **`server/services/workshop/runtime/manager.ts:329` — in the invoke path, unbounded, no eviction.**
384
+ ```ts
385
+ private readonly lastToolInvokeAt = new Map<string, number>()
386
+ ```
387
+ Writes: `manager.ts:2757 this.lastToolInvokeAt.set(input.agentId, Date.now())` (every `invokeHostTool` call);
388
+ reads: `manager.ts:704 toolActivityOf: (agentId: string) => this.lastToolInvokeAt.get(agentId) ?? null`.
389
+ No `delete`/cap → one entry per distinct agentId ever invoked, forever (small, but unbounded and attacker-reachable
390
+ via §1.1, e.g. spraying `agentId` values that exist).
391
+ 4. **`server/services/workshop/agents/tool-approvals.ts:37-43` — bounded.**
392
+ ```ts
393
+ private pending = new Map<string, { approval: ToolApproval, resolve: ..., timer: NodeJS.Timeout }>()
394
+ ...
395
+ private history: ToolApproval[] = []
396
+ ```
397
+ Eviction exists: timeout deletes (`:75 this.pending.delete(approval.id)`), decide deletes (`:92`),
398
+ cancel deletes (`:117`), history capped (`:162 if (this.history.length > HISTORY_CAP) this.history.splice(HISTORY_CAP)`).
399
+ 5. `scene-events.ts` per-peer visible-lines is stashed on the peer object (`:35`), no separate collection.
400
+ 6. Request-scoped only (not leaks): `harnesses.get.ts:18`, `channels/[id]/plugins/index.put.ts:30`,
401
+ `channels.post.ts:51`, `daq/alarms/[id]/ack.post.ts` (no map), `ws.ts:188 peerBudget = new WeakMap(...)` (GC-safe).
402
+ `harness-terminal.ts` `sessions` Map has a sweep — `harness-terminal.ts:469-479 sweepTerminalSessions(...)`
403
+ (`sessions.delete(pid)`), invoked from `manager.ts:816`.
404
+
405
+ ### 3.2 Full-table fetch + JS filtering
406
+
407
+ * `server/api/workshop/dcw/index.get.ts:29-36` — five full arrays filtered in JS:
408
+ `recipes: visible ? ctrl.listRecipes().filter(r => inLine(r.lineId)) : ctrl.listRecipes()`, likewise `runs`,
409
+ `products`, `lines`, `lineStates`.
410
+ * `server/api/workshop/dcw/index.get.ts:31-33` — **N+1 in JS**: `ctrl.listHistory(400).filter(h => inLine(nodeLine(h.nodeId))).slice(0, 60)`
411
+ where `nodeLine = (nodeId: string): string | undefined => ctrl.byId(nodeId)?.lineId` (`:22`) and
412
+ `byId` is a linear scan: `dcw-node.repo.ts:40-42 byId(id: string): DcwNode | undefined { return this.list.find(n => n.id === id) }`
413
+ → up to 400 × nodeCount comparisons per request.
414
+ * `server/api/workshop/agent-tools/bindings/index.get.ts:13` — `getAgentNodeBindingRepo().all()` returns the whole JSON list (`node-bindings.repo.ts:48-50`).
415
+ * `server/api/workshop/dcw/recipes/index.get.ts:11` — `{ recipes: repo.list(), runs: repo.listRuns() }`, no filter/limit.
416
+ * `server/api/workshop/channels/[id]/tasks/index.get.ts:23` — `taskEngineOf(manager).list(channelId)` →
417
+ `task.repo.ts:67 SELECT ${COLS} FROM tasks WHERE channel_id = ? ORDER BY createdAt ASC, rowid ASC` — **no LIMIT**; every task row of the channel is returned.
418
+ * `server/api/workshop/mailbox.get.ts:12-13` — client `limit` (uncapped) then fetch-all-and-slice:
419
+ `manager.ts:2834-2839 pollMailbox(...) { this.requireMember(...); return this.deps.repos.messages.listPendingByChannelAgent(channelId, callerAgentId).slice(0, limit).map(rowToMessage) }` — the repo query at that call site passes no limit (`message.repo.ts:91-95` has a `LIMIT ?` variant, unused here).
420
+ * `manager.ts:1552 listByAgent(targetAgentId, 10_000)` (delete memory path) and
421
+ `manager.ts:1489 listByAgentChannel(channelId, TEAM_AGENT_ID, 1_000_000)` (delete team memory) — huge limits.
422
+ * Member lookups fetch the whole roster then search: `channels/[id]/agents/[agentId].patch.ts:20-21`,
423
+ `[agentId].delete.ts:19-20`, `[agentId]/stop.post.ts:20-21`, `model.patch.ts:22-23`, `position.patch.ts:21-22`,
424
+ `range.patch.ts:21-22` all do `const members = await manager.listChannelAgents(channelId)` + `.some(...)`/`.find(...)`.
425
+ * `dcw/line/query.get.ts:26` → `dcw-controller.ts:888 getDaqNodeRepo().all().filter(...)`, then one TSDB round trip.
426
+ * `dcw/runs/[id]/data.get.ts:19` → `dcw-controller.ts:979-986`: `getDaqNodeRepo().all().filter(...)` then
427
+ `await Promise.all(lineNodes.map(async (node) => ... getTsdb().query(node.id, ...)))` — one TSDB query **per node**
428
+ (documented as intentional at `:977`).
429
+ * `channels/[id]/agents/[agentId]/model.patch.ts:34` — `for (const a of repo.listAll())` full asset list per request.
430
+ * `agents/index.get.ts:12` → `withOwnerNames(templates)` does one user lookup per template, 60 s-cached, never evicted (`caller.ts:105-135`).
431
+
432
+ ### 3.3 Limits
433
+
434
+ Huge / unbounded as passed from the route:
435
+
436
+ * `mailbox.get.ts:12-13` — no upper bound: `const limit = Number.parseInt(url.searchParams.get('limit') ?? '50', 10)` … `limit > 0 ? limit : 50`.
437
+ * `channels/[id]/tasks/index.get.ts:23` — no limit parameter at all.
438
+ * `dcw/index.get.ts:32` — `listHistory(400)` (then slices to 60).
439
+ * `dcw/line/query.get.ts:35`, `dcw/[id]/param-ledger.get.ts` (`limit: 30`/`20` internal), `dcw/[id]/samples`:
440
+ `limit: num(q.limit)` passed raw, clamped only downstream at the adapter:
441
+ `timescale.adapter.ts:109 const limit = Math.min(opts.limit ?? 500, 5000)` / `:157 Math.min(q.limit ?? 2000, 10_000)`;
442
+ `sqlite.adapter.ts:128`, `:182` identical.
443
+ * Properly capped: `audit.get.ts:15 Math.min(500, Math.max(1, Number(q.limit) || 100))`,
444
+ `dcw/journal/index.get.ts:18 Math.min(limit, 500)`, `dcw/optimizations/index.get.ts:20`, `events.get.ts:18 limit: z.coerce.number().int().min(1).max(1000)`,
445
+ `messages/index.get.ts:13 max(500)`, `daq/alarms.get.ts:14 Math.min(500, ...)`, `daq/[id]/frames` clamp at
446
+ `daq-controller.ts:849 Math.min(Math.max(opts.limit ?? 100, 1), 1000)`, `manager.listChannelMail` `Math.min(500, ...)` (`manager.ts:2874`).
447
+
448
+ ---
449
+
450
+ ## 4. ERROR PROPAGATION
451
+
452
+ ### 4.1 Swallowed errors that hide failures
453
+
454
+ * `server/api/workshop/caller.ts:127-132` — user-name resolution failure is invisible:
455
+ ```ts
456
+ try {
457
+ name = userRepository.findById(userId)?.name ?? null
458
+ }
459
+ catch {
460
+ name = null
461
+ }
462
+ ```
463
+ `withOwnerNames` then renders `ownerName: null` (`caller.ts:113-118`) with no log — a broken `users.sqlite`
464
+ looks like "no owner" in every list that uses it (`agents/index.get.ts:12`).
465
+ * `server/api/workshop/caller.ts:28-33` — `resolveCallerOrNull` swallows every error including 401:
466
+ ```ts
467
+ try {
468
+ return resolveCaller(event)
469
+ }
470
+ catch {
471
+ return null
472
+ }
473
+ ```
474
+ Consumed at `channels/[id]/agents/index.get.ts:20-23`, where a genuine failure of the user path is silently
475
+ downgraded to the agent-token path.
476
+ * `server/api/workshop/audit.get.ts:24-29` — corrupt audit detail is silently replaced by `{}`:
477
+ ```ts
478
+ try {
479
+ detail = JSON.parse(String(r.detailJson ?? '{}'))
480
+ }
481
+ catch {
482
+ detail = {}
483
+ }
484
+ ```
485
+ * `server/api/workshop/dcw/[id].delete.ts:18` — `const body = await readBody<{ approvalId?: string }>(event).catch(() => ({})) ?? {}` (deliberate, DELETE-with-empty-body).
486
+ * Sanctioned-but-opaque fire-and-forget in the memory write paths: `manager.ts:1478`,
487
+ `manager.ts:1515-1521`, `manager.ts:1540` — `void vectorizeMemory(...).catch(() => {})` and
488
+ `.then(...).catch(() => {})` (vectorization failures never surface).
489
+ * `server/services/workshop/permissions.ts:70` and `:76` — `}).catch(() => {})` on both broadcast paths
490
+ (`broadcastSceneEvent('permissions.changed')`, `emitPluginEvent('permissions:changed')`): a failed permission-change
491
+ broadcast means clients keep stale grants with no log.
492
+ * `server/services/workshop/scene-events.ts:74-79` — send failures delete the peer silently (see §5).
493
+ * `server/services/workshop/daq/daq-controller.ts:1189` — `.catch(() => {})` on queue start;
494
+ `dcw-controller.ts:836` — `.catch(() => {})` on `markLineOffline`.
495
+
496
+ ### 4.2 Internal error messages returned to the client (info leak)
497
+
498
+ * `server/services/workshop/runtime/manager.ts:2785-2788` — raw internal `Error.message` is returned to the HTTP
499
+ caller as tool output (this is the endpoint of §1.1):
500
+ ```ts
501
+ catch (err) {
502
+ const reason = err instanceof Error ? err.message : String(err)
503
+ return { text: `工具「${input.tool}」调用失败: ${reason}`, isError: true }
504
+ }
505
+ ```
506
+ e.g. SQLite constraint text, filesystem paths from `saveJsonFileAtomic`, driver/Modbus errors.
507
+ * `server/api/workshop/ws.ts:739` — `message: error instanceof Error ? error.message : 'workshop 未初始化'` is sent
508
+ to the client in an `error` control frame.
509
+ * Generic 500 path is clean: `server/utils/response.ts:44-46` logs the error and returns
510
+ `{ code: 'INTERNAL_ERROR', message: '服务器内部错误' }` — no stack, no message.
511
+
512
+ ### 4.3 Status-code mis-mapping (failures reported as 500)
513
+
514
+ `server/api/workshop/daq/[id]/samples.get.ts` / `frames.get.ts` / `frames/content.get.ts` call controller methods
515
+ that throw a **plain** `Error` carrying a non-standard `status` property:
516
+
517
+ ```ts
518
+ // server/services/workshop/daq/daq-controller.ts:797
519
+ if (!node) throw Object.assign(new Error(`数采节点不存在: ${id}`), { status: 404 })
520
+ ```
521
+ ```ts
522
+ // server/services/workshop/daq/daq-controller.ts:857, :862
523
+ if (!node) throw Object.assign(new Error(`数采节点不存在: ${id}`), { status: 404 })
524
+ ...
525
+ if (!row || row.kind !== 'image') throw Object.assign(new Error(`帧不存在: ${id}@${tsMs}`), { status: 404 })
526
+ ```
527
+
528
+ `defineApiHandler` only honors `AppError` (`response.ts:30-33`) and `H3Error` (`:34-43`); a plain `Error` falls to
529
+ `console.error('[api] unhandled error:', error)` + HTTP 500 (`response.ts:44-46`). So "node not found" surfaces to
530
+ the UI as a 500, and the internal process is logged as an unhandled error.
531
+
532
+ ---
533
+
534
+ ## 5. SCENE EVENTS (`server/services/workshop/scene-events.ts`)
535
+
536
+ **Subscriber tracking** — a `globalThis`-backed `Set` of duck-typed peers:
537
+
538
+ ```ts
539
+ // scene-events.ts:14-18
540
+ interface WsPeer {
541
+ send(data: string | Uint8Array): void
542
+ close(code?: number, reason?: string): void
543
+ }
544
+ ```
545
+ ```ts
546
+ // scene-events.ts:20-27
547
+ const g = globalThis as typeof globalThis & {
548
+ __sceneEventPeers?: Set<WsPeer>
549
+ }
550
+
551
+ /** 在线 peer 注册表(ws 路由 sub 成功时登记,断开/退订移除) */
552
+ function peers(): Set<WsPeer> {
553
+ return g.__sceneEventPeers ??= new Set()
554
+ }
555
+ ```
556
+
557
+ **Subscribe path** (only after user auth; a per-peer line-visibility set is stamped on the peer object):
558
+
559
+ ```ts
560
+ // server/api/workshop/ws.ts:174-177
561
+ function attachScenePeer(peer: WsPeer, user: { id: string, role: string }): void {
562
+ setPeerVisibleLines(peer, visibleLineIds(user))
563
+ registerScenePeer(peer)
564
+ }
565
+ ```
566
+ ```ts
567
+ // scene-events.ts:34-36
568
+ export function setPeerVisibleLines(peer: WsPeer, visible: Set<string> | null): void {
569
+ (peer as WsPeer & { __awVisibleLines?: Set<string> | null }).__awVisibleLines = visible
570
+ }
571
+ ```
572
+ ```ts
573
+ // scene-events.ts:50-52
574
+ export function registerScenePeer(peer: WsPeer): void {
575
+ peers().add(peer)
576
+ }
577
+ ```
578
+ Call sites: `ws.ts:176` only (grep: `registerScenePeer` appears in `scene-events.ts:50` and `ws.ts:176`).
579
+
580
+ **Unsubscribe path — exists, on socket close and error:**
581
+
582
+ ```ts
583
+ // server/api/workshop/ws.ts:753-762
584
+ close(peer) {
585
+ unsubscribePeer(peer)
586
+ unregisterScenePeer(peer)
587
+ },
588
+
589
+ error(peer, error) {
590
+ console.error('[workshop-ws] connection error:', error)
591
+ unsubscribePeer(peer)
592
+ unregisterScenePeer(peer)
593
+ },
594
+ ```
595
+ ```ts
596
+ // scene-events.ts:54-56
597
+ export function unregisterScenePeer(peer: WsPeer): void {
598
+ peers().delete(peer)
599
+ }
600
+ ```
601
+
602
+ **Max subscriber count: NONE.** There is no cap anywhere — grep for `__sceneEventPeers` yields only `scene-events.ts:21,26`;
603
+ `registerScenePeer` (`:50-52`) performs an unconditional `add` with no size check, and `sceneEventPeerCount()`
604
+ (`:58-60`) is exported but never called by any handler (grep: only its own declaration).
605
+
606
+ **Dead-subscriber removal (two mechanisms, both partial):**
607
+
608
+ 1. Close/error hooks above.
609
+ 2. Lazy removal when a send throws:
610
+ ```ts
611
+ // scene-events.ts:72-80
612
+ for (const peer of peers()) {
613
+ if (lineId !== undefined && !peerSeesLine(peer, lineId)) continue
614
+ try {
615
+ peer.send(frame)
616
+ }
617
+ catch {
618
+ peers().delete(peer)
619
+ }
620
+ }
621
+ ```
622
+ same pattern in `broadcastPeerEvent` (`:92-99`).
623
+
624
+ **Can a subscriber leak? Yes — with the caveat that the primary paths are covered.**
625
+ * The removal depends entirely on the ws route's `close`/`error` hooks firing (`ws.ts:753-762`). There is **no
626
+ heartbeat/liveness timeout and no size cap** in the scene-peer set itself: a peer whose `send()` never throws
627
+ (e.g. half-open TCP where the write lands in the kernel buffer) and whose close hook never fires stays registered
628
+ for the process lifetime. The slow-consumer guard at `ws.ts:199-206` (`peer.close(1013, 'slow consumer')` +
629
+ `stream.peers.delete(peer)`) exists but only bounds *stream* fan-out, and relies on that same close hook to reach
630
+ `unregisterScenePeer`.
631
+ * The registry lives on `globalThis` (`scene-events.ts:20-22`) while peers are created per module instance, so any
632
+ module re-evaluation (dev HMR / nitro re-import) keeps the old peer objects in the same Set until their close hook
633
+ fires; nothing prunes stale entries.
634
+ * Broadcast cost is unbounded per frame: `broadcastSceneEvent` (`:66-81`) serializes once (`:71`) then loops all
635
+ peers and `send`s synchronously — with N pages open, every scene event costs N sends (by design per the comment at
636
+ `:62-65`), so a subscriber-count leak degrades CPU linearly with no ceiling.
637
+
638
+ ---
639
+
640
+ ## Priority summary
641
+
642
+ 1. **P0** `agent-tools/invoke.post.ts:18+25` + `manager.ts:2750` — any user token + arbitrary `agentId` ⇒ act as any
643
+ agent (PLC writes, recipe writes, model promotion, arbitrary training Python). Unfixed; previously documented at
644
+ `docs/audit/audit-agents.md:186-249`.
645
+ 2. **P0** `bindings/[id].patch.ts` — any user can flip any binding to `mode:'auto'`, silently removing HITL from
646
+ another team's control path.
647
+ 3. **P1** `dcw/[id]/read.post.ts`, `dcw/[id].patch.ts`, `dcw/index.post.ts`, `dcw/lines/[id].delete.ts`,
648
+ `daq/[id].delete.ts`, `daq/[id]/test.post.ts`, `daq/alarms.get.ts`, `dcw/journal/*`, `dcw/optimizations/*`,
649
+ `dcw/recipes/index.get.ts`, `dcw/recipes/[id]/versions.get.ts`, `dcw/[id]/param-ledger.get.ts` — authenticated
650
+ but unscoped access to industrial data/control.
651
+ 4. **P1** `bindings/index.post.ts:33-38` — binds any `agentId` without resolving or authorizing it.
652
+ 5. **P2** GET handlers that start acquisition/pipelines and insert rows (`daq/index.get.ts:20-22`,
653
+ `daq/[id]/samples.get.ts`→`daq-controller.ts:794`, `channels/[id]/index.get.ts:16`).
654
+ 6. **P2** `daq/test-driver.post.ts` / `dcw/test-driver.post.ts` — caller-controlled outbound connect primitive.
655
+ 7. **P3** `caller.ts:122` uncapped `nameCache`; `manager.ts:329` uncapped `lastToolInvokeAt`; no scene-peer cap.
656
+ 8. **P3** `daq` 404s surface as 500 (`daq-controller.ts:797,838,857,862` vs `response.ts:29-47`).
657
+ 9. **P3** swaggered error text: `manager.ts:2787` returns raw `err.message` to callers.