agentworkshop 0.8.1 → 0.8.3

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 (1563) 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/{DuUc4bbY2.js → B9qIhT7k2.js} +1 -1
  8. package/.output/public/_nuxt/{BkEokGX5.js → BE9oKpOt.js} +1 -1
  9. package/.output/public/_nuxt/{D_59BNP1.js → Bbk1XCCM.js} +3 -3
  10. package/.output/public/_nuxt/{Dz9C2pTa.js → CMzExk8F.js} +1 -1
  11. package/.output/public/_nuxt/{dHwWyr6b.js → CT4bi_Y4.js} +1 -1
  12. package/.output/public/_nuxt/{26OL4Ao82.js → CeCSjB9O2.js} +1 -1
  13. package/.output/public/_nuxt/{Dyxf2xZw.js → Cot5VNae.js} +1 -1
  14. package/.output/public/_nuxt/{BVg2R2VB2.js → Crf8_Ad02.js} +1 -1
  15. package/.output/public/_nuxt/{rDvMijKA.js → D9tNM-1a.js} +2 -2
  16. package/.output/public/_nuxt/{YAA98rWJ.js → DAug2CPf.js} +7 -7
  17. package/.output/public/_nuxt/{CQSxS_Ek.js → DbhTN7-T.js} +1 -1
  18. package/.output/public/_nuxt/DgGzwjAr2.js +2 -0
  19. package/.output/public/_nuxt/DkRozlDP2.js +1 -0
  20. package/.output/public/_nuxt/{DGu_fna7.js → DoChWkff.js} +1 -1
  21. package/.output/public/_nuxt/{Byiiiwc72.js → DxH5focQ2.js} +1 -1
  22. package/.output/public/_nuxt/Dyr3LPGL.js +1 -0
  23. package/.output/public/_nuxt/{CC2Pv8VL2.js → MC_i34H42.js} +1 -1
  24. package/.output/public/_nuxt/OmpTerminalPanel.DMWgGwDs.css +1 -0
  25. package/.output/public/_nuxt/PluginSlot.BqBzLD4T.css +1 -0
  26. package/.output/public/_nuxt/TownView.Cn8SPG7S.css +1 -0
  27. package/.output/public/_nuxt/{CmuGMxDP.js → TugRY_4O.js} +1 -1
  28. package/.output/public/_nuxt/{BPUQZ9Lq2.js → WybiLTow2.js} +1 -1
  29. package/.output/public/_nuxt/{BaYDgyaR.js → Zn0BZpf0.js} +3 -3
  30. package/.output/public/_nuxt/{_id_.BQRWK7J2.css → _id_.Be5JaH-P.css} +1 -1
  31. package/.output/public/_nuxt/{_wsId_.DCnKQQdY.css → _wsId_.p_vAYtTp.css} +1 -1
  32. package/.output/public/_nuxt/{agents.D-JPovTZ.css → agents.CRomddYR.css} +1 -1
  33. package/.output/public/_nuxt/aml.DgOMpDpv.css +1 -0
  34. package/.output/public/_nuxt/builds/latest.json +1 -1
  35. package/.output/public/_nuxt/builds/meta/fd0033e4-1eaa-42f8-9a04-3132717a703b.json +1 -0
  36. package/.output/public/_nuxt/{default.BEXGWZFQ.css → default.CpAx70gC.css} +1 -1
  37. package/.output/public/_nuxt/{logs.BkJPbR_K.css → logs.DcSvz6vi.css} +1 -1
  38. package/.output/public/_nuxt/{monitor.D3yEqqrv.css → monitor.OoNTwfMJ.css} +1 -1
  39. package/.output/public/_nuxt/{ontology.B_3Wn907.css → ontology.JqJ6PjV1.css} +1 -1
  40. package/.output/public/_nuxt/{operations.-l6u44Ar.css → operations.C48ggFa5.css} +1 -1
  41. package/.output/public/_nuxt/{pages.Cdpm_B-G.css → pages.Dpa28tJW.css} +1 -1
  42. package/.output/public/_nuxt/permissions.CrV-4t-6.css +1 -0
  43. package/.output/public/_nuxt/{BfeXib9G.js → rcdmiszh2.js} +1 -1
  44. package/.output/public/_nuxt/schedules.DYWOjGHm.css +1 -0
  45. package/.output/public/_nuxt/{teams.CLQaXno5.css → teams.DEJoJ4QV.css} +1 -1
  46. package/.output/public/_nuxt/{tokens.BDSUWF-L.css → tokens.DKZWCP5v.css} +1 -1
  47. package/.output/public/_nuxt/tools.DP-nsTli.css +1 -0
  48. package/.output/public/_nuxt/wK6Pp4Zc2.js +2 -0
  49. package/.output/public/_nuxt/{workshop.BBiFhXuM.css → workshop.PT1xhP8C.css} +1 -1
  50. package/.output/public/favicon.svg +14 -14
  51. package/.output/public/robots.txt +3 -3
  52. package/.output/server/chunks/_/LeftOutlined.mjs.map +1 -1
  53. package/.output/server/chunks/_/RightOutlined.mjs.map +1 -1
  54. package/.output/server/chunks/_/SearchOutlined.mjs +1230 -1261
  55. package/.output/server/chunks/_/SearchOutlined.mjs.map +1 -1
  56. package/.output/server/chunks/_/error-500.mjs.map +1 -1
  57. package/.output/server/chunks/_/nitro.mjs +3308 -3389
  58. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  59. package/.output/server/chunks/build/AuthGate-G74Wr5IV.mjs +704 -0
  60. package/.output/server/chunks/build/AuthGate-G74Wr5IV.mjs.map +1 -0
  61. package/.output/server/chunks/build/FormItemContext-DmuQqaeJ.mjs +77 -0
  62. package/.output/server/chunks/build/FormItemContext-DmuQqaeJ.mjs.map +1 -0
  63. package/.output/server/chunks/build/OmpTerminalPanel-5cB-78zp.mjs +889 -0
  64. package/.output/server/chunks/build/OmpTerminalPanel-5cB-78zp.mjs.map +1 -0
  65. package/.output/server/chunks/build/PluginSlot-CZlGlRoR.mjs +131 -0
  66. package/.output/server/chunks/build/PluginSlot-CZlGlRoR.mjs.map +1 -0
  67. package/.output/server/chunks/build/TownView-CUbzOT_M.mjs +5960 -0
  68. package/.output/server/chunks/build/TownView-CUbzOT_M.mjs.map +1 -0
  69. package/.output/server/chunks/build/_id_-BHWZiRQZ.mjs +373 -0
  70. package/.output/server/chunks/build/_id_-BHWZiRQZ.mjs.map +1 -0
  71. package/.output/server/chunks/build/_id_-JaGx0yBE.mjs +1922 -0
  72. package/.output/server/chunks/build/_id_-JaGx0yBE.mjs.map +1 -0
  73. package/.output/server/chunks/build/_wsId_-C4DKkEqv.mjs +13707 -0
  74. package/.output/server/chunks/build/_wsId_-C4DKkEqv.mjs.map +1 -0
  75. package/.output/server/chunks/build/agents-DRod4lTC.mjs +1047 -0
  76. package/.output/server/chunks/build/agents-DRod4lTC.mjs.map +1 -0
  77. package/.output/server/chunks/build/alert-CNGhs--Y.mjs +260 -0
  78. package/.output/server/chunks/build/alert-CNGhs--Y.mjs.map +1 -0
  79. package/.output/server/chunks/build/aml-B3Umz4DR.mjs +729 -0
  80. package/.output/server/chunks/build/aml-B3Umz4DR.mjs.map +1 -0
  81. package/.output/server/chunks/build/analysis-tNpFLtMt.mjs +502 -0
  82. package/.output/server/chunks/build/analysis-tNpFLtMt.mjs.map +1 -0
  83. package/.output/server/chunks/build/{api-B4Om0mEc.mjs → api-D-zkgkj-.mjs} +8 -10
  84. package/.output/server/chunks/build/api-D-zkgkj-.mjs.map +1 -0
  85. package/.output/server/chunks/build/{api-BsAgXWxi.mjs → api-D3gy2e2q.mjs} +22 -24
  86. package/.output/server/chunks/build/api-D3gy2e2q.mjs.map +1 -0
  87. package/.output/server/chunks/build/{api-BEW_ebY_.mjs → api-bn4OKkl_.mjs} +17 -19
  88. package/.output/server/chunks/build/api-bn4OKkl_.mjs.map +1 -0
  89. package/.output/server/chunks/build/api-error-CnW_xiNI.mjs +46 -0
  90. package/.output/server/chunks/build/api-error-CnW_xiNI.mjs.map +1 -0
  91. package/.output/server/chunks/build/apiClient-DIXx9sfD.mjs +70 -0
  92. package/.output/server/chunks/build/apiClient-DIXx9sfD.mjs.map +1 -0
  93. package/.output/server/chunks/build/board-B2oYXGBy.mjs +172 -0
  94. package/.output/server/chunks/build/board-B2oYXGBy.mjs.map +1 -0
  95. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs +81 -94
  96. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs.map +1 -1
  97. package/.output/server/chunks/build/card-BECE6y_G.mjs +922 -0
  98. package/.output/server/chunks/build/card-BECE6y_G.mjs.map +1 -0
  99. package/.output/server/chunks/build/channel-templates-R2TInv8B.mjs +950 -0
  100. package/.output/server/chunks/build/channel-templates-R2TInv8B.mjs.map +1 -0
  101. package/.output/server/chunks/build/chart-trend-BWeZh5Lv.mjs +113 -112
  102. package/.output/server/chunks/build/chart-trend-BWeZh5Lv.mjs.map +1 -1
  103. package/.output/server/chunks/build/checkbox-C6xY5uc6.mjs +429 -0
  104. package/.output/server/chunks/build/checkbox-C6xY5uc6.mjs.map +1 -0
  105. package/.output/server/chunks/build/client-only-S7k53PIm.mjs +42 -0
  106. package/.output/server/chunks/build/client-only-S7k53PIm.mjs.map +1 -0
  107. package/.output/server/chunks/build/constants-HPHJvjne.mjs +65 -75
  108. package/.output/server/chunks/build/constants-HPHJvjne.mjs.map +1 -1
  109. package/.output/server/chunks/build/core-CRlsQhzd.mjs +292 -0
  110. package/.output/server/chunks/build/core-CRlsQhzd.mjs.map +1 -0
  111. package/.output/server/chunks/build/daq-DHsYtWC-.mjs +1210 -0
  112. package/.output/server/chunks/build/daq-DHsYtWC-.mjs.map +1 -0
  113. package/.output/server/chunks/build/data-Cl4wRZO6.mjs +459 -0
  114. package/.output/server/chunks/build/data-Cl4wRZO6.mjs.map +1 -0
  115. package/.output/server/chunks/build/dcw-DnjOM6p1.mjs +467 -0
  116. package/.output/server/chunks/build/dcw-DnjOM6p1.mjs.map +1 -0
  117. package/.output/server/chunks/build/dcw-driver-badge-Df5wL_ZA.mjs +3 -15
  118. package/.output/server/chunks/build/dcw-driver-badge-Df5wL_ZA.mjs.map +1 -1
  119. package/.output/server/chunks/build/default-DDRKP2Mb.mjs +2246 -0
  120. package/.output/server/chunks/build/default-DDRKP2Mb.mjs.map +1 -0
  121. package/.output/server/chunks/build/descriptions-B3uhDesi.mjs +401 -0
  122. package/.output/server/chunks/build/descriptions-B3uhDesi.mjs.map +1 -0
  123. package/.output/server/chunks/build/drawer-DwXxapMg.mjs +822 -0
  124. package/.output/server/chunks/build/drawer-DwXxapMg.mjs.map +1 -0
  125. package/.output/server/chunks/build/dropdown-DLrGy-Fs.mjs +12 -0
  126. package/.output/server/chunks/build/dropdown-DLrGy-Fs.mjs.map +1 -0
  127. package/.output/server/chunks/build/dropdown-nsGv8Gqx.mjs +530 -0
  128. package/.output/server/chunks/build/dropdown-nsGv8Gqx.mjs.map +1 -0
  129. package/.output/server/chunks/build/{es-Bxu10NJ2.mjs → es-DXSEkmAm.mjs} +1 -2
  130. package/.output/server/chunks/build/es-DXSEkmAm.mjs.map +1 -0
  131. package/.output/server/chunks/build/firstNotUndefined-laiThpLD.mjs +2082 -0
  132. package/.output/server/chunks/build/firstNotUndefined-laiThpLD.mjs.map +1 -0
  133. package/.output/server/chunks/build/form-Cw2Ex9w5.mjs +3543 -0
  134. package/.output/server/chunks/build/form-Cw2Ex9w5.mjs.map +1 -0
  135. package/.output/server/chunks/build/hasIn-RYRGomyg.mjs +192 -0
  136. package/.output/server/chunks/build/hasIn-RYRGomyg.mjs.map +1 -0
  137. package/.output/server/chunks/build/hitl-B4cHRlkC.mjs +120 -0
  138. package/.output/server/chunks/build/hitl-B4cHRlkC.mjs.map +1 -0
  139. package/.output/server/chunks/build/input-CJgB-RL6.mjs +1705 -0
  140. package/.output/server/chunks/build/input-CJgB-RL6.mjs.map +1 -0
  141. package/.output/server/chunks/build/input-number-CQKL42p_.mjs +1027 -0
  142. package/.output/server/chunks/build/input-number-CQKL42p_.mjs.map +1 -0
  143. package/.output/server/chunks/build/interval-DiAUqODq.mjs +8 -0
  144. package/.output/server/chunks/build/interval-DiAUqODq.mjs.map +1 -0
  145. package/.output/server/chunks/build/isNumeric-DQiJ-b15.mjs +6 -0
  146. package/.output/server/chunks/build/isNumeric-DQiJ-b15.mjs.map +1 -0
  147. package/.output/server/chunks/build/logs-C4vKFkHQ.mjs +381 -0
  148. package/.output/server/chunks/build/logs-C4vKFkHQ.mjs.map +1 -0
  149. package/.output/server/chunks/build/menu-xO8ocVtL.mjs +1833 -0
  150. package/.output/server/chunks/build/menu-xO8ocVtL.mjs.map +1 -0
  151. package/.output/server/chunks/build/monitor-BNrG6v3b.mjs +2216 -0
  152. package/.output/server/chunks/build/monitor-BNrG6v3b.mjs.map +1 -0
  153. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs +0 -2
  154. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs.map +1 -1
  155. package/.output/server/chunks/build/ontology-B_0Vm6j-.mjs +1416 -0
  156. package/.output/server/chunks/build/ontology-B_0Vm6j-.mjs.map +1 -0
  157. package/.output/server/chunks/build/operations-D8D6-Jm-.mjs +278 -0
  158. package/.output/server/chunks/build/operations-D8D6-Jm-.mjs.map +1 -0
  159. package/.output/server/chunks/build/optimizer-DaTyaY3c.mjs +202 -0
  160. package/.output/server/chunks/build/optimizer-DaTyaY3c.mjs.map +1 -0
  161. package/.output/server/chunks/build/pages-Dac4icQC.mjs +439 -0
  162. package/.output/server/chunks/build/pages-Dac4icQC.mjs.map +1 -0
  163. package/.output/server/chunks/build/pagination-BTzq7dD5.mjs +1330 -0
  164. package/.output/server/chunks/build/pagination-BTzq7dD5.mjs.map +1 -0
  165. package/.output/server/chunks/build/permissions-qmimwB0M.mjs +649 -0
  166. package/.output/server/chunks/build/permissions-qmimwB0M.mjs.map +1 -0
  167. package/.output/server/chunks/build/plugins-Dh_goy-k.mjs +269 -0
  168. package/.output/server/chunks/build/plugins-Dh_goy-k.mjs.map +1 -0
  169. package/.output/server/chunks/build/popconfirm-DuGF7ty-.mjs +333 -0
  170. package/.output/server/chunks/build/popconfirm-DuGF7ty-.mjs.map +1 -0
  171. package/.output/server/chunks/build/responsiveObserve-CzRpNXkr.mjs +77 -0
  172. package/.output/server/chunks/build/responsiveObserve-CzRpNXkr.mjs.map +1 -0
  173. package/.output/server/chunks/build/schedules-C2_x38gj.mjs +7039 -0
  174. package/.output/server/chunks/build/schedules-C2_x38gj.mjs.map +1 -0
  175. package/.output/server/chunks/build/segmented-29uEKZ3D.mjs +332 -0
  176. package/.output/server/chunks/build/segmented-29uEKZ3D.mjs.map +1 -0
  177. package/.output/server/chunks/build/select-CJb2XrQf.mjs +3734 -0
  178. package/.output/server/chunks/build/select-CJb2XrQf.mjs.map +1 -0
  179. package/.output/server/chunks/build/settings-Cz2Plds0.mjs +944 -0
  180. package/.output/server/chunks/build/settings-Cz2Plds0.mjs.map +1 -0
  181. package/.output/server/chunks/build/space-BByD-mFE.mjs +107 -0
  182. package/.output/server/chunks/build/space-BByD-mFE.mjs.map +1 -0
  183. package/.output/server/chunks/build/spin-XhbgGeLP.mjs +313 -0
  184. package/.output/server/chunks/build/spin-XhbgGeLP.mjs.map +1 -0
  185. package/.output/server/chunks/build/studio-CwYXl00G.mjs +329 -0
  186. package/.output/server/chunks/build/studio-CwYXl00G.mjs.map +1 -0
  187. package/.output/server/chunks/build/switch-DWcwVFxW.mjs +374 -0
  188. package/.output/server/chunks/build/switch-DWcwVFxW.mjs.map +1 -0
  189. package/.output/server/chunks/build/table-Zhuo7Fq-.mjs +7249 -0
  190. package/.output/server/chunks/build/table-Zhuo7Fq-.mjs.map +1 -0
  191. package/.output/server/chunks/build/tabs-BCwBXjNt.mjs +1838 -0
  192. package/.output/server/chunks/build/tabs-BCwBXjNt.mjs.map +1 -0
  193. package/.output/server/chunks/build/tag-CRW-anwy.mjs +1010 -0
  194. package/.output/server/chunks/build/tag-CRW-anwy.mjs.map +1 -0
  195. package/.output/server/chunks/build/teams-CwhFdcYn.mjs +1160 -0
  196. package/.output/server/chunks/build/teams-CwhFdcYn.mjs.map +1 -0
  197. package/.output/server/chunks/build/tokens-C5ODO1HA.mjs +992 -0
  198. package/.output/server/chunks/build/tokens-C5ODO1HA.mjs.map +1 -0
  199. package/.output/server/chunks/build/tools-C0YKragH.mjs +487 -0
  200. package/.output/server/chunks/build/tools-C0YKragH.mjs.map +1 -0
  201. package/.output/server/chunks/build/tooltip-GlMrUZzx.mjs +888 -0
  202. package/.output/server/chunks/build/tooltip-GlMrUZzx.mjs.map +1 -0
  203. package/.output/server/chunks/build/town-BV-hbwb5.mjs +16 -29
  204. package/.output/server/chunks/build/town-BV-hbwb5.mjs.map +1 -1
  205. package/.output/server/chunks/build/town-LkDwWnKA.mjs +117 -0
  206. package/.output/server/chunks/build/town-LkDwWnKA.mjs.map +1 -0
  207. package/.output/server/chunks/build/types-D6J7slEa.mjs.map +1 -1
  208. package/.output/server/chunks/build/types-DWqIeMRP.mjs +28 -29
  209. package/.output/server/chunks/build/types-DWqIeMRP.mjs.map +1 -1
  210. package/.output/server/chunks/build/useAgentHarnessOptions-CYKuLtZ2.mjs +120 -0
  211. package/.output/server/chunks/build/useAgentHarnessOptions-CYKuLtZ2.mjs.map +1 -0
  212. package/.output/server/chunks/build/useAgentTemplateActions-Da_V1LSD.mjs +71 -0
  213. package/.output/server/chunks/build/useAgentTemplateActions-Da_V1LSD.mjs.map +1 -0
  214. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs +16 -23
  215. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs.map +1 -1
  216. package/.output/server/chunks/build/useAgentTemplateForm-BWvax5_E.mjs +112 -0
  217. package/.output/server/chunks/build/useAgentTemplateForm-BWvax5_E.mjs.map +1 -0
  218. package/.output/server/chunks/build/useAgentTemplatesCatalog-BnYjZy59.mjs +140 -0
  219. package/.output/server/chunks/build/useAgentTemplatesCatalog-BnYjZy59.mjs.map +1 -0
  220. package/.output/server/chunks/build/useAmlDatasets-nGi10DAl.mjs +88 -0
  221. package/.output/server/chunks/build/useAmlDatasets-nGi10DAl.mjs.map +1 -0
  222. package/.output/server/chunks/build/useAmlEntities-CTgNAgcZ.mjs +79 -0
  223. package/.output/server/chunks/build/useAmlEntities-CTgNAgcZ.mjs.map +1 -0
  224. package/.output/server/chunks/build/useAmlEnv-Da2TVfyK.mjs +188 -0
  225. package/.output/server/chunks/build/useAmlEnv-Da2TVfyK.mjs.map +1 -0
  226. package/.output/server/chunks/build/useAmlExperiments-U9AQ52RI.mjs +86 -0
  227. package/.output/server/chunks/build/useAmlExperiments-U9AQ52RI.mjs.map +1 -0
  228. package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs +32 -37
  229. package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs.map +1 -1
  230. package/.output/server/chunks/build/useAmlJobs-BM1mu5iH.mjs +251 -0
  231. package/.output/server/chunks/build/useAmlJobs-BM1mu5iH.mjs.map +1 -0
  232. package/.output/server/chunks/build/useAmlModels-C1DwIOMi.mjs +90 -0
  233. package/.output/server/chunks/build/useAmlModels-C1DwIOMi.mjs.map +1 -0
  234. package/.output/server/chunks/build/useAmlNotes-CNm47QdS.mjs +80 -0
  235. package/.output/server/chunks/build/useAmlNotes-CNm47QdS.mjs.map +1 -0
  236. package/.output/server/chunks/build/useAmlPredict-m8I1AdRn.mjs +126 -0
  237. package/.output/server/chunks/build/useAmlPredict-m8I1AdRn.mjs.map +1 -0
  238. package/.output/server/chunks/build/useAnalysisFeed-CpbOaiBD.mjs +120 -0
  239. package/.output/server/chunks/build/useAnalysisFeed-CpbOaiBD.mjs.map +1 -0
  240. package/.output/server/chunks/build/useDaqAddNode-CRorxgOY.mjs +141 -0
  241. package/.output/server/chunks/build/useDaqAddNode-CRorxgOY.mjs.map +1 -0
  242. package/.output/server/chunks/build/useDaqDetailBinding-Ck-YUW9J.mjs +72 -0
  243. package/.output/server/chunks/build/useDaqDetailBinding-Ck-YUW9J.mjs.map +1 -0
  244. package/.output/server/chunks/build/useDaqDetailFrames-CLMoreaz.mjs +78 -0
  245. package/.output/server/chunks/build/useDaqDetailFrames-CLMoreaz.mjs.map +1 -0
  246. package/.output/server/chunks/build/useDaqDetailHistory-BVNQXwC_.mjs +166 -0
  247. package/.output/server/chunks/build/useDaqDetailHistory-BVNQXwC_.mjs.map +1 -0
  248. package/.output/server/chunks/build/useDaqDetailNode-BC0e9OfX.mjs +103 -0
  249. package/.output/server/chunks/build/useDaqDetailNode-BC0e9OfX.mjs.map +1 -0
  250. package/.output/server/chunks/build/useDaqDetailParams-D173iwFg.mjs +157 -0
  251. package/.output/server/chunks/build/useDaqDetailParams-D173iwFg.mjs.map +1 -0
  252. package/.output/server/chunks/build/useDaqFilters-CC-o_21d.mjs +224 -0
  253. package/.output/server/chunks/build/useDaqFilters-CC-o_21d.mjs.map +1 -0
  254. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs +43 -44
  255. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs.map +1 -1
  256. package/.output/server/chunks/build/useDaqOptimizations-4vK2w1yn.mjs +132 -0
  257. package/.output/server/chunks/build/useDaqOptimizations-4vK2w1yn.mjs.map +1 -0
  258. package/.output/server/chunks/build/useDaqStream-BHKpSJFd.mjs +385 -0
  259. package/.output/server/chunks/build/useDaqStream-BHKpSJFd.mjs.map +1 -0
  260. package/.output/server/chunks/build/useDaqTemplates-CsXSc7yI.mjs +181 -0
  261. package/.output/server/chunks/build/useDaqTemplates-CsXSc7yI.mjs.map +1 -0
  262. package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs +312 -310
  263. package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs.map +1 -1
  264. package/.output/server/chunks/build/useDashboardData-DuKjuJTz.mjs +139 -0
  265. package/.output/server/chunks/build/useDashboardData-DuKjuJTz.mjs.map +1 -0
  266. package/.output/server/chunks/build/useDcwAddNode-C5DcxsHF.mjs +217 -0
  267. package/.output/server/chunks/build/useDcwAddNode-C5DcxsHF.mjs.map +1 -0
  268. package/.output/server/chunks/build/{useDcwCards-SaiImIYQ.mjs → useDcwCards-0bAVo6uB.mjs} +20 -23
  269. package/.output/server/chunks/build/useDcwCards-0bAVo6uB.mjs.map +1 -0
  270. package/.output/server/chunks/build/useDcwDetailScope-BNFOlt2v.mjs +184 -0
  271. package/.output/server/chunks/build/useDcwDetailScope-BNFOlt2v.mjs.map +1 -0
  272. package/.output/server/chunks/build/useDcwDetailTemplates-DSH-o0tE.mjs +143 -0
  273. package/.output/server/chunks/build/useDcwDetailTemplates-DSH-o0tE.mjs.map +1 -0
  274. package/.output/server/chunks/build/useDcwFilter-W61BFUcT.mjs +65 -0
  275. package/.output/server/chunks/build/useDcwFilter-W61BFUcT.mjs.map +1 -0
  276. package/.output/server/chunks/build/{useDcwLedger-0ie-0WTc.mjs → useDcwLedger-DsColLdc.mjs} +29 -35
  277. package/.output/server/chunks/build/useDcwLedger-DsColLdc.mjs.map +1 -0
  278. package/.output/server/chunks/build/useDcwLineMutations-Cx4Ir7g3.mjs +133 -0
  279. package/.output/server/chunks/build/useDcwLineMutations-Cx4Ir7g3.mjs.map +1 -0
  280. package/.output/server/chunks/build/useDcwLineRun-DQ0vB08z.mjs +100 -0
  281. package/.output/server/chunks/build/useDcwLineRun-DQ0vB08z.mjs.map +1 -0
  282. package/.output/server/chunks/build/useDcwParamApprovals-CYspRuDk.mjs +119 -0
  283. package/.output/server/chunks/build/useDcwParamApprovals-CYspRuDk.mjs.map +1 -0
  284. package/.output/server/chunks/build/useDcwProducts-CTbm_5S_.mjs +88 -0
  285. package/.output/server/chunks/build/useDcwProducts-CTbm_5S_.mjs.map +1 -0
  286. package/.output/server/chunks/build/useDcwQuery-E0yjZs7G.mjs +93 -0
  287. package/.output/server/chunks/build/useDcwQuery-E0yjZs7G.mjs.map +1 -0
  288. package/.output/server/chunks/build/useDcwQuickActions-BvT5VFOY.mjs +84 -0
  289. package/.output/server/chunks/build/useDcwQuickActions-BvT5VFOY.mjs.map +1 -0
  290. package/.output/server/chunks/build/useDcwRecipes-zngShyk0.mjs +263 -0
  291. package/.output/server/chunks/build/useDcwRecipes-zngShyk0.mjs.map +1 -0
  292. package/.output/server/chunks/build/useDcwStream-82IdjJKk.mjs +455 -0
  293. package/.output/server/chunks/build/useDcwStream-82IdjJKk.mjs.map +1 -0
  294. package/.output/server/chunks/build/useDcwTemplates-CpHrcnvJ.mjs +87 -0
  295. package/.output/server/chunks/build/useDcwTemplates-CpHrcnvJ.mjs.map +1 -0
  296. package/.output/server/chunks/build/useDcwWrites-BlOhljp9.mjs +136 -0
  297. package/.output/server/chunks/build/useDcwWrites-BlOhljp9.mjs.map +1 -0
  298. package/.output/server/chunks/build/useDeviceTwins-DL-VLFeX.mjs +118 -0
  299. package/.output/server/chunks/build/useDeviceTwins-DL-VLFeX.mjs.map +1 -0
  300. package/.output/server/chunks/build/useExpConfirmations-DgwqTb9O.mjs +104 -0
  301. package/.output/server/chunks/build/useExpConfirmations-DgwqTb9O.mjs.map +1 -0
  302. package/.output/server/chunks/build/useLocalTime-C__kwn8h.mjs +52 -0
  303. package/.output/server/chunks/build/useLocalTime-C__kwn8h.mjs.map +1 -0
  304. package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs +30 -33
  305. package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs.map +1 -1
  306. package/.output/server/chunks/build/useLogsManual-BcfanT0s.mjs +80 -0
  307. package/.output/server/chunks/build/useLogsManual-BcfanT0s.mjs.map +1 -0
  308. package/.output/server/chunks/build/useLogsQuery-BGlKVKpV.mjs +136 -0
  309. package/.output/server/chunks/build/useLogsQuery-BGlKVKpV.mjs.map +1 -0
  310. package/.output/server/chunks/build/useLogsScope-BRyy550Y.mjs +75 -0
  311. package/.output/server/chunks/build/useLogsScope-BRyy550Y.mjs.map +1 -0
  312. package/.output/server/chunks/build/useMonitorColumns-vVnt3r5Q.mjs +155 -166
  313. package/.output/server/chunks/build/useMonitorColumns-vVnt3r5Q.mjs.map +1 -1
  314. package/.output/server/chunks/build/useMonitorData-BUey2Xly.mjs +128 -0
  315. package/.output/server/chunks/build/useMonitorData-BUey2Xly.mjs.map +1 -0
  316. package/.output/server/chunks/build/useMonitorFormat-rhs7FlNo.mjs +77 -0
  317. package/.output/server/chunks/build/useMonitorFormat-rhs7FlNo.mjs.map +1 -0
  318. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs +20 -27
  319. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs.map +1 -1
  320. package/.output/server/chunks/build/useOperationsFeed-DWfCjP4l.mjs +182 -0
  321. package/.output/server/chunks/build/useOperationsFeed-DWfCjP4l.mjs.map +1 -0
  322. package/.output/server/chunks/build/useOpsLog--yf8erUi.mjs +139 -0
  323. package/.output/server/chunks/build/useOpsLog--yf8erUi.mjs.map +1 -0
  324. package/.output/server/chunks/build/useRecipeDispatchApprovals-CKF2sB9P.mjs +146 -0
  325. package/.output/server/chunks/build/useRecipeDispatchApprovals-CKF2sB9P.mjs.map +1 -0
  326. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs +23 -39
  327. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs.map +1 -1
  328. package/.output/server/chunks/build/useTeamActions-C08sAVqY.mjs +71 -0
  329. package/.output/server/chunks/build/useTeamActions-C08sAVqY.mjs.map +1 -0
  330. package/.output/server/chunks/build/useTeamAddMemberDialog-fzTmflr8.mjs +78 -0
  331. package/.output/server/chunks/build/useTeamAddMemberDialog-fzTmflr8.mjs.map +1 -0
  332. package/.output/server/chunks/build/useTeamCreateDialog-De63ep-X.mjs +91 -0
  333. package/.output/server/chunks/build/useTeamCreateDialog-De63ep-X.mjs.map +1 -0
  334. package/.output/server/chunks/build/useTeamDeployDialog-CpAtG5Jy.mjs +76 -0
  335. package/.output/server/chunks/build/useTeamDeployDialog-CpAtG5Jy.mjs.map +1 -0
  336. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs +31 -38
  337. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs.map +1 -1
  338. package/.output/server/chunks/build/useTeamPluginDialog-C1OOe1sL.mjs +99 -0
  339. package/.output/server/chunks/build/useTeamPluginDialog-C1OOe1sL.mjs.map +1 -0
  340. package/.output/server/chunks/build/useTeamsCatalog-DA41SMDu.mjs +124 -0
  341. package/.output/server/chunks/build/useTeamsCatalog-DA41SMDu.mjs.map +1 -0
  342. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs +21 -28
  343. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs.map +1 -1
  344. package/.output/server/chunks/build/useTokenCreate-XHTQExra.mjs +106 -0
  345. package/.output/server/chunks/build/useTokenCreate-XHTQExra.mjs.map +1 -0
  346. package/.output/server/chunks/build/useTokenRename-Cf1B0cRy.mjs +81 -0
  347. package/.output/server/chunks/build/useTokenRename-Cf1B0cRy.mjs.map +1 -0
  348. package/.output/server/chunks/build/useTokenReveal-C8n1Vt9t.mjs +108 -0
  349. package/.output/server/chunks/build/useTokenReveal-C8n1Vt9t.mjs.map +1 -0
  350. package/.output/server/chunks/build/useTokensList-MMIq24E-.mjs +86 -0
  351. package/.output/server/chunks/build/useTokensList-MMIq24E-.mjs.map +1 -0
  352. package/.output/server/chunks/build/useTownBus-D9SoIsAN.mjs +16 -17
  353. package/.output/server/chunks/build/useTownBus-D9SoIsAN.mjs.map +1 -1
  354. package/.output/server/chunks/build/useWorkbenchAuth-Dyc_czui.mjs +131 -0
  355. package/.output/server/chunks/build/useWorkbenchAuth-Dyc_czui.mjs.map +1 -0
  356. package/.output/server/chunks/build/useWorkbenchWorkspaces-DT33HbBD.mjs +128 -0
  357. package/.output/server/chunks/build/useWorkbenchWorkspaces-DT33HbBD.mjs.map +1 -0
  358. package/.output/server/chunks/build/useWorkshopApi-BkEgGBIM.mjs +118 -0
  359. package/.output/server/chunks/build/useWorkshopApi-BkEgGBIM.mjs.map +1 -0
  360. package/.output/server/chunks/build/useWorkshopWs-BWrVj4jL.mjs +1577 -0
  361. package/.output/server/chunks/build/useWorkshopWs-BWrVj4jL.mjs.map +1 -0
  362. package/.output/server/chunks/build/{useWorkspaceAuth-Dlvj9csD.mjs → useWorkspaceAuth-TahC9EC7.mjs} +4 -16
  363. package/.output/server/chunks/build/useWorkspaceAuth-TahC9EC7.mjs.map +1 -0
  364. package/.output/server/chunks/build/useWorkspaceChannels-BVAHmhN3.mjs +94 -0
  365. package/.output/server/chunks/build/useWorkspaceChannels-BVAHmhN3.mjs.map +1 -0
  366. package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs +30 -33
  367. package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs.map +1 -1
  368. package/.output/server/chunks/build/useWorkspaceShell-rQHWNNWJ.mjs +150 -0
  369. package/.output/server/chunks/build/useWorkspaceShell-rQHWNNWJ.mjs.map +1 -0
  370. package/.output/server/chunks/build/users-pVCK50z-.mjs +566 -0
  371. package/.output/server/chunks/build/users-pVCK50z-.mjs.map +1 -0
  372. package/.output/server/chunks/build/workshop-DAgsBgG4.mjs +499 -0
  373. package/.output/server/chunks/build/workshop-DAgsBgG4.mjs.map +1 -0
  374. package/.output/server/chunks/build/workspaces-CmW0cpOt.mjs +111 -121
  375. package/.output/server/chunks/build/workspaces-CmW0cpOt.mjs.map +1 -1
  376. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +4 -1
  377. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
  378. package/.output/server/chunks/routes/renderer.mjs +1 -1
  379. package/.output/server/chunks/routes/renderer.mjs.map +1 -1
  380. package/.output/server/chunks/virtual/entry.mjs +9357 -10721
  381. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  382. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  383. package/.output/server/chunks/virtual/precomputed.mjs.map +1 -1
  384. package/.output/server/package.json +1 -1
  385. package/README-zh.md +2 -2
  386. package/README.md +3 -3
  387. package/app/components/AwLogo.vue +75 -75
  388. package/app/components/aml/AmlDatasetFormModal.vue +279 -279
  389. package/app/components/aml/AmlDatasetTable.vue +319 -319
  390. package/app/components/aml/AmlExperimentsTable.vue +142 -142
  391. package/app/components/aml/AmlInfraBanner.vue +23 -23
  392. package/app/components/aml/AmlJobsTable.vue +248 -248
  393. package/app/components/aml/AmlOverviewBar.vue +62 -62
  394. package/app/components/aml/AmlPageHeader.vue +47 -47
  395. package/app/components/aml/AmlPredictConsole.vue +201 -201
  396. package/app/components/app-header/HitlBell.vue +423 -423
  397. package/app/components/daq/DaqAddNodeModal.vue +209 -209
  398. package/app/components/daq/DaqAlarmBar.vue +46 -46
  399. package/app/components/daq/DaqControlCard.vue +159 -159
  400. package/app/components/daq/DaqInfraBanner.vue +31 -31
  401. package/app/components/daq/DaqLineBanner.vue +47 -47
  402. package/app/components/daq/DaqNodePanel.vue +396 -396
  403. package/app/components/daq/DaqOptPanel.vue +197 -197
  404. package/app/components/daq/DaqTemplateModal.vue +246 -246
  405. package/app/components/dashboard/DashboardGaugeBand.vue +78 -78
  406. package/app/components/dashboard/DashboardHero.vue +209 -209
  407. package/app/components/dashboard/DashboardLineStatePanel.vue +78 -78
  408. package/app/components/dashboard/DashboardNodeStatePanel.vue +46 -46
  409. package/app/components/dashboard/DashboardPipelinePanel.vue +46 -46
  410. package/app/components/dashboard/DashboardTrendPanel.vue +83 -83
  411. package/app/components/dashboard/DashboardWritePanel.vue +52 -52
  412. package/app/components/dcw/DcwCreateLineModal.vue +105 -105
  413. package/app/components/dcw/DcwDeleteLineModal.vue +73 -73
  414. package/app/components/dcw/DcwDetailTemplateModal.vue +238 -238
  415. package/app/components/dcw/DcwLedgerCard.vue +160 -160
  416. package/app/components/dcw/DcwMesArtifacts.vue +140 -140
  417. package/app/components/dcw/DcwProductCreateModal.vue +113 -113
  418. package/app/components/dcw/DcwRecipeDispatchHistoryModal.vue +244 -244
  419. package/app/components/dcw/DcwRecipeEditModal.vue +399 -399
  420. package/app/components/dcw/DcwRecipeHistoryModal.vue +165 -165
  421. package/app/components/dcw/DcwRunDataModal.vue +191 -191
  422. package/app/components/dcw/DcwTemplateModal.vue +227 -227
  423. package/app/components/dcw/DcwWriteHistoryCard.vue +96 -96
  424. package/app/components/dcw/ExpConfirmCard.vue +103 -103
  425. package/app/components/dcw/RecipeDispatchApprovalCard.vue +330 -330
  426. package/app/components/logs/LogsPageHead.vue +71 -71
  427. package/app/components/monitor/MonitorAgentTable.vue +143 -143
  428. package/app/components/monitor/MonitorChannelTable.vue +80 -80
  429. package/app/components/monitor/MonitorLoginGate.vue +24 -24
  430. package/app/components/monitor/MonitorPageHead.vue +92 -92
  431. package/app/components/monitor/MonitorProcessTable.vue +159 -159
  432. package/app/components/ontology/OntologyGraph.vue +356 -356
  433. package/app/components/operations/OperationsFilterCard.vue +164 -164
  434. package/app/components/operations/OperationsPageHead.vue +47 -47
  435. package/app/components/tokens/TokenCreateModal.vue +42 -42
  436. package/app/components/tokens/TokenOnceModal.vue +164 -164
  437. package/app/components/tokens/TokenRenameModal.vue +40 -40
  438. package/app/components/tokens/TokensPageHead.vue +76 -76
  439. package/app/components/workshop/A2aRpcDebugger.vue +237 -237
  440. package/app/components/workshop/AgentInspectorDrawer.vue +424 -424
  441. package/app/components/workshop/AgentLanesView.vue +278 -278
  442. package/app/components/workshop/ArtifactCard.vue +120 -120
  443. package/app/components/workshop/AssetLibrary.vue +452 -452
  444. package/app/components/workshop/ChatMemberPanel.vue +556 -556
  445. package/app/components/workshop/CommandPalette.vue +270 -270
  446. package/app/components/workshop/Composer.vue +540 -540
  447. package/app/components/workshop/DaqTemplateIcon.vue +33 -33
  448. package/app/components/workshop/DeviceTwinPanel.vue +167 -167
  449. package/app/components/workshop/FileSelectorModal.vue +188 -188
  450. package/app/components/workshop/InspectorPanel.vue +301 -301
  451. package/app/components/workshop/PluginSlot.vue +120 -120
  452. package/app/components/workshop/TranscriptTimeline.vue +223 -223
  453. package/app/components/workshop/agents/AgentTemplateEditModal.vue +139 -139
  454. package/app/components/workshop/blocks/ClusterArtifact.vue +61 -61
  455. package/app/components/workshop/blocks/ClusterError.vue +85 -85
  456. package/app/components/workshop/blocks/ClusterLife.vue +87 -87
  457. package/app/components/workshop/blocks/ClusterMember.vue +95 -95
  458. package/app/components/workshop/blocks/ClusterMemory.vue +84 -84
  459. package/app/components/workshop/blocks/ClusterOther.vue +67 -67
  460. package/app/components/workshop/blocks/ClusterStatus.vue +149 -149
  461. package/app/components/workshop/blocks/ClusterTool.vue +176 -176
  462. package/app/components/workshop/blocks/EventBlockAvatar.vue +114 -114
  463. package/app/components/workshop/blocks/EventBlockHead.vue +232 -232
  464. package/app/components/workshop/composer/ComposerToolbar.vue +278 -278
  465. package/app/components/workshop/composer/MentionMenu.vue +135 -135
  466. package/app/components/workshop/composer/ReplyChip.vue +65 -65
  467. package/app/components/workshop/composer/StatusChip.vue +171 -171
  468. package/app/components/workshop/console/Dock.vue +71 -71
  469. package/app/components/workshop/console/LeftPane.vue +84 -84
  470. package/app/components/workshop/device-twin/DeviceTwinCard.vue +265 -265
  471. package/app/components/workshop/device-twin/DeviceTwinDcwSection.vue +203 -203
  472. package/app/components/workshop/lanes/AddMemberModal.vue +270 -270
  473. package/app/components/workshop/lanes/EditMemberModal.vue +106 -106
  474. package/app/components/workshop/lanes/LanesToolbar.vue +97 -97
  475. package/app/components/workshop/session-list/ChannelSettingsModal.vue +3 -3
  476. package/app/components/workshop/session-list/MountChannelModal.vue +124 -124
  477. package/app/components/workshop/session-list/SaveTemplateModal.vue +93 -93
  478. package/app/components/workshop/task-board/Card.vue +172 -172
  479. package/app/components/workshop/task-board/Column.vue +151 -151
  480. package/app/components/workshop/task-board/List.vue +157 -157
  481. package/app/components/workshop/task-board/StatusMenu.vue +88 -88
  482. package/app/components/workshop/teams/TeamAddMemberModal.vue +53 -53
  483. package/app/components/workshop/teams/TeamCreateModal.vue +94 -94
  484. package/app/components/workshop/teams/TeamDeployModal.vue +40 -40
  485. package/app/components/workshop/teams/TeamPluginModal.vue +119 -119
  486. package/app/components/workshop/terminal/OmpTerminalPanel.vue +270 -270
  487. package/app/components/workshop/terminal/TerminalHitlCard.vue +170 -170
  488. package/app/components/workshop/town/TownScene.ts +466 -466
  489. package/app/components/workshop/town/TownView.vue +561 -561
  490. package/app/components/workshop/town/components/AutoModeConfirmModal.vue +94 -94
  491. package/app/components/workshop/town/components/TownAgentBindings.vue +405 -405
  492. package/app/components/workshop/town/components/TownAgentInspector.vue +554 -554
  493. package/app/components/workshop/town/components/TownAlarmList.vue +147 -147
  494. package/app/components/workshop/town/components/TownBoundaryPanel.vue +350 -350
  495. package/app/components/workshop/town/components/TownCalloutLayer.vue +147 -147
  496. package/app/components/workshop/town/components/TownChannelDock.vue +116 -116
  497. package/app/components/workshop/town/components/TownControlDock.vue +405 -405
  498. package/app/components/workshop/town/components/TownDaqNodeInspector.vue +345 -345
  499. package/app/components/workshop/town/components/TownDaqTree.vue +366 -366
  500. package/app/components/workshop/town/components/TownDcwBindSection.vue +473 -473
  501. package/app/components/workshop/town/components/TownDcwNodeInspector.vue +185 -185
  502. package/app/components/workshop/town/components/TownDcwTree.vue +280 -280
  503. package/app/components/workshop/town/components/TownDeviceBindings.vue +394 -394
  504. package/app/components/workshop/town/components/TownDeviceTransform.vue +248 -248
  505. package/app/components/workshop/town/components/TownEventList.vue +120 -120
  506. package/app/components/workshop/town/components/TownHealthBody.vue +100 -100
  507. package/app/components/workshop/town/components/TownKpiStrip.vue +207 -207
  508. package/app/components/workshop/town/components/TownLeftRail.vue +308 -308
  509. package/app/components/workshop/town/components/TownLoadingMask.vue +61 -61
  510. package/app/components/workshop/town/components/TownNavMap.vue +154 -154
  511. package/app/components/workshop/town/components/TownRightRail.vue +543 -543
  512. package/app/components/workshop/town/components/TownStage.vue +281 -281
  513. package/app/components/workshop/town/components/TownStageTop.vue +238 -238
  514. package/app/components/workshop/town/components/TownStatusBar.vue +108 -108
  515. package/app/components/workshop/town/components/TownTopNav.vue +367 -367
  516. package/app/components/workshop/town/components/TownTrendDock.vue +178 -178
  517. package/app/components/workshop/town/scene/town-scene-agents.ts +254 -254
  518. package/app/components/workshop/town/scene/town-scene-behavior.ts +194 -194
  519. package/app/components/workshop/town/scene/town-scene-bubbles.ts +96 -96
  520. package/app/components/workshop/town/scene/town-scene-core.ts +158 -158
  521. package/app/components/workshop/town/scene/town-scene-models.ts +109 -109
  522. package/app/components/workshop/town/scene/town-scene-visuals.ts +279 -279
  523. package/app/components/workshop/town/scene/town-scene3d-agents.ts +308 -308
  524. package/app/components/workshop/town/scene/town-scene3d-blocks.ts +297 -297
  525. package/app/components/workshop/town/scene/town-scene3d-bubbles.ts +281 -281
  526. package/app/components/workshop/town/scene/town-scene3d-camera.ts +282 -282
  527. package/app/components/workshop/town/scene/town-scene3d-devices.ts +433 -433
  528. package/app/components/workshop/town/scene/town-scene3d-editing.ts +490 -490
  529. package/app/components/workshop/town/scene/town-scene3d-events.ts +173 -173
  530. package/app/components/workshop/town/scene/town-scene3d-factory.ts +412 -412
  531. package/app/components/workshop/town/scene/town-scene3d-hud.ts +110 -110
  532. package/app/components/workshop/town/scene/town-scene3d-lifecycle.ts +144 -144
  533. package/app/components/workshop/town/scene/town-scene3d-links.ts +141 -141
  534. package/app/components/workshop/town/scene/town-scene3d-loop.ts +286 -286
  535. package/app/components/workshop/town/scene/town-scene3d-models.ts +154 -154
  536. package/app/components/workshop/town/scene/town-scene3d-nodes.ts +562 -562
  537. package/app/components/workshop/town/scene/town-scene3d-ranges.ts +273 -273
  538. package/app/components/workshop/town/scene/town-scene3d-renderer.ts +320 -320
  539. package/app/components/workshop/town/scene/town-scene3d-selection.ts +257 -257
  540. package/app/components/workshop/town/scene/town-scene3d-types.ts +264 -264
  541. package/app/components/workshop/transcript/TranscriptBlockList.vue +68 -68
  542. package/app/components/workshop/transcript/TranscriptEarlierPager.vue +81 -81
  543. package/app/components/workshop/transcript/TranscriptFilterBar.vue +126 -126
  544. package/app/components/workshop/workbench/CreateWorkspaceModal.vue +36 -36
  545. package/app/components/workshop/workbench/WorkspaceEmpty.vue +56 -56
  546. package/app/composables/useResponsive.ts +88 -88
  547. package/app/composables/workshop/device-twin-types.ts +29 -29
  548. package/app/composables/workshop/event-blocks/attention.ts +58 -58
  549. package/app/composables/workshop/event-blocks/classify.ts +44 -44
  550. package/app/composables/workshop/event-blocks/clusterer.ts +231 -231
  551. package/app/composables/workshop/event-blocks/fold-stream.ts +45 -45
  552. package/app/composables/workshop/event-blocks/markdown.ts +81 -81
  553. package/app/composables/workshop/event-blocks/mentions.ts +49 -49
  554. package/app/composables/workshop/event-blocks/text-utils.ts +100 -100
  555. package/app/composables/workshop/event-blocks/types.ts +40 -40
  556. package/app/composables/workshop/town/town-relay-props.ts +231 -231
  557. package/app/composables/workshop/town/town-view-types.ts +145 -145
  558. package/app/composables/workshop/town/useTownAgentBindings.ts +182 -182
  559. package/app/composables/workshop/town/useTownAgentChat.ts +203 -203
  560. package/app/composables/workshop/town/useTownAlarms.ts +36 -36
  561. package/app/composables/workshop/town/useTownCallouts.ts +174 -174
  562. package/app/composables/workshop/town/useTownChannels.ts +220 -220
  563. package/app/composables/workshop/town/useTownHealth.ts +66 -66
  564. package/app/composables/workshop/town/useTownHudTickers.ts +77 -77
  565. package/app/composables/workshop/town/useTownLayout.ts +277 -277
  566. package/app/composables/workshop/town/useTownNavMap.ts +301 -301
  567. package/app/composables/workshop/town/useTownNodeBindings.ts +345 -345
  568. package/app/composables/workshop/town/useTownPanelDrag.ts +91 -91
  569. package/app/composables/workshop/town/useTownRailData.ts +421 -421
  570. package/app/composables/workshop/town/useTownSceneControl.ts +92 -92
  571. package/app/composables/workshop/town/useTownSceneInput.ts +275 -275
  572. package/app/composables/workshop/town/useTownSceneRuntime.ts +390 -390
  573. package/app/composables/workshop/town/useTownSheets.ts +41 -41
  574. package/app/composables/workshop/town/useTownTrends.ts +93 -93
  575. package/app/composables/workshop/useChannelList.ts +88 -88
  576. package/app/composables/workshop/useChannelTerminals.ts +65 -65
  577. package/app/composables/workshop/useComposerMentions.ts +130 -130
  578. package/app/composables/workshop/useDcwStream.ts +374 -374
  579. package/app/composables/workshop/useDeviceTwinDcwWrite.ts +77 -77
  580. package/app/composables/workshop/useDeviceTwinPanel.ts +56 -56
  581. package/app/composables/workshop/useEscClose.ts +44 -44
  582. package/app/composables/workshop/useEventBlockView.ts +159 -159
  583. package/app/composables/workshop/useEventBlocks.ts +33 -33
  584. package/app/composables/workshop/useHitlAnswer.ts +184 -184
  585. package/app/composables/workshop/useLaneWidths.ts +27 -27
  586. package/app/composables/workshop/useOmpTerminalSession.ts +424 -424
  587. package/app/composables/workshop/usePluginAdmin.ts +152 -152
  588. package/app/composables/workshop/usePluginPanels.ts +72 -72
  589. package/app/composables/workshop/useRuntimeConfigDraft.ts +118 -118
  590. package/app/composables/workshop/useSettingsGroups.ts +243 -243
  591. package/app/composables/workshop/useTaskBoardColumns.ts +47 -47
  592. package/app/composables/workshop/useTerminalRenderer.ts +308 -308
  593. package/app/composables/workshop/useTranscriptEnterStage.ts +48 -48
  594. package/app/composables/workshop/useTranscriptHistory.ts +52 -52
  595. package/app/composables/workshop/useTranscriptScroll.ts +113 -113
  596. package/app/composables/workshop/useVisibleInterval.ts +42 -42
  597. package/app/composables/workshop/useWorkshopWs.ts +265 -265
  598. package/app/config/index.ts +1 -1
  599. package/app/middleware/locale-cookie.global.ts +22 -22
  600. package/app/pages/aml/api.ts +6 -6
  601. package/app/pages/aml/composables/useAmlDatasets.ts +38 -38
  602. package/app/pages/aml/composables/useAmlEntities.ts +57 -57
  603. package/app/pages/aml/composables/useAmlEnv.ts +191 -191
  604. package/app/pages/aml/composables/useAmlExperiments.ts +45 -45
  605. package/app/pages/aml/composables/useAmlFormat.ts +44 -44
  606. package/app/pages/aml/composables/useAmlJobs.ts +131 -131
  607. package/app/pages/aml/composables/useAmlModels.ts +56 -56
  608. package/app/pages/aml/composables/useAmlNotes.ts +47 -47
  609. package/app/pages/aml/composables/useAmlPredict.ts +93 -93
  610. package/app/pages/aml/constants.ts +63 -63
  611. package/app/pages/aml/index.vue +236 -236
  612. package/app/pages/composables/useDashboardCharts.ts +192 -192
  613. package/app/pages/composables/useDashboardData.ts +144 -144
  614. package/app/pages/daq/composables/useDaqAddNode.ts +126 -126
  615. package/app/pages/daq/composables/useDaqDetailBinding.ts +29 -29
  616. package/app/pages/daq/composables/useDaqDetailFrames.ts +42 -42
  617. package/app/pages/daq/composables/useDaqDetailNode.ts +53 -53
  618. package/app/pages/daq/composables/useDaqDetailParams.ts +138 -138
  619. package/app/pages/daq/composables/useDaqFilters.ts +187 -187
  620. package/app/pages/daq/composables/useDaqNodeWindow.ts +86 -86
  621. package/app/pages/daq/composables/useDaqOptimizations.ts +99 -99
  622. package/app/pages/daq/composables/useDaqTemplates.ts +152 -152
  623. package/app/pages/daq/index.vue +260 -260
  624. package/app/pages/dcw/composables/useDcwCards.ts +27 -27
  625. package/app/pages/dcw/composables/useDcwDetailScope.ts +145 -145
  626. package/app/pages/dcw/composables/useDcwDetailTemplates.ts +94 -94
  627. package/app/pages/dcw/composables/useDcwFilter.ts +29 -29
  628. package/app/pages/dcw/composables/useDcwLedger.ts +34 -34
  629. package/app/pages/dcw/composables/useDcwLineMutations.ts +115 -115
  630. package/app/pages/dcw/composables/useDcwLineRun.ts +60 -60
  631. package/app/pages/dcw/composables/useDcwProducts.ts +54 -54
  632. package/app/pages/dcw/composables/useDcwQuery.ts +68 -68
  633. package/app/pages/dcw/composables/useDcwQuickActions.ts +47 -47
  634. package/app/pages/dcw/composables/useDcwRecipes.ts +256 -256
  635. package/app/pages/dcw/composables/useDcwTemplates.ts +50 -50
  636. package/app/pages/dcw/index.vue +195 -195
  637. package/app/pages/dcw/types.ts +9 -9
  638. package/app/pages/index.vue +126 -126
  639. package/app/pages/logs/composables/useLogsFormat.ts +43 -43
  640. package/app/pages/logs/composables/useLogsScope.ts +39 -39
  641. package/app/pages/monitor/types.ts +61 -61
  642. package/app/pages/operations.vue +61 -61
  643. package/app/pages/permissions/index.vue +369 -369
  644. package/app/pages/tokens/composables/useTokenClipboard.ts +33 -33
  645. package/app/pages/tokens/composables/useTokenCreate.ts +93 -93
  646. package/app/pages/tokens/composables/useTokenRename.ts +54 -54
  647. package/app/pages/tokens/composables/useTokenReveal.ts +84 -84
  648. package/app/pages/tokens/composables/useTokensList.ts +60 -60
  649. package/app/pages/tokens.vue +111 -111
  650. package/app/pages/tools/index.vue +98 -98
  651. package/app/pages/workshop/agents.vue +130 -130
  652. package/app/pages/workshop/composables/useAgentHarnessOptions.ts +59 -59
  653. package/app/pages/workshop/composables/useAgentTemplateActions.ts +42 -42
  654. package/app/pages/workshop/composables/useAgentTemplateDialogState.ts +24 -24
  655. package/app/pages/workshop/composables/useAgentTemplateForm.ts +88 -88
  656. package/app/pages/workshop/composables/useAgentTemplatesCatalog.ts +92 -92
  657. package/app/pages/workshop/composables/useTeamActions.ts +44 -44
  658. package/app/pages/workshop/composables/useTeamAddMemberDialog.ts +49 -49
  659. package/app/pages/workshop/composables/useTeamCreateDialog.ts +67 -67
  660. package/app/pages/workshop/composables/useTeamDeployDialog.ts +49 -49
  661. package/app/pages/workshop/composables/useTeamDialogState.ts +46 -46
  662. package/app/pages/workshop/composables/useTeamPluginDialog.ts +72 -72
  663. package/app/pages/workshop/composables/useTeamsCatalog.ts +100 -100
  664. package/app/pages/workshop/composables/useWorkbenchWorkspaces.ts +123 -123
  665. package/app/pages/workshop/composables/useWorkspaceAuth.ts +31 -31
  666. package/app/pages/workshop/composables/useWorkspaceChannels.ts +62 -62
  667. package/app/pages/workshop/composables/useWorkspaceShell.ts +136 -136
  668. package/app/pages/workshop/schedules.vue +553 -553
  669. package/app/pages/workshop/w/[wsId].vue +221 -221
  670. package/app/plugins/aw-plugins.client.ts +213 -213
  671. package/app/plugins/esc-close.client.ts +31 -31
  672. package/app/stores/workshop/hitl.ts +183 -183
  673. package/app/stores/workshop/narrow-fetch.ts +23 -23
  674. package/app/utils/api-error.ts +75 -75
  675. package/app/utils/builtin-catalog.ts +104 -104
  676. package/app/utils/chart-trend.ts +97 -97
  677. package/app/utils/dcw-driver-badge.ts +16 -16
  678. package/app/utils/dcw-recipe-form.ts +26 -26
  679. package/cli/commands/tui.mjs +28 -28
  680. package/cli/commands/update.mjs +124 -124
  681. package/cli/core/child-lifecycle.mjs +136 -136
  682. package/cli/core/meta.mjs +38 -38
  683. package/cli/core/post-build.mjs +96 -96
  684. package/config.yml +1 -1
  685. package/docs/cli.en.md +2 -2
  686. package/docs/cli.md +2 -2
  687. package/docs/mcp.en.md +27 -27
  688. package/docs/multi-harness-architecture.md +248 -248
  689. package/docs/plugins.en.md +1 -1
  690. package/docs/plugins.md +1 -1
  691. package/docs/sdk.en.md +1 -1
  692. package/docs/sdk.md +1 -1
  693. package/docs/tui.md +43 -43
  694. package/i18n/dicts/_en.json +1551 -1551
  695. package/i18n/dicts/_en2.json +300 -300
  696. package/i18n/dicts/_en4.json +114 -114
  697. package/i18n/dicts/agentLanesView.json +61 -61
  698. package/i18n/dicts/appHeader.json +17 -17
  699. package/i18n/dicts/channelSessionList.json +51 -51
  700. package/i18n/dicts/chat.json +79 -79
  701. package/i18n/dicts/clusterTool.json +4 -4
  702. package/i18n/dicts/composer.json +38 -38
  703. package/i18n/dicts/ctpl.json +37 -37
  704. package/i18n/dicts/dcwDetail.json +219 -219
  705. package/i18n/dicts/lineOps.json +14 -14
  706. package/i18n/dicts/multiChannelView.json +13 -13
  707. package/i18n/dicts/notifications.json +13 -13
  708. package/i18n/dicts/taskInspectorDrawer.json +25 -25
  709. package/i18n/dicts/teamPlugins.json +10 -10
  710. package/i18n/dicts/townView.json +209 -209
  711. package/mcp/discovery.mjs +227 -227
  712. package/package.json +1 -1
  713. package/public/favicon.svg +14 -14
  714. package/public/robots.txt +3 -3
  715. package/scripts/_audit/audit-harness-adapters.md +664 -664
  716. package/scripts/_audit/aw-mcp-live-e2e.mjs +293 -293
  717. package/scripts/_audit/bump-version.mjs +51 -51
  718. package/scripts/_audit/detached-instance.mjs +112 -112
  719. package/scripts/_audit/detached-start.mjs +103 -103
  720. package/scripts/_audit/eda-ui-fix-acceptance.mjs +212 -212
  721. package/scripts/_audit/guard-upstream-liveness.mjs +104 -104
  722. package/scripts/_audit/http-api-authz-audit.md +657 -657
  723. package/scripts/_audit/kb-team-mock-e2e.mjs +146 -146
  724. package/scripts/_audit/kb-team-omp-e2e.mjs +229 -229
  725. package/scripts/_audit/run.mjs +21 -21
  726. package/scripts/_audit/runtime-audit.md +716 -716
  727. package/scripts/_audit/skills-guided-e2e.mjs +316 -316
  728. package/scripts/_audit/stability-soak.mjs +252 -252
  729. package/scripts/_audit/stubs/nuxt-imports.mjs +67 -67
  730. package/scripts/_audit/ts-register-hook.mjs +12 -12
  731. package/scripts/_audit/ts-resolve-hook.mjs +96 -96
  732. package/scripts/_aw-packaged-start.cjs +22 -22
  733. package/scripts/_aw0746-stage12.mjs +94 -94
  734. package/scripts/_aw0746-stage34.mjs +136 -136
  735. package/scripts/_aw0746-stage6b-train-sweep.mjs +145 -145
  736. package/scripts/_aw0746-stage6c-jobsmoke.mjs +69 -69
  737. package/scripts/_dbg-configroot-audit.mjs +86 -86
  738. package/scripts/_dbg-daq-intervals-func.mjs +115 -115
  739. package/scripts/_dbg-perms-e2e.mjs +142 -142
  740. package/scripts/_dbg-protocol-matrix.mjs +462 -462
  741. package/scripts/_dbg-render-regression.mjs +193 -193
  742. package/scripts/_dbg-schedule-e2e.mjs +262 -262
  743. package/scripts/_e2e-ui-functional.mjs +371 -371
  744. package/scripts/_i18n-en-cjk-scan.mjs +28 -28
  745. package/scripts/_i18n-en-verify.mjs +107 -107
  746. package/scripts/_i18n-extra-checks.mjs +53 -53
  747. package/scripts/_i18n-scan-hardcoded.mjs +180 -180
  748. package/scripts/_lib-aml-python-run.mjs +17 -17
  749. package/scripts/_lint-reflow.mjs +105 -105
  750. package/scripts/_loop-biax-campaign.mjs +130 -130
  751. package/scripts/_plc-sim-detached.cjs +22 -22
  752. package/scripts/_probe-daq-omp-task.mjs +100 -100
  753. package/scripts/_probe-daq-scope-default.mjs +123 -123
  754. package/scripts/_probe-model-channel-link.cjs +25 -25
  755. package/scripts/_probe-recipe-switch.mjs +92 -92
  756. package/scripts/_provision-injection-line.mjs +39 -39
  757. package/scripts/_run-matrix.ps1 +53 -53
  758. package/scripts/_sweep-button-contrast.mjs +87 -87
  759. package/scripts/acceptance-aml-hybrid-e2e.ts +396 -396
  760. package/scripts/acceptance-aml-hybrid-live.mjs +93 -93
  761. package/scripts/acceptance-aml-model-identity.ts +137 -137
  762. package/scripts/agent-daq-isolation-e2e.mjs +91 -91
  763. package/scripts/api-contract-smoke.mjs +126 -126
  764. package/scripts/ask-hitl-e2e.mjs +96 -96
  765. package/scripts/aw-expose.mjs +159 -159
  766. package/scripts/channel-interaction-smoke.mjs +80 -80
  767. package/scripts/data-studio-ui-e2e.mjs +163 -163
  768. package/scripts/demo-group-chat-all-real.ts +279 -279
  769. package/scripts/demo-group-chat-omp-cases.ts +210 -210
  770. package/scripts/demo-group-chat-omp.ts +184 -184
  771. package/scripts/demo-group-chat-order.ts +197 -197
  772. package/scripts/dev-modbus-simulator.mjs +55 -55
  773. package/scripts/docs-shots.mjs +36 -36
  774. package/scripts/e2e-agentteam-chat.mjs +473 -473
  775. package/scripts/e2e-agentteam-real-triage.mjs +421 -421
  776. package/scripts/e2e-aml-decoupled.mjs +162 -162
  777. package/scripts/e2e-aw-tui-global.mjs +277 -277
  778. package/scripts/e2e-closedloop/cleanup.mjs +27 -27
  779. package/scripts/e2e-closedloop/lib.mjs +109 -109
  780. package/scripts/e2e-closedloop/main.mjs +59 -59
  781. package/scripts/e2e-closedloop/scenarios-accounts.mjs +210 -210
  782. package/scripts/e2e-closedloop/scenarios-authz.mjs +196 -196
  783. package/scripts/e2e-closedloop/scenarios-daq-dcw.mjs +222 -222
  784. package/scripts/e2e-closedloop/scenarios-plugins.mjs +169 -169
  785. package/scripts/e2e-closedloop/state.mjs +10 -10
  786. package/scripts/e2e-config-groups.mjs +238 -238
  787. package/scripts/e2e-crash-cycle.mjs +108 -108
  788. package/scripts/e2e-full-closedloop.mjs +16 -16
  789. package/scripts/e2e-hil-multi-user.mjs +307 -307
  790. package/scripts/e2e-hil-restart.mjs +339 -339
  791. package/scripts/e2e-idd-results-ui.mjs +175 -0
  792. package/scripts/e2e-idd-results.mjs +48 -16
  793. package/scripts/e2e-injection-recipe-closedloop.mjs +203 -203
  794. package/scripts/e2e-line-governance.mjs +352 -352
  795. package/scripts/e2e-ontology.mjs +393 -393
  796. package/scripts/e2e-plc-plugin-closedloop.mjs +549 -549
  797. package/scripts/e2e-timezone-settings.mjs +57 -57
  798. package/scripts/full-stack-shots.mjs +145 -145
  799. package/scripts/full-tool-injection-harness-e2e.mjs +214 -214
  800. package/scripts/hitl-reject-e2e.mjs +131 -131
  801. package/scripts/line-log-smoke.mjs +260 -260
  802. package/scripts/live-aml-mockomp.mjs +304 -304
  803. package/scripts/live-aml-optloop-resume.mjs +322 -322
  804. package/scripts/live-aml-optloop.mjs +588 -588
  805. package/scripts/live-aml-stage9.mjs +169 -169
  806. package/scripts/live-aml-two-goals.mjs +315 -315
  807. package/scripts/live-optloop-two-modes.mjs +857 -857
  808. package/scripts/mes-agent-integration-e2e.mjs +361 -361
  809. package/scripts/ops-plugins-e2e.mjs +85 -85
  810. package/scripts/proof-omp-real.ts +189 -189
  811. package/scripts/scenario-suite-setup.mjs +337 -337
  812. package/scripts/scenario-suite-stability.mjs +144 -144
  813. package/scripts/smoke-optimization-verify.ts +72 -72
  814. package/scripts/team-coordination-e2e.mjs +96 -96
  815. package/scripts/test-agentteam-task-chat-flow.ts +420 -420
  816. package/scripts/test-agentteam-workflow.ts +472 -472
  817. package/scripts/test-aw-skills.mjs +102 -102
  818. package/scripts/test-cli-exit.mjs +343 -343
  819. package/scripts/test-daq-frame-race.mjs +358 -358
  820. package/scripts/test-data-root.mjs +208 -208
  821. package/scripts/test-events-index.mjs +176 -176
  822. package/scripts/test-group-chat-hardening.ts +265 -265
  823. package/scripts/test-group-chat-unit/lib.ts +186 -186
  824. package/scripts/test-group-chat-unit/main.ts +45 -45
  825. package/scripts/test-group-chat-unit/section-a-migration.ts +75 -75
  826. package/scripts/test-group-chat-unit/section-b-permission-matrix.ts +88 -88
  827. package/scripts/test-group-chat-unit/section-c-member-lifecycle.ts +64 -64
  828. package/scripts/test-group-chat-unit/section-d-mention-resolution.ts +36 -36
  829. package/scripts/test-group-chat-unit/section-e-chat-facts.ts +97 -97
  830. package/scripts/test-group-chat-unit/section-f-user-notifications.ts +52 -52
  831. package/scripts/test-group-chat-unit/section-g-member-projection.ts +44 -44
  832. package/scripts/test-group-chat-unit/section-h-outbox-consistency.ts +30 -30
  833. package/scripts/test-group-chat-unit/section-i-read-idempotency.ts +24 -24
  834. package/scripts/test-group-chat-unit/section-j-permission-scope.ts +150 -150
  835. package/scripts/test-group-chat-unit.ts +35 -35
  836. package/scripts/test-hitl-decision.ts +526 -526
  837. package/scripts/test-hitl-legacy-channel-auth.ts +143 -143
  838. package/scripts/test-hitl-registry.ts +112 -112
  839. package/scripts/test-log-flooding.mjs +160 -160
  840. package/scripts/test-lru.mjs +101 -101
  841. package/scripts/test-memory-month-query.mjs +70 -70
  842. package/scripts/test-plugin-hardening.mjs +90 -90
  843. package/scripts/test-plugin-lifecycle.mjs +173 -173
  844. package/scripts/test-rollback-index.mjs +137 -137
  845. package/scripts/test-schedule-runtime.ts +309 -309
  846. package/scripts/test-scheduler-loop/scenarios-supervise.ts +25 -25
  847. package/scripts/test-sdk-surface.mjs +158 -158
  848. package/scripts/test-serial-bridge.mjs +418 -418
  849. package/scripts/test-tui-commands.mjs +148 -148
  850. package/scripts/test-tui-reducers.mjs +72 -72
  851. package/scripts/three-system-e2e/lib.mjs +79 -79
  852. package/scripts/three-system-e2e/main.mjs +40 -40
  853. package/scripts/three-system-e2e/phases/phase-0-user-token.mjs +42 -42
  854. package/scripts/three-system-e2e/phases/phase-0a2-line-autoselect.mjs +35 -35
  855. package/scripts/three-system-e2e/phases/phase-0b-fixture-grants.mjs +39 -39
  856. package/scripts/three-system-e2e/phases/phase-0c-plugin-outbound-auth.mjs +95 -95
  857. package/scripts/three-system-e2e/phases/stage-1-health.mjs +47 -47
  858. package/scripts/three-system-e2e/phases/stage-2-5-team-plugins.mjs +84 -84
  859. package/scripts/three-system-e2e/phases/stage-2-teams-tools-hitl.mjs +184 -184
  860. package/scripts/three-system-e2e/phases/stage-3-diag.mjs +73 -73
  861. package/scripts/three-system-e2e/phases/stage-4-plugin-toggle.mjs +53 -53
  862. package/scripts/three-system-e2e/state.mjs +87 -87
  863. package/scripts/three-system-e2e.mjs +40 -40
  864. package/scripts/tool-face-batch-identity-e2e.mjs +222 -222
  865. package/scripts/tsconfig.json +14 -14
  866. package/scripts/tui-smoke.mjs +100 -100
  867. package/scripts/typecheck.mjs +75 -75
  868. package/scripts/ui/admin-shots.mjs +46 -46
  869. package/scripts/ui/bump-microfont.mjs +39 -39
  870. package/scripts/ui/linkcheck2.mjs +37 -37
  871. package/scripts/ui/live-render-check.mjs +72 -72
  872. package/scripts/ui/md-lint.mjs +80 -80
  873. package/scripts/ui/perf-audit.mjs +132 -132
  874. package/scripts/ui/readme-assets.mjs +30 -30
  875. package/scripts/ui/readme-shots.mjs +42 -42
  876. package/scripts/ui/record-demo.mjs +557 -557
  877. package/scripts/ui/record.mjs +225 -225
  878. package/scripts/ui/seed-admin.mjs +68 -68
  879. package/scripts/ui/seed-demo.mjs +83 -83
  880. package/scripts/ui/seed-industrial-demo.mjs +171 -171
  881. package/scripts/ui/shot-hero.mjs +25 -25
  882. package/scripts/ui/shots.mjs +75 -75
  883. package/scripts/ui/sim-ui-shot.mjs +16 -16
  884. package/scripts/ui/smoke-refactor.mjs +258 -258
  885. package/scripts/ui/verify-nav.mjs +51 -51
  886. package/scripts/ui/verify-responsive.mjs +285 -285
  887. package/sdk/client.d.mts +110 -110
  888. package/sdk/examples/line-sentinel/index.mjs +105 -105
  889. package/sdk/examples/ops-notifier/index.mjs +34 -34
  890. package/sdk/examples/sample-insight/index.mjs +39 -39
  891. package/server/api/plugins/[name]/[...path].ts +5 -1
  892. package/server/api/plugins/client/[name].get.ts +18 -18
  893. package/server/api/plugins/i18n.get.ts +12 -12
  894. package/server/api/plugins/manifest.get.ts +10 -10
  895. package/server/api/system/backup/list.get.ts +32 -32
  896. package/server/api/system/backup/run.post.ts +21 -21
  897. package/server/api/system/config-groups/[id].delete.ts +21 -21
  898. package/server/api/system/config-groups/[id].patch.ts +26 -26
  899. package/server/api/system/config-groups/index.get.ts +21 -21
  900. package/server/api/system/config-groups/index.post.ts +33 -33
  901. package/server/api/system/timezone.get.ts +20 -20
  902. package/server/api/users/tokens/[id]/token.get.ts +11 -11
  903. package/server/api/workshop/[...path].ts +13 -13
  904. package/server/api/workshop/agent-tools/approvals/index.get.ts +43 -43
  905. package/server/api/workshop/agent-tools/bindings/[id].delete.ts +26 -26
  906. package/server/api/workshop/agent-tools/bindings/grant.post.ts +45 -45
  907. package/server/api/workshop/agent-tools/bindings/index.get.ts +41 -41
  908. package/server/api/workshop/agent-tools/bindings/revoke.post.ts +42 -42
  909. package/server/api/workshop/aml/datasets/[id]/preview.get.ts +68 -68
  910. package/server/api/workshop/aml/datasets/[id].delete.ts +39 -39
  911. package/server/api/workshop/aml/datasets/[id].get.ts +53 -53
  912. package/server/api/workshop/aml/datasets/[id].patch.ts +30 -30
  913. package/server/api/workshop/aml/datasets/index.get.ts +20 -20
  914. package/server/api/workshop/aml/datasets/index.post.ts +27 -27
  915. package/server/api/workshop/aml/entities/index.get.ts +13 -13
  916. package/server/api/workshop/aml/entities/prune.post.ts +28 -28
  917. package/server/api/workshop/aml/env/index.get.ts +13 -13
  918. package/server/api/workshop/aml/env/recheck.post.ts +14 -14
  919. package/server/api/workshop/aml/env/uv.post.ts +21 -21
  920. package/server/api/workshop/aml/env/venv.post.ts +24 -24
  921. package/server/api/workshop/aml/experiments/index.get.ts +35 -35
  922. package/server/api/workshop/aml/index.get.ts +37 -37
  923. package/server/api/workshop/aml/jobs/[id]/cancel.post.ts +21 -21
  924. package/server/api/workshop/aml/jobs/[id]/logs.get.ts +23 -23
  925. package/server/api/workshop/aml/jobs/[id]/retry.post.ts +20 -20
  926. package/server/api/workshop/aml/jobs/[id].delete.ts +44 -44
  927. package/server/api/workshop/aml/jobs/[id].get.ts +23 -23
  928. package/server/api/workshop/aml/jobs/index.get.ts +26 -26
  929. package/server/api/workshop/aml/models/[id]/predict.post.ts +24 -24
  930. package/server/api/workshop/aml/models/[id]/promote.post.ts +30 -30
  931. package/server/api/workshop/aml/models/index.get.ts +48 -48
  932. package/server/api/workshop/aml/training-plans/[id]/train.post.ts +18 -18
  933. package/server/api/workshop/aml/training-plans/[id].delete.ts +18 -18
  934. package/server/api/workshop/aml/training-plans/[id].patch.ts +30 -30
  935. package/server/api/workshop/aml/training-plans/index.get.ts +9 -9
  936. package/server/api/workshop/aml/training-plans/index.post.ts +43 -43
  937. package/server/api/workshop/approvals/[id]/decide.post.ts +30 -30
  938. package/server/api/workshop/approvals/index.get.ts +22 -22
  939. package/server/api/workshop/audit.get.ts +43 -43
  940. package/server/api/workshop/channels/[id]/chat/messages/[messageId]/read.post.ts +22 -22
  941. package/server/api/workshop/channels/[id]/chat/messages/index.get.ts +29 -29
  942. package/server/api/workshop/channels/[id]/chat/messages/index.post.ts +51 -51
  943. package/server/api/workshop/channels/[id]/chat/permissions.get.ts +35 -35
  944. package/server/api/workshop/channels/[id]/index.patch.ts +64 -64
  945. package/server/api/workshop/channels/[id]/members/[userId]/approve.post.ts +20 -20
  946. package/server/api/workshop/channels/[id]/members/[userId].delete.ts +21 -21
  947. package/server/api/workshop/channels/[id]/members/index.get.ts +23 -23
  948. package/server/api/workshop/channels/[id]/members/leave.post.ts +20 -20
  949. package/server/api/workshop/channels/[id]/twin-profile.get.ts +45 -45
  950. package/server/api/workshop/channels/[id]/twin-profile.patch.ts +72 -72
  951. package/server/api/workshop/daq/[id]/test.post.ts +1 -1
  952. package/server/api/workshop/daq/alarms.get.ts +16 -16
  953. package/server/api/workshop/dcw/[id]/write.post.ts +4 -4
  954. package/server/api/workshop/dcw/[id].delete.ts +41 -41
  955. package/server/api/workshop/dcw/[id].patch.ts +40 -40
  956. package/server/api/workshop/dcw/mes-test-read.post.ts +24 -24
  957. package/server/api/workshop/dcw/params/[id]/read.post.ts +17 -17
  958. package/server/api/workshop/dcw/params/[id]/write.post.ts +21 -21
  959. package/server/api/workshop/dcw/params/[id].delete.ts +19 -19
  960. package/server/api/workshop/dcw/params/[id].patch.ts +23 -23
  961. package/server/api/workshop/dcw/params/index.get.ts +27 -27
  962. package/server/api/workshop/dcw/params/index.post.ts +25 -25
  963. package/server/api/workshop/dcw/products/[id].delete.ts +16 -16
  964. package/server/api/workshop/dcw/products/[id].patch.ts +17 -17
  965. package/server/api/workshop/dcw/recipes/[id]/index.patch.ts +22 -22
  966. package/server/api/workshop/dcw/recipes/[id]/versions.get.ts +14 -14
  967. package/server/api/workshop/dcw/recipes/[id].delete.ts +25 -25
  968. package/server/api/workshop/dcw/recipes/index.get.ts +12 -12
  969. package/server/api/workshop/dcw/runs/[id]/close.post.ts +15 -15
  970. package/server/api/workshop/dcw/templates/[key].delete.ts +14 -14
  971. package/server/api/workshop/dcw/templates/[key].patch.ts +16 -16
  972. package/server/api/workshop/dcw/templates/index.post.ts +15 -15
  973. package/server/api/workshop/dcw/test-driver.post.ts +16 -16
  974. package/server/api/workshop/device-twins/[id].delete.ts +25 -25
  975. package/server/api/workshop/eda/runs/[id]/labels.patch.ts +25 -25
  976. package/server/api/workshop/exp/confirmations/[id]/decide.post.ts +41 -41
  977. package/server/api/workshop/exp/confirmations/index.get.ts +25 -25
  978. package/server/api/workshop/harnesses/[id]/providers.get.ts +16 -16
  979. package/server/api/workshop/hitl/respond.post.ts +94 -94
  980. package/server/api/workshop/notifications/index.get.ts +60 -60
  981. package/server/api/workshop/notifications/read.post.ts +31 -31
  982. package/server/api/workshop/ontology/drafts/[draftId]/subgraph.ts +24 -24
  983. package/server/api/workshop/plugins/[name]/disable.post.ts +21 -21
  984. package/server/api/workshop/plugins/[name]/enable.post.ts +21 -21
  985. package/server/api/workshop/plugins/[name]/index.get.ts +14 -14
  986. package/server/api/workshop/schedules/[id]/run.post.ts +15 -15
  987. package/server/api/workshop/schedules/[id]/runs.get.ts +15 -15
  988. package/server/api/workshop/schedules/[id].delete.ts +14 -14
  989. package/server/api/workshop/schedules/[id].get.ts +13 -13
  990. package/server/api/workshop/schedules/[id].patch.ts +29 -29
  991. package/server/api/workshop/schedules/index.get.ts +12 -12
  992. package/server/api/workshop/schedules/index.post.ts +32 -32
  993. package/server/api/workshop/tasks/[id]/reassign.post.ts +32 -32
  994. package/server/api/workshop/tasks/[id]/update.post.ts +35 -35
  995. package/server/api/workshop/teams/[id]/plugins/index.get.ts +36 -36
  996. package/server/api/workshop/teams/[id]/plugins/index.put.ts +42 -42
  997. package/server/api/workshop/ws/audience.ts +56 -56
  998. package/server/api/workshop/ws/db-buffer.ts +68 -68
  999. package/server/api/workshop/ws/event-mapping.ts +47 -47
  1000. package/server/api/workshop/ws/handlers.ts +132 -132
  1001. package/server/api/workshop/ws/hub.ts +133 -133
  1002. package/server/api/workshop/ws/index.ts +23 -23
  1003. package/server/api/workshop/ws/notification-uplink.ts +77 -77
  1004. package/server/api/workshop/ws/shared.ts +94 -94
  1005. package/server/api/workshop/ws/streams.ts +146 -146
  1006. package/server/middleware/00-security-headers.ts +38 -38
  1007. package/server/middleware/01-rate-guard.ts +101 -101
  1008. package/server/plugins/aml-twin-worker.ts +32 -32
  1009. package/server/plugins/dev-stability-guard.ts +42 -42
  1010. package/server/plugins-builtin/diag-bridge/client.mjs +32 -12
  1011. package/server/plugins-builtin/diag-bridge/host/constants.mjs +25 -25
  1012. package/server/plugins-builtin/diag-bridge/host/exports.mjs +104 -104
  1013. package/server/plugins-builtin/diag-bridge/host/helpers.mjs +39 -9
  1014. package/server/plugins-builtin/diag-bridge/host/index.mjs +15 -15
  1015. package/server/plugins-builtin/diag-bridge/host/intents.mjs +62 -62
  1016. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +60 -26
  1017. package/server/plugins-builtin/diag-bridge/host/snapshot.mjs +93 -93
  1018. package/server/plugins-builtin/diag-bridge/index.mjs +9 -9
  1019. package/server/plugins-builtin/serial-bridge/client.mjs +211 -211
  1020. package/server/plugins-builtin/serial-bridge/drivers.mjs +409 -409
  1021. package/server/plugins-builtin/serial-bridge/i18n.json +62 -62
  1022. package/server/plugins-builtin/serial-bridge/index.mjs +247 -247
  1023. package/server/plugins-builtin/serial-bridge/lib.mjs +208 -208
  1024. package/server/plugins-builtin/serial-bridge/rtu.mjs +168 -168
  1025. package/server/services/system-config/contracts.ts +29 -29
  1026. package/server/services/system-config/dispose.ts +19 -19
  1027. package/server/services/system-config/facade.ts +26 -26
  1028. package/server/services/system-config/groups.ts +108 -108
  1029. package/server/services/system-config/index.ts +21 -21
  1030. package/server/services/system-config/init.ts +26 -26
  1031. package/server/services/system-config/mutate.ts +103 -103
  1032. package/server/services/system-config/plugins.ts +104 -104
  1033. package/server/services/system-config/snapshot.ts +59 -59
  1034. package/server/services/system-config/state.ts +79 -79
  1035. package/server/services/system-config/types.ts +58 -58
  1036. package/server/services/workshop/agents/adapters/omp-rpc-client/api.ts +111 -111
  1037. package/server/services/workshop/agents/adapters/omp-rpc-client/contracts.ts +22 -22
  1038. package/server/services/workshop/agents/adapters/omp-rpc-client/facade.ts +7 -7
  1039. package/server/services/workshop/agents/adapters/omp-rpc-client/frames.ts +0 -18
  1040. package/server/services/workshop/agents/adapters/omp-rpc-client/helpers.ts +38 -38
  1041. package/server/services/workshop/agents/adapters/omp-rpc-client/index.ts +25 -25
  1042. package/server/services/workshop/agents/adapters/omp-rpc-client/start.ts +70 -70
  1043. package/server/services/workshop/agents/adapters/omp-rpc-client/state.ts +65 -65
  1044. package/server/services/workshop/agents/adapters/omp-rpc-client/stdout.ts +92 -92
  1045. package/server/services/workshop/agents/adapters/omp-rpc-client/usage.ts +47 -47
  1046. package/server/services/workshop/agents/agent-badge.ts +38 -38
  1047. package/server/services/workshop/agents/binding-authz.ts +60 -60
  1048. package/server/services/workshop/agents/binding-mode.ts +51 -51
  1049. package/server/services/workshop/agents/codex-agent/client.ts +170 -170
  1050. package/server/services/workshop/agents/codex-agent/core.ts +119 -119
  1051. package/server/services/workshop/agents/codex-agent/facade.ts +8 -8
  1052. package/server/services/workshop/agents/codex-agent/helpers.ts +13 -13
  1053. package/server/services/workshop/agents/codex-agent/hitl.ts +138 -138
  1054. package/server/services/workshop/agents/codex-agent/index.ts +14 -14
  1055. package/server/services/workshop/agents/codex-agent/turn.ts +367 -367
  1056. package/server/services/workshop/agents/codex-agent/types.ts +42 -42
  1057. package/server/services/workshop/agents/harness-process.ts +3 -3
  1058. package/server/services/workshop/agents/harness-terminal/api.ts +197 -197
  1059. package/server/services/workshop/agents/harness-terminal/index.ts +17 -17
  1060. package/server/services/workshop/agents/harness-terminal/io.ts +120 -120
  1061. package/server/services/workshop/agents/harness-terminal/park.ts +55 -55
  1062. package/server/services/workshop/agents/harness-terminal/sanitize.ts +98 -98
  1063. package/server/services/workshop/agents/harness-terminal/session.ts +124 -124
  1064. package/server/services/workshop/agents/harness-terminal/shared.ts +74 -74
  1065. package/server/services/workshop/agents/hitl-capabilities.ts +312 -312
  1066. package/server/services/workshop/agents/hitl-decision/answers.ts +32 -32
  1067. package/server/services/workshop/agents/hitl-decision/decide.ts +268 -268
  1068. package/server/services/workshop/agents/hitl-decision/payload.ts +45 -45
  1069. package/server/services/workshop/agents/hitl-decision/shared.ts +108 -108
  1070. package/server/services/workshop/agents/hitl-decision/visibility.ts +94 -94
  1071. package/server/services/workshop/agents/host-tool-bridge/tools/progress.ts +84 -84
  1072. package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +104 -104
  1073. package/server/services/workshop/agents/host-tool-bridge/tools/team.ts +70 -70
  1074. package/server/services/workshop/agents/industrial/aml-activity.ts +131 -131
  1075. package/server/services/workshop/agents/industrial/audit-query.ts +66 -66
  1076. package/server/services/workshop/agents/industrial/daq-tools.ts +352 -352
  1077. package/server/services/workshop/agents/industrial/exp-tools.ts +104 -104
  1078. package/server/services/workshop/agents/industrial/ops-tools.ts +16 -54
  1079. package/server/services/workshop/agents/industrial/param-tools.ts +69 -69
  1080. package/server/services/workshop/agents/industrial/recipe-gate.ts +6 -19
  1081. package/server/services/workshop/agents/industrial/recipe-propose-tools.ts +1 -1
  1082. package/server/services/workshop/agents/node-bindings.repo.ts +207 -207
  1083. package/server/services/workshop/agents/node-delegation.ts +159 -159
  1084. package/server/services/workshop/agents/omp-agent/core.ts +146 -146
  1085. package/server/services/workshop/agents/omp-agent/facade.ts +8 -8
  1086. package/server/services/workshop/agents/omp-agent/helpers.ts +37 -37
  1087. package/server/services/workshop/agents/omp-agent/index.ts +16 -16
  1088. package/server/services/workshop/agents/omp-agent/tools-steer.ts +1 -18
  1089. package/server/services/workshop/agents/omp-agent/types.ts +45 -45
  1090. package/server/services/workshop/agents/opencode-agent/core.ts +77 -77
  1091. package/server/services/workshop/agents/opencode-agent/facade.ts +8 -8
  1092. package/server/services/workshop/agents/opencode-agent/helpers.ts +29 -29
  1093. package/server/services/workshop/agents/opencode-agent/hitl.ts +113 -113
  1094. package/server/services/workshop/agents/opencode-agent/index.ts +16 -16
  1095. package/server/services/workshop/agents/opencode-agent/lifecycle.ts +44 -44
  1096. package/server/services/workshop/agents/opencode-agent/server.ts +244 -244
  1097. package/server/services/workshop/agents/opencode-agent/turn.ts +278 -278
  1098. package/server/services/workshop/agents/opencode-agent/types.ts +54 -54
  1099. package/server/services/workshop/agents/tool-classes.ts +44 -44
  1100. package/server/services/workshop/aml/clean.ts +120 -120
  1101. package/server/services/workshop/aml/entity.ts +367 -367
  1102. package/server/services/workshop/aml/job-orchestrator/broadcast.ts +37 -37
  1103. package/server/services/workshop/aml/job-orchestrator/control.ts +94 -94
  1104. package/server/services/workshop/aml/job-orchestrator/failure.ts +96 -96
  1105. package/server/services/workshop/aml/job-orchestrator/index.ts +22 -22
  1106. package/server/services/workshop/aml/job-orchestrator/process.ts +101 -101
  1107. package/server/services/workshop/aml/job-orchestrator/shared.ts +53 -53
  1108. package/server/services/workshop/aml/job-orchestrator/status.ts +20 -20
  1109. package/server/services/workshop/aml/job-orchestrator/tick.ts +37 -37
  1110. package/server/services/workshop/aml/python/train-example.py +92 -92
  1111. package/server/services/workshop/aml/runtime.ts +137 -137
  1112. package/server/services/workshop/aml/stats.ts +140 -140
  1113. package/server/services/workshop/aml/twin/calibration-worker.ts +150 -150
  1114. package/server/services/workshop/aml/twin/model-backed-provider.ts +332 -332
  1115. package/server/services/workshop/aml/twin/physics-spec-draft.ts +185 -185
  1116. package/server/services/workshop/aml/twin/prompt-composer.ts +143 -143
  1117. package/server/services/workshop/aml/twin/training-plans.ts +260 -260
  1118. package/server/services/workshop/aml/twin/write-guard.ts +19 -19
  1119. package/server/services/workshop/assets/character-asset.repo.ts +1 -1
  1120. package/server/services/workshop/assets/device-twin.repo.ts +1 -1
  1121. package/server/services/workshop/daq/bus/index.ts +5 -12
  1122. package/server/services/workshop/daq/daq-controller/contracts.ts +39 -39
  1123. package/server/services/workshop/daq/daq-controller/facade.ts +28 -28
  1124. package/server/services/workshop/daq/daq-controller/frames.ts +137 -137
  1125. package/server/services/workshop/daq/daq-controller/helpers.ts +52 -52
  1126. package/server/services/workshop/daq/daq-controller/index.ts +22 -22
  1127. package/server/services/workshop/daq/daq-controller/runtime-control.ts +72 -72
  1128. package/server/services/workshop/daq/daq-controller/sweep-alarms.ts +176 -176
  1129. package/server/services/workshop/daq/daq-controller/tsdb-twin.ts +138 -138
  1130. package/server/services/workshop/daq/drivers/http.ts +95 -95
  1131. package/server/services/workshop/daq/drivers/mock.ts +130 -130
  1132. package/server/services/workshop/daq/drivers/modbus-rtu.ts +67 -67
  1133. package/server/services/workshop/daq/drivers/modbus-tcp.ts +307 -307
  1134. package/server/services/workshop/daq/drivers/opcua.ts +227 -227
  1135. package/server/services/workshop/daq/drivers/s7-stub.ts +29 -29
  1136. package/server/services/workshop/daq/host-bindings.ts +71 -71
  1137. package/server/services/workshop/daq/host-ports.ts +65 -65
  1138. package/server/services/workshop/db/aml-team-seeds.ts +118 -118
  1139. package/server/services/workshop/db/backup-registry.ts +33 -33
  1140. package/server/services/workshop/db/channel-member.repo.ts +122 -122
  1141. package/server/services/workshop/db/channel.repo.ts +203 -203
  1142. package/server/services/workshop/db/chat-message.repo.ts +233 -233
  1143. package/server/services/workshop/db/database/index.ts +18 -18
  1144. package/server/services/workshop/db/database/json.ts +14 -14
  1145. package/server/services/workshop/db/database/open.ts +97 -97
  1146. package/server/services/workshop/db/database/seed-data.ts +60 -60
  1147. package/server/services/workshop/db/hitl-request.repo.ts +221 -221
  1148. package/server/services/workshop/db/notification.repo.ts +199 -199
  1149. package/server/services/workshop/db/readonly.ts +30 -30
  1150. package/server/services/workshop/db/scheduled-task.repo.ts +235 -235
  1151. package/server/services/workshop/db/transaction.ts +72 -72
  1152. package/server/services/workshop/dcw/dcw-controller/contracts.ts +16 -16
  1153. package/server/services/workshop/dcw/dcw-controller/control.ts +78 -78
  1154. package/server/services/workshop/dcw/dcw-controller/facade.ts +19 -19
  1155. package/server/services/workshop/dcw/dcw-controller/index.ts +22 -22
  1156. package/server/services/workshop/dcw/dcw-controller/params.ts +97 -97
  1157. package/server/services/workshop/dcw/dcw-controller/products.ts +103 -103
  1158. package/server/services/workshop/dcw/dcw-controller/write-audit.ts +49 -49
  1159. package/server/services/workshop/dcw/dcw-templates.ts +136 -136
  1160. package/server/services/workshop/dcw/param-conversion.ts +78 -78
  1161. package/server/services/workshop/dcw/param-map.repo.ts +349 -349
  1162. package/server/services/workshop/dcw/plugin-bridge.ts +45 -45
  1163. package/server/services/workshop/dcw/recipe-rollback-manager/contracts.ts +26 -26
  1164. package/server/services/workshop/dcw/recipe-rollback-manager/facade.ts +13 -13
  1165. package/server/services/workshop/dcw/recipe-rollback-manager/helpers.ts +30 -30
  1166. package/server/services/workshop/dcw/recipe-rollback-manager/index.ts +17 -17
  1167. package/server/services/workshop/dcw/recipe-rollback-manager/internal.ts +33 -33
  1168. package/server/services/workshop/dcw/recipe-rollback-manager/judge.ts +52 -52
  1169. package/server/services/workshop/dcw/recipe-rollback-manager/lock.ts +137 -137
  1170. package/server/services/workshop/dcw/recipe-rollback-manager/rollback.ts +190 -190
  1171. package/server/services/workshop/dcw/recipe-rollback-manager/state.ts +21 -21
  1172. package/server/services/workshop/dcw/recipe-rollback-manager/sweep.ts +77 -77
  1173. package/server/services/workshop/dcw/recipe-rollback-manager/types.ts +3 -3
  1174. package/server/services/workshop/dcw/recipe-rollback-manager/views.ts +214 -214
  1175. package/server/services/workshop/exp/exp-collector.ts +275 -275
  1176. package/server/services/workshop/exp/exp-state.repo.ts +339 -339
  1177. package/server/services/workshop/mes/mes-controller.ts +1155 -1155
  1178. package/server/services/workshop/mes/mes-hook.ts +567 -567
  1179. package/server/services/workshop/ontology/subgraph.core.ts +300 -300
  1180. package/server/services/workshop/ontology/subgraph.service.ts +113 -113
  1181. package/server/services/workshop/plugins/host/api.mjs +90 -90
  1182. package/server/services/workshop/plugins/host/config.mjs +135 -135
  1183. package/server/services/workshop/plugins/host/index.mjs +23 -23
  1184. package/server/services/workshop/plugins/host/init.mjs +109 -109
  1185. package/server/services/workshop/plugins/host/load.mjs +321 -321
  1186. package/server/services/workshop/plugins/host/reload.mjs +94 -94
  1187. package/server/services/workshop/plugins/host/rollback.mjs +72 -72
  1188. package/server/services/workshop/plugins/host/state.mjs +54 -54
  1189. package/server/services/workshop/plugins/host/toggle.mjs +64 -64
  1190. package/server/services/workshop/plugins/host.mjs +9 -9
  1191. package/server/services/workshop/runtime/agent-runtime/facade.ts +7 -7
  1192. package/server/services/workshop/runtime/agent-runtime/helpers.ts +18 -18
  1193. package/server/services/workshop/runtime/agent-runtime/index.ts +19 -19
  1194. package/server/services/workshop/runtime/agent-runtime/lifecycle.ts +137 -137
  1195. package/server/services/workshop/runtime/chat-mention.ts +164 -164
  1196. package/server/services/workshop/runtime/chat-projection.ts +246 -246
  1197. package/server/services/workshop/runtime/manager/admin-agents.ts +268 -268
  1198. package/server/services/workshop/runtime/manager/bus.ts +182 -182
  1199. package/server/services/workshop/runtime/manager/channel-template-constants.ts +20 -20
  1200. package/server/services/workshop/runtime/manager/chat-reply.ts +181 -181
  1201. package/server/services/workshop/runtime/manager/chat.ts +384 -384
  1202. package/server/services/workshop/runtime/manager/facade.ts +24 -24
  1203. package/server/services/workshop/runtime/manager/helpers.ts +119 -119
  1204. package/server/services/workshop/runtime/manager/index.ts +42 -42
  1205. package/server/services/workshop/runtime/manager/internal.ts +73 -73
  1206. package/server/services/workshop/runtime/manager/notifications.ts +108 -108
  1207. package/server/services/workshop/runtime/manager/teams.ts +148 -148
  1208. package/server/services/workshop/runtime/memory/contracts.ts +18 -18
  1209. package/server/services/workshop/runtime/memory/facade.ts +10 -10
  1210. package/server/services/workshop/runtime/memory/helpers.ts +196 -196
  1211. package/server/services/workshop/runtime/memory/index.ts +27 -27
  1212. package/server/services/workshop/runtime/memory/score.ts +33 -33
  1213. package/server/services/workshop/runtime/memory/state.ts +40 -40
  1214. package/server/services/workshop/runtime/monitor.ts +3 -3
  1215. package/server/services/workshop/runtime/platform-notice.ts +113 -113
  1216. package/server/services/workshop/runtime/schedule-runtime.ts +347 -347
  1217. package/server/services/workshop/runtime/scheduler-loop/contracts.ts +29 -29
  1218. package/server/services/workshop/runtime/scheduler-loop/facade.ts +7 -7
  1219. package/server/services/workshop/runtime/scheduler-loop/helpers.ts +14 -14
  1220. package/server/services/workshop/runtime/scheduler-loop/index.ts +16 -16
  1221. package/server/services/workshop/runtime/task-engine/facade.ts +7 -7
  1222. package/server/services/workshop/runtime/task-engine/index.ts +15 -15
  1223. package/server/services/workshop/runtime/task-engine/types.ts +3 -3
  1224. package/server/services/workshop/runtime/user-notification-hub.ts +192 -192
  1225. package/server/types/pg.d.ts +49 -49
  1226. package/server/utils/approval-gate.ts +67 -67
  1227. package/server/utils/mojibake-guard.ts +29 -29
  1228. package/server/utils/stability-severity.ts +77 -77
  1229. package/shared/config/groups.mjs +241 -241
  1230. package/shared/dcw-protocol/catalog.ts +232 -232
  1231. package/shared/dcw-protocol/closed-loop.ts +137 -137
  1232. package/shared/lru.mjs +97 -97
  1233. package/tui/README.md +74 -74
  1234. package/tui/aw-tui.mjs +445 -445
  1235. package/tui/commands/index.mjs +287 -287
  1236. package/tui/components/chat-log.mjs +42 -42
  1237. package/tui/components/monitor-pane.mjs +39 -39
  1238. package/tui/components/root.mjs +53 -53
  1239. package/tui/components/status-bar.mjs +33 -33
  1240. package/tui/lib/api.mjs +82 -82
  1241. package/tui/lib/pickers.mjs +121 -121
  1242. package/tui/lib/reducers.mjs +218 -218
  1243. package/tui/lib/state.mjs +86 -86
  1244. package/tui/lib/virtual-terminal.mjs +48 -48
  1245. package/tui/lib/ws.mjs +125 -125
  1246. package/tui/theme.mjs +38 -38
  1247. package/.output/.AgentWorkShop/aml-python/__pycache__/aml_eval.cpython-312.pyc +0 -0
  1248. package/.output/.AgentWorkShop/aml-python/__pycache__/amlkit.cpython-312.pyc +0 -0
  1249. package/.output/.AgentWorkShop/aml-python/__pycache__/train-example.cpython-312.pyc +0 -0
  1250. package/.output/.AgentWorkShop/aml-python/__pycache__/train-hybrid-example.cpython-312.pyc +0 -0
  1251. package/.output/public/_nuxt/BRYBzVMJ.js +0 -1
  1252. package/.output/public/_nuxt/BW2uTUx52.js +0 -2
  1253. package/.output/public/_nuxt/BtZKe9ZV.js +0 -1
  1254. package/.output/public/_nuxt/CfFUK6932.js +0 -2
  1255. package/.output/public/_nuxt/DhW7cFOa.js +0 -1
  1256. package/.output/public/_nuxt/OmpTerminalPanel.ComMDrA8.css +0 -1
  1257. package/.output/public/_nuxt/PluginSlot.CGH0vb95.css +0 -1
  1258. package/.output/public/_nuxt/TownView.CC3t-Dte.css +0 -1
  1259. package/.output/public/_nuxt/aml.PalMp-5n.css +0 -1
  1260. package/.output/public/_nuxt/builds/meta/fa0af8b5-3929-428d-a6de-3b5cc6b8248f.json +0 -1
  1261. package/.output/public/_nuxt/permissions.DxuOOIqQ.css +0 -1
  1262. package/.output/public/_nuxt/schedules.BXNJ9q_I.css +0 -1
  1263. package/.output/public/_nuxt/tools.BwXFAb-X.css +0 -1
  1264. package/.output/server/chunks/build/AuthGate-nF1evO4v.mjs +0 -716
  1265. package/.output/server/chunks/build/AuthGate-nF1evO4v.mjs.map +0 -1
  1266. package/.output/server/chunks/build/FormItemContext-BlyzocS0.mjs +0 -72
  1267. package/.output/server/chunks/build/FormItemContext-BlyzocS0.mjs.map +0 -1
  1268. package/.output/server/chunks/build/OmpTerminalPanel-BhvhQ1gG.mjs +0 -942
  1269. package/.output/server/chunks/build/OmpTerminalPanel-BhvhQ1gG.mjs.map +0 -1
  1270. package/.output/server/chunks/build/PluginSlot-BUKXwV2X.mjs +0 -141
  1271. package/.output/server/chunks/build/PluginSlot-BUKXwV2X.mjs.map +0 -1
  1272. package/.output/server/chunks/build/TownView-BWMDbosY.mjs +0 -6489
  1273. package/.output/server/chunks/build/TownView-BWMDbosY.mjs.map +0 -1
  1274. package/.output/server/chunks/build/_id_-BK-t8nRG.mjs +0 -392
  1275. package/.output/server/chunks/build/_id_-BK-t8nRG.mjs.map +0 -1
  1276. package/.output/server/chunks/build/_id_-CZPlPDm4.mjs +0 -2045
  1277. package/.output/server/chunks/build/_id_-CZPlPDm4.mjs.map +0 -1
  1278. package/.output/server/chunks/build/_wsId_-BPy-Aj9L.mjs +0 -14297
  1279. package/.output/server/chunks/build/_wsId_-BPy-Aj9L.mjs.map +0 -1
  1280. package/.output/server/chunks/build/agents-CpNLdI8E.mjs +0 -1078
  1281. package/.output/server/chunks/build/agents-CpNLdI8E.mjs.map +0 -1
  1282. package/.output/server/chunks/build/alert-D0ivtTGy.mjs +0 -263
  1283. package/.output/server/chunks/build/alert-D0ivtTGy.mjs.map +0 -1
  1284. package/.output/server/chunks/build/aml-DRAFRcGU.mjs +0 -814
  1285. package/.output/server/chunks/build/aml-DRAFRcGU.mjs.map +0 -1
  1286. package/.output/server/chunks/build/analysis-p-dBkjoK.mjs +0 -533
  1287. package/.output/server/chunks/build/analysis-p-dBkjoK.mjs.map +0 -1
  1288. package/.output/server/chunks/build/api-B4Om0mEc.mjs.map +0 -1
  1289. package/.output/server/chunks/build/api-BEW_ebY_.mjs.map +0 -1
  1290. package/.output/server/chunks/build/api-BsAgXWxi.mjs.map +0 -1
  1291. package/.output/server/chunks/build/api-error-BwAQLw44.mjs +0 -47
  1292. package/.output/server/chunks/build/api-error-BwAQLw44.mjs.map +0 -1
  1293. package/.output/server/chunks/build/apiClient-BvXtNzC8.mjs +0 -81
  1294. package/.output/server/chunks/build/apiClient-BvXtNzC8.mjs.map +0 -1
  1295. package/.output/server/chunks/build/board-Dl2Ar22r.mjs +0 -178
  1296. package/.output/server/chunks/build/board-Dl2Ar22r.mjs.map +0 -1
  1297. package/.output/server/chunks/build/card-Cqk0Ur-L.mjs +0 -953
  1298. package/.output/server/chunks/build/card-Cqk0Ur-L.mjs.map +0 -1
  1299. package/.output/server/chunks/build/channel-templates-ByHOQQkO.mjs +0 -942
  1300. package/.output/server/chunks/build/channel-templates-ByHOQQkO.mjs.map +0 -1
  1301. package/.output/server/chunks/build/checkbox-CrT4cnfu.mjs +0 -439
  1302. package/.output/server/chunks/build/checkbox-CrT4cnfu.mjs.map +0 -1
  1303. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs +0 -43
  1304. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs.map +0 -1
  1305. package/.output/server/chunks/build/core-CgTOPS4t.mjs +0 -294
  1306. package/.output/server/chunks/build/core-CgTOPS4t.mjs.map +0 -1
  1307. package/.output/server/chunks/build/daq-CdxcfY_G.mjs +0 -1266
  1308. package/.output/server/chunks/build/daq-CdxcfY_G.mjs.map +0 -1
  1309. package/.output/server/chunks/build/data-D8uX1dnm.mjs +0 -481
  1310. package/.output/server/chunks/build/data-D8uX1dnm.mjs.map +0 -1
  1311. package/.output/server/chunks/build/dcw-BlDQtS4q.mjs +0 -505
  1312. package/.output/server/chunks/build/dcw-BlDQtS4q.mjs.map +0 -1
  1313. package/.output/server/chunks/build/default-CNWS6NUw.mjs +0 -2353
  1314. package/.output/server/chunks/build/default-CNWS6NUw.mjs.map +0 -1
  1315. package/.output/server/chunks/build/descriptions-BNlfKG9y.mjs +0 -406
  1316. package/.output/server/chunks/build/descriptions-BNlfKG9y.mjs.map +0 -1
  1317. package/.output/server/chunks/build/drawer-Caji0PLs.mjs +0 -834
  1318. package/.output/server/chunks/build/drawer-Caji0PLs.mjs.map +0 -1
  1319. package/.output/server/chunks/build/dropdown-BNwTVGde.mjs +0 -14
  1320. package/.output/server/chunks/build/dropdown-BNwTVGde.mjs.map +0 -1
  1321. package/.output/server/chunks/build/dropdown-Cd-xPhR6.mjs +0 -540
  1322. package/.output/server/chunks/build/dropdown-Cd-xPhR6.mjs.map +0 -1
  1323. package/.output/server/chunks/build/es-Bxu10NJ2.mjs.map +0 -1
  1324. package/.output/server/chunks/build/firstNotUndefined-8H5_qHUu.mjs +0 -2448
  1325. package/.output/server/chunks/build/firstNotUndefined-8H5_qHUu.mjs.map +0 -1
  1326. package/.output/server/chunks/build/form-D_UpWPN4.mjs +0 -4712
  1327. package/.output/server/chunks/build/form-D_UpWPN4.mjs.map +0 -1
  1328. package/.output/server/chunks/build/hasIn-DBdElbjM.mjs +0 -553
  1329. package/.output/server/chunks/build/hasIn-DBdElbjM.mjs.map +0 -1
  1330. package/.output/server/chunks/build/hitl-Bd30yr1J.mjs +0 -132
  1331. package/.output/server/chunks/build/hitl-Bd30yr1J.mjs.map +0 -1
  1332. package/.output/server/chunks/build/input-GtPuSEgt.mjs +0 -2181
  1333. package/.output/server/chunks/build/input-GtPuSEgt.mjs.map +0 -1
  1334. package/.output/server/chunks/build/input-number-BNlNDK7H.mjs +0 -1120
  1335. package/.output/server/chunks/build/input-number-BNlNDK7H.mjs.map +0 -1
  1336. package/.output/server/chunks/build/interval-DvHBIIZh.mjs +0 -9
  1337. package/.output/server/chunks/build/interval-DvHBIIZh.mjs.map +0 -1
  1338. package/.output/server/chunks/build/isNumeric-CP7q_yhz.mjs +0 -7
  1339. package/.output/server/chunks/build/isNumeric-CP7q_yhz.mjs.map +0 -1
  1340. package/.output/server/chunks/build/logs-pRb-TMWa.mjs +0 -427
  1341. package/.output/server/chunks/build/logs-pRb-TMWa.mjs.map +0 -1
  1342. package/.output/server/chunks/build/menu-BXt-X0dt.mjs +0 -1952
  1343. package/.output/server/chunks/build/menu-BXt-X0dt.mjs.map +0 -1
  1344. package/.output/server/chunks/build/monitor-Cq6hRFeQ.mjs +0 -2253
  1345. package/.output/server/chunks/build/monitor-Cq6hRFeQ.mjs.map +0 -1
  1346. package/.output/server/chunks/build/ontology-DK0Mf0zT.mjs +0 -1406
  1347. package/.output/server/chunks/build/ontology-DK0Mf0zT.mjs.map +0 -1
  1348. package/.output/server/chunks/build/operations-SMQrRAcr.mjs +0 -311
  1349. package/.output/server/chunks/build/operations-SMQrRAcr.mjs.map +0 -1
  1350. package/.output/server/chunks/build/optimizer-BlWTsM-W.mjs +0 -202
  1351. package/.output/server/chunks/build/optimizer-BlWTsM-W.mjs.map +0 -1
  1352. package/.output/server/chunks/build/pages-AFRP4-EL.mjs +0 -542
  1353. package/.output/server/chunks/build/pages-AFRP4-EL.mjs.map +0 -1
  1354. package/.output/server/chunks/build/pagination-DTAconUo.mjs +0 -1346
  1355. package/.output/server/chunks/build/pagination-DTAconUo.mjs.map +0 -1
  1356. package/.output/server/chunks/build/permissions-DgXQZSyx.mjs +0 -637
  1357. package/.output/server/chunks/build/permissions-DgXQZSyx.mjs.map +0 -1
  1358. package/.output/server/chunks/build/plugins-LRjaSEZy.mjs +0 -272
  1359. package/.output/server/chunks/build/plugins-LRjaSEZy.mjs.map +0 -1
  1360. package/.output/server/chunks/build/popconfirm-DxYPGRgS.mjs +0 -340
  1361. package/.output/server/chunks/build/popconfirm-DxYPGRgS.mjs.map +0 -1
  1362. package/.output/server/chunks/build/responsiveObserve-DM3hpzhU.mjs +0 -78
  1363. package/.output/server/chunks/build/responsiveObserve-DM3hpzhU.mjs.map +0 -1
  1364. package/.output/server/chunks/build/schedules-dSnr8url.mjs +0 -7172
  1365. package/.output/server/chunks/build/schedules-dSnr8url.mjs.map +0 -1
  1366. package/.output/server/chunks/build/segmented-D3HWtHPw.mjs +0 -341
  1367. package/.output/server/chunks/build/segmented-D3HWtHPw.mjs.map +0 -1
  1368. package/.output/server/chunks/build/select-B3Dsb9yq.mjs +0 -3923
  1369. package/.output/server/chunks/build/select-B3Dsb9yq.mjs.map +0 -1
  1370. package/.output/server/chunks/build/settings-BrIhnS2Z.mjs +0 -1014
  1371. package/.output/server/chunks/build/settings-BrIhnS2Z.mjs.map +0 -1
  1372. package/.output/server/chunks/build/space-Dwu2Skt8.mjs +0 -110
  1373. package/.output/server/chunks/build/space-Dwu2Skt8.mjs.map +0 -1
  1374. package/.output/server/chunks/build/spin-C2cuvGth.mjs +0 -357
  1375. package/.output/server/chunks/build/spin-C2cuvGth.mjs.map +0 -1
  1376. package/.output/server/chunks/build/studio-cdoNCfyy.mjs +0 -332
  1377. package/.output/server/chunks/build/studio-cdoNCfyy.mjs.map +0 -1
  1378. package/.output/server/chunks/build/switch-CyR-H6Fb.mjs +0 -377
  1379. package/.output/server/chunks/build/switch-CyR-H6Fb.mjs.map +0 -1
  1380. package/.output/server/chunks/build/table-CmVD-cA9.mjs +0 -7546
  1381. package/.output/server/chunks/build/table-CmVD-cA9.mjs.map +0 -1
  1382. package/.output/server/chunks/build/tabs-Vg0e7cZE.mjs +0 -1924
  1383. package/.output/server/chunks/build/tabs-Vg0e7cZE.mjs.map +0 -1
  1384. package/.output/server/chunks/build/tag-y0sn-xv9.mjs +0 -1156
  1385. package/.output/server/chunks/build/tag-y0sn-xv9.mjs.map +0 -1
  1386. package/.output/server/chunks/build/teams-B1d32eHK.mjs +0 -1203
  1387. package/.output/server/chunks/build/teams-B1d32eHK.mjs.map +0 -1
  1388. package/.output/server/chunks/build/tokens-GYaGJ35Z.mjs +0 -1062
  1389. package/.output/server/chunks/build/tokens-GYaGJ35Z.mjs.map +0 -1
  1390. package/.output/server/chunks/build/tools-s_9U1Djj.mjs +0 -487
  1391. package/.output/server/chunks/build/tools-s_9U1Djj.mjs.map +0 -1
  1392. package/.output/server/chunks/build/tooltip-C2n2nNiQ.mjs +0 -920
  1393. package/.output/server/chunks/build/tooltip-C2n2nNiQ.mjs.map +0 -1
  1394. package/.output/server/chunks/build/town-B5aoiG98.mjs +0 -133
  1395. package/.output/server/chunks/build/town-B5aoiG98.mjs.map +0 -1
  1396. package/.output/server/chunks/build/useAgentHarnessOptions-DOrQHeBh.mjs +0 -124
  1397. package/.output/server/chunks/build/useAgentHarnessOptions-DOrQHeBh.mjs.map +0 -1
  1398. package/.output/server/chunks/build/useAgentTemplateActions-CzlplRWh.mjs +0 -77
  1399. package/.output/server/chunks/build/useAgentTemplateActions-CzlplRWh.mjs.map +0 -1
  1400. package/.output/server/chunks/build/useAgentTemplateForm-DQo1enf2.mjs +0 -117
  1401. package/.output/server/chunks/build/useAgentTemplateForm-DQo1enf2.mjs.map +0 -1
  1402. package/.output/server/chunks/build/useAgentTemplatesCatalog-DP-iMmqz.mjs +0 -133
  1403. package/.output/server/chunks/build/useAgentTemplatesCatalog-DP-iMmqz.mjs.map +0 -1
  1404. package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs +0 -92
  1405. package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs.map +0 -1
  1406. package/.output/server/chunks/build/useAmlEntities-BJhvdqHJ.mjs +0 -86
  1407. package/.output/server/chunks/build/useAmlEntities-BJhvdqHJ.mjs.map +0 -1
  1408. package/.output/server/chunks/build/useAmlEnv-CDIZ6xTe.mjs +0 -194
  1409. package/.output/server/chunks/build/useAmlEnv-CDIZ6xTe.mjs.map +0 -1
  1410. package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs +0 -89
  1411. package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs.map +0 -1
  1412. package/.output/server/chunks/build/useAmlJobs-BF9LpwXz.mjs +0 -267
  1413. package/.output/server/chunks/build/useAmlJobs-BF9LpwXz.mjs.map +0 -1
  1414. package/.output/server/chunks/build/useAmlModels-_bweOr3R.mjs +0 -93
  1415. package/.output/server/chunks/build/useAmlModels-_bweOr3R.mjs.map +0 -1
  1416. package/.output/server/chunks/build/useAmlNotes-DQj980iX.mjs +0 -86
  1417. package/.output/server/chunks/build/useAmlNotes-DQj980iX.mjs.map +0 -1
  1418. package/.output/server/chunks/build/useAmlPredict-DHNgDSJn.mjs +0 -130
  1419. package/.output/server/chunks/build/useAmlPredict-DHNgDSJn.mjs.map +0 -1
  1420. package/.output/server/chunks/build/useAnalysisFeed-BrEGV_9x.mjs +0 -129
  1421. package/.output/server/chunks/build/useAnalysisFeed-BrEGV_9x.mjs.map +0 -1
  1422. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs +0 -142
  1423. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs.map +0 -1
  1424. package/.output/server/chunks/build/useDaqDetailBinding-DCWaLKXT.mjs +0 -70
  1425. package/.output/server/chunks/build/useDaqDetailBinding-DCWaLKXT.mjs.map +0 -1
  1426. package/.output/server/chunks/build/useDaqDetailFrames-BOIcOJRB.mjs +0 -79
  1427. package/.output/server/chunks/build/useDaqDetailFrames-BOIcOJRB.mjs.map +0 -1
  1428. package/.output/server/chunks/build/useDaqDetailHistory-D6WulPVs.mjs +0 -176
  1429. package/.output/server/chunks/build/useDaqDetailHistory-D6WulPVs.mjs.map +0 -1
  1430. package/.output/server/chunks/build/useDaqDetailNode-DeOsDxK5.mjs +0 -99
  1431. package/.output/server/chunks/build/useDaqDetailNode-DeOsDxK5.mjs.map +0 -1
  1432. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs +0 -159
  1433. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs.map +0 -1
  1434. package/.output/server/chunks/build/useDaqFilters-CctmO03p.mjs +0 -222
  1435. package/.output/server/chunks/build/useDaqFilters-CctmO03p.mjs.map +0 -1
  1436. package/.output/server/chunks/build/useDaqOptimizations-CmX_dpBc.mjs +0 -136
  1437. package/.output/server/chunks/build/useDaqOptimizations-CmX_dpBc.mjs.map +0 -1
  1438. package/.output/server/chunks/build/useDaqStream-B9ZBVQrI.mjs +0 -395
  1439. package/.output/server/chunks/build/useDaqStream-B9ZBVQrI.mjs.map +0 -1
  1440. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs +0 -187
  1441. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs.map +0 -1
  1442. package/.output/server/chunks/build/useDashboardData-B36wVWo2.mjs +0 -153
  1443. package/.output/server/chunks/build/useDashboardData-B36wVWo2.mjs.map +0 -1
  1444. package/.output/server/chunks/build/useDcwAddNode-DACVcEHs.mjs +0 -219
  1445. package/.output/server/chunks/build/useDcwAddNode-DACVcEHs.mjs.map +0 -1
  1446. package/.output/server/chunks/build/useDcwCards-SaiImIYQ.mjs.map +0 -1
  1447. package/.output/server/chunks/build/useDcwDetailScope-DLOklSMO.mjs +0 -184
  1448. package/.output/server/chunks/build/useDcwDetailScope-DLOklSMO.mjs.map +0 -1
  1449. package/.output/server/chunks/build/useDcwDetailTemplates-ClmIdZ40.mjs +0 -148
  1450. package/.output/server/chunks/build/useDcwDetailTemplates-ClmIdZ40.mjs.map +0 -1
  1451. package/.output/server/chunks/build/useDcwFilter-CPMyCltx.mjs +0 -71
  1452. package/.output/server/chunks/build/useDcwFilter-CPMyCltx.mjs.map +0 -1
  1453. package/.output/server/chunks/build/useDcwLedger-0ie-0WTc.mjs.map +0 -1
  1454. package/.output/server/chunks/build/useDcwLineMutations-DNxo66yM.mjs +0 -137
  1455. package/.output/server/chunks/build/useDcwLineMutations-DNxo66yM.mjs.map +0 -1
  1456. package/.output/server/chunks/build/useDcwLineRun-CHskwscT.mjs +0 -104
  1457. package/.output/server/chunks/build/useDcwLineRun-CHskwscT.mjs.map +0 -1
  1458. package/.output/server/chunks/build/useDcwParamApprovals-DtScUc-W.mjs +0 -121
  1459. package/.output/server/chunks/build/useDcwParamApprovals-DtScUc-W.mjs.map +0 -1
  1460. package/.output/server/chunks/build/useDcwProducts-BMaxzLu6.mjs +0 -93
  1461. package/.output/server/chunks/build/useDcwProducts-BMaxzLu6.mjs.map +0 -1
  1462. package/.output/server/chunks/build/useDcwQuery-TVU3Eo0M.mjs +0 -98
  1463. package/.output/server/chunks/build/useDcwQuery-TVU3Eo0M.mjs.map +0 -1
  1464. package/.output/server/chunks/build/useDcwQuickActions-BREFmR9T.mjs +0 -88
  1465. package/.output/server/chunks/build/useDcwQuickActions-BREFmR9T.mjs.map +0 -1
  1466. package/.output/server/chunks/build/useDcwRecipes-Bc9urA1N.mjs +0 -258
  1467. package/.output/server/chunks/build/useDcwRecipes-Bc9urA1N.mjs.map +0 -1
  1468. package/.output/server/chunks/build/useDcwStream-Dir5ufAU.mjs +0 -452
  1469. package/.output/server/chunks/build/useDcwStream-Dir5ufAU.mjs.map +0 -1
  1470. package/.output/server/chunks/build/useDcwTemplates-BzagZztS.mjs +0 -91
  1471. package/.output/server/chunks/build/useDcwTemplates-BzagZztS.mjs.map +0 -1
  1472. package/.output/server/chunks/build/useDcwWrites-BROwTLCn.mjs +0 -140
  1473. package/.output/server/chunks/build/useDcwWrites-BROwTLCn.mjs.map +0 -1
  1474. package/.output/server/chunks/build/useDeviceTwins-BqwVJaZg.mjs +0 -128
  1475. package/.output/server/chunks/build/useDeviceTwins-BqwVJaZg.mjs.map +0 -1
  1476. package/.output/server/chunks/build/useExpConfirmations-BM626N4p.mjs +0 -107
  1477. package/.output/server/chunks/build/useExpConfirmations-BM626N4p.mjs.map +0 -1
  1478. package/.output/server/chunks/build/useLocalTime-uVSM44Um.mjs +0 -55
  1479. package/.output/server/chunks/build/useLocalTime-uVSM44Um.mjs.map +0 -1
  1480. package/.output/server/chunks/build/useLogsManual-cVBZQ_Mt.mjs +0 -88
  1481. package/.output/server/chunks/build/useLogsManual-cVBZQ_Mt.mjs.map +0 -1
  1482. package/.output/server/chunks/build/useLogsQuery-D7hrJ3yn.mjs +0 -150
  1483. package/.output/server/chunks/build/useLogsQuery-D7hrJ3yn.mjs.map +0 -1
  1484. package/.output/server/chunks/build/useLogsScope-aaPQeTRm.mjs +0 -83
  1485. package/.output/server/chunks/build/useLogsScope-aaPQeTRm.mjs.map +0 -1
  1486. package/.output/server/chunks/build/useMonitorData-DIkiLr_h.mjs +0 -135
  1487. package/.output/server/chunks/build/useMonitorData-DIkiLr_h.mjs.map +0 -1
  1488. package/.output/server/chunks/build/useMonitorFormat-CyURtH8N.mjs +0 -91
  1489. package/.output/server/chunks/build/useMonitorFormat-CyURtH8N.mjs.map +0 -1
  1490. package/.output/server/chunks/build/useOperationsFeed-Ci4mZAn_.mjs +0 -195
  1491. package/.output/server/chunks/build/useOperationsFeed-Ci4mZAn_.mjs.map +0 -1
  1492. package/.output/server/chunks/build/useOpsLog-C-M6Eace.mjs +0 -149
  1493. package/.output/server/chunks/build/useOpsLog-C-M6Eace.mjs.map +0 -1
  1494. package/.output/server/chunks/build/useRecipeDispatchApprovals-BYtiqfeb.mjs +0 -156
  1495. package/.output/server/chunks/build/useRecipeDispatchApprovals-BYtiqfeb.mjs.map +0 -1
  1496. package/.output/server/chunks/build/useTeamActions-I_8QWp9w.mjs +0 -79
  1497. package/.output/server/chunks/build/useTeamActions-I_8QWp9w.mjs.map +0 -1
  1498. package/.output/server/chunks/build/useTeamAddMemberDialog-BLn4nTuy.mjs +0 -84
  1499. package/.output/server/chunks/build/useTeamAddMemberDialog-BLn4nTuy.mjs.map +0 -1
  1500. package/.output/server/chunks/build/useTeamCreateDialog-Bp5qKtpI.mjs +0 -97
  1501. package/.output/server/chunks/build/useTeamCreateDialog-Bp5qKtpI.mjs.map +0 -1
  1502. package/.output/server/chunks/build/useTeamDeployDialog-DwIaz6Cx.mjs +0 -80
  1503. package/.output/server/chunks/build/useTeamDeployDialog-DwIaz6Cx.mjs.map +0 -1
  1504. package/.output/server/chunks/build/useTeamPluginDialog-B932gZOI.mjs +0 -103
  1505. package/.output/server/chunks/build/useTeamPluginDialog-B932gZOI.mjs.map +0 -1
  1506. package/.output/server/chunks/build/useTeamsCatalog-DBwaLQBw.mjs +0 -123
  1507. package/.output/server/chunks/build/useTeamsCatalog-DBwaLQBw.mjs.map +0 -1
  1508. package/.output/server/chunks/build/useTokenCreate-Ctl0YGhL.mjs +0 -115
  1509. package/.output/server/chunks/build/useTokenCreate-Ctl0YGhL.mjs.map +0 -1
  1510. package/.output/server/chunks/build/useTokenRename-Cm3ypSfN.mjs +0 -87
  1511. package/.output/server/chunks/build/useTokenRename-Cm3ypSfN.mjs.map +0 -1
  1512. package/.output/server/chunks/build/useTokenReveal-CeoWL5Mt.mjs +0 -118
  1513. package/.output/server/chunks/build/useTokenReveal-CeoWL5Mt.mjs.map +0 -1
  1514. package/.output/server/chunks/build/useTokensList-CNIzON3u.mjs +0 -92
  1515. package/.output/server/chunks/build/useTokensList-CNIzON3u.mjs.map +0 -1
  1516. package/.output/server/chunks/build/useWorkbenchAuth-CY-bVFMu.mjs +0 -141
  1517. package/.output/server/chunks/build/useWorkbenchAuth-CY-bVFMu.mjs.map +0 -1
  1518. package/.output/server/chunks/build/useWorkbenchWorkspaces-DhZQFss9.mjs +0 -138
  1519. package/.output/server/chunks/build/useWorkbenchWorkspaces-DhZQFss9.mjs.map +0 -1
  1520. package/.output/server/chunks/build/useWorkshopApi-CaSItJVq.mjs +0 -119
  1521. package/.output/server/chunks/build/useWorkshopApi-CaSItJVq.mjs.map +0 -1
  1522. package/.output/server/chunks/build/useWorkshopWs-YQ5URrbt.mjs +0 -1659
  1523. package/.output/server/chunks/build/useWorkshopWs-YQ5URrbt.mjs.map +0 -1
  1524. package/.output/server/chunks/build/useWorkspaceAuth-Dlvj9csD.mjs.map +0 -1
  1525. package/.output/server/chunks/build/useWorkspaceChannels-CPFepxTN.mjs +0 -92
  1526. package/.output/server/chunks/build/useWorkspaceChannels-CPFepxTN.mjs.map +0 -1
  1527. package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs +0 -168
  1528. package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs.map +0 -1
  1529. package/.output/server/chunks/build/users-DjiVC_tS.mjs +0 -569
  1530. package/.output/server/chunks/build/users-DjiVC_tS.mjs.map +0 -1
  1531. package/.output/server/chunks/build/workshop-1gKeDASV.mjs +0 -546
  1532. package/.output/server/chunks/build/workshop-1gKeDASV.mjs.map +0 -1
  1533. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.json +0 -1
  1534. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/1459e6269990a5d229b9228c8b2f62ffaa7d350068380ae8b875fee0db45cca6.source +0 -180
  1535. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/c2991e909c70c5c12b90a407c7adcf63384c51668a2b334e6e047fa675c268fe.source +0 -305
  1536. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/e09129039d1e27e3fac24becc9bdafd2d1a7c8049bff24173df007be865f0165.source +0 -264
  1537. package/app/.mimosa/hook-status/sess_05189059-e42d-4188-8911-4f7baabe009b-28ef7c75ea.json +0 -14
  1538. package/scripts/e2e-direct-rest-simulator-paper.mjs +0 -624
  1539. package/scripts/e2e-pi-simulator-paper.mjs +0 -2316
  1540. package/scripts/e2e-registered-harness-simulator-paper.mjs +0 -1926
  1541. package/scripts/e2e-simulator-optimizer-paper.mjs +0 -264
  1542. package/scripts/fixtures/omp-paper-harness.mjs +0 -163
  1543. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.json +0 -1
  1544. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.mvhn1irp-99488-e3fdc1cbfc.baseline/942d2679b87b96c612b4f2a425c3ccc5b6f3234f0cf589a8441602f866fbe277.source +0 -41
  1545. package/server/.mimosa/hook-state/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2.mvhn1irp-99488-e3fdc1cbfc.baseline/dd617a82339d2c61e49e28e416aabeb2fc100fb3cb1beca18d02dfb833214af6.source +0 -51
  1546. package/server/.mimosa/hook-status/sess_869e5bfd-07f4-4b6e-a991-6221fcf6b7d2-e67b6b91bf.json +0 -14
  1547. package/server/services/workshop/.mimosa/hook-state/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f.json +0 -1
  1548. package/server/services/workshop/.mimosa/hook-status/sess_fed429fb-c8b7-4a50-bbd6-45afc580893f-e6b75bbfe6.json +0 -14
  1549. package/server/services/workshop/agents/omp-agent/supervision-history.ts +0 -38
  1550. package/server/services/workshop/aml/python/__pycache__/aml_eval.cpython-312.pyc +0 -0
  1551. package/server/services/workshop/aml/python/__pycache__/amlkit.cpython-312.pyc +0 -0
  1552. package/server/services/workshop/aml/python/__pycache__/train-example.cpython-312.pyc +0 -0
  1553. package/server/services/workshop/aml/python/__pycache__/train-hybrid-example.cpython-312.pyc +0 -0
  1554. package/server/services/workshop/optimization/python/.mimosa/hook-state/session_187ec97f45d4bd02369bbe94da527cf1.json +0 -1
  1555. package/server/services/workshop/optimization/python/.mimosa/hook-state/session_187ec97f45d4bd02369bbe94da527cf1.mvjqkcs6-68688-fb7131a89c.baseline/190a6772a4e43801737b4ba6072eb9d53d3099b5d8a9e6f57bc5e8592a26a6c4.source +0 -274
  1556. package/server/services/workshop/optimization/python/.mimosa/hook-status/session_187ec97f45d4bd02369bbe94da527cf1-01ed7f04fa.json +0 -14
  1557. package/server/services/workshop/optimization/python/__pycache__/problems.cpython-312.pyc +0 -0
  1558. /package/.output/public/_nuxt/{9j2J4k4w.js → 9j2J4k4w2.js} +0 -0
  1559. /package/.output/public/_nuxt/{BY3Lbz3h2.js → BY3Lbz3h.js} +0 -0
  1560. /package/.output/public/_nuxt/{Iub61dX92.js → Iub61dX9.js} +0 -0
  1561. /package/.output/public/_nuxt/{Q-JpBT032.js → Q-JpBT03.js} +0 -0
  1562. /package/.output/public/_nuxt/{dVw8IHY62.js → dVw8IHY6.js} +0 -0
  1563. /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.