agentworkshop 0.8.5 → 0.8.6

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 (349) hide show
  1. package/.AgentWorkShop/prompts/host-tools.en.json +3 -3
  2. package/.AgentWorkShop/prompts/host-tools.json +14 -4
  3. package/.output/.AgentWorkShop/prompts/host-tools.en.json +3 -3
  4. package/.output/.AgentWorkShop/prompts/host-tools.json +14 -4
  5. package/.output/nitro.json +1 -1
  6. package/.output/public/_nuxt/{U_n8pryv2.js → 7op-BMk82.js} +1 -1
  7. package/.output/public/_nuxt/{zWZ26UWi.js → B1SIgyrl.js} +1 -1
  8. package/.output/public/_nuxt/{C4tXwpSt.js → BA2lmfW4.js} +1 -1
  9. package/.output/public/_nuxt/{EJkmXP432.js → BDXQqSkl2.js} +1 -1
  10. package/.output/public/_nuxt/{CY_7u1ST2.js → BI9jj13f2.js} +1 -1
  11. package/.output/public/_nuxt/{CGf9neEK2.js → BiXqyYNw2.js} +1 -1
  12. package/.output/public/_nuxt/{D9GoOkyP2.js → BlOm8JIs2.js} +1 -1
  13. package/.output/public/_nuxt/{CQ31GiJU2.js → BoXKUOiN2.js} +1 -1
  14. package/.output/public/_nuxt/{DZzbCFY2.js → BuLoPmcf.js} +1 -1
  15. package/.output/public/_nuxt/{D9ppMCbw.js → BwOK42JQ.js} +1 -1
  16. package/.output/public/_nuxt/{CZJ5cw6r2.js → C1RMfPoB2.js} +1 -1
  17. package/.output/public/_nuxt/{CGviZq4E.js → COfo_Bg3.js} +1 -1
  18. package/.output/public/_nuxt/CTGJHZ8X2.js +1 -0
  19. package/.output/public/_nuxt/{SgsmmrsZ.js → CY2NkFvI.js} +1 -1
  20. package/.output/public/_nuxt/{B4GOTVfN.js → C_4mzQ5X.js} +1 -1
  21. package/.output/public/_nuxt/{DGmFHb7m.js → CdvMP3lv.js} +1 -1
  22. package/.output/public/_nuxt/{iqxZGXsY.js → CooauJ7D.js} +1 -1
  23. package/.output/public/_nuxt/{C3vxePED.js → D1eVi1zr.js} +1 -1
  24. package/.output/public/_nuxt/{DnuJ66Jy.js → D6PUmBb0.js} +1 -1
  25. package/.output/public/_nuxt/{BBhroEeN.js → DC8sMA36.js} +1 -1
  26. package/.output/public/_nuxt/{DOUuGOQR2.js → DDHh85c42.js} +1 -1
  27. package/.output/public/_nuxt/{Cy_HDgSl.js → DDXOfmo2.js} +2 -2
  28. package/.output/public/_nuxt/{Cr2xJ_CY.js → DMFwLxfu.js} +1 -1
  29. package/.output/public/_nuxt/{BZg_MIK42.js → DoprKJ5a2.js} +1 -1
  30. package/.output/public/_nuxt/{BzBBEE-o2.js → Dr1FVeQG2.js} +1 -1
  31. package/.output/public/_nuxt/{W0sNnJQh.js → DtnsTW7e.js} +1 -1
  32. package/.output/public/_nuxt/{gUYi1hLJ2.js → DxDqd6T42.js} +1 -1
  33. package/.output/public/_nuxt/{B0UUODeh.js → DzU3zEKX.js} +1 -1
  34. package/.output/public/_nuxt/{BkO5WdX5.js → EgO70wrE.js} +1 -1
  35. package/.output/public/_nuxt/{7OZQiw002.js → HJKu4eEV2.js} +1 -1
  36. package/.output/public/_nuxt/{ChF6qLpY2.js → K5Xen0wZ2.js} +1 -1
  37. package/.output/public/_nuxt/{CNrRZmSx2.js → Rb4o4o-82.js} +1 -1
  38. package/.output/public/_nuxt/{BqBTlfiz.js → Tf6SJSDj.js} +1 -1
  39. package/.output/public/_nuxt/{DJaGVY4v2.js → ZzOyoXex2.js} +1 -1
  40. package/.output/public/_nuxt/{PbzVdCTA2.js → azOGy_tU2.js} +1 -1
  41. package/.output/public/_nuxt/{D1thFC3z.js → be-4wyTo.js} +1 -1
  42. package/.output/public/_nuxt/builds/latest.json +1 -1
  43. package/.output/public/_nuxt/builds/meta/593b65bd-cf1d-4b7f-a993-57e939c38f36.json +1 -0
  44. package/.output/public/_nuxt/{8b9CKi6F.js → dcjPjLPI.js} +1 -1
  45. package/.output/public/_nuxt/{ae2-5ZPt.js → h-Fn7pRD.js} +1 -1
  46. package/.output/public/_nuxt/{-gy9k_TE2.js → hyLdZsOd2.js} +1 -1
  47. package/.output/public/_nuxt/{BHxG41IQ2.js → o8sYG6xx2.js} +1 -1
  48. package/.output/server/chunks/_/access.mjs +1 -1
  49. package/.output/server/chunks/_/agent-dto.mjs +26 -0
  50. package/.output/server/chunks/_/agent-dto.mjs.map +1 -0
  51. package/.output/server/chunks/_/data-export.mjs +6 -6
  52. package/.output/server/chunks/_/data-query.mjs +3 -3
  53. package/.output/server/chunks/_/eda-run.repo.mjs +2 -2
  54. package/.output/server/chunks/_/features.mjs +5 -5
  55. package/.output/server/chunks/_/golden.mjs +3 -3
  56. package/.output/server/chunks/_/harness-spawn-policy.mjs +77 -0
  57. package/.output/server/chunks/_/harness-spawn-policy.mjs.map +1 -0
  58. package/.output/server/chunks/_/index.mjs +1 -1
  59. package/.output/server/chunks/_/line-scope.mjs +32 -0
  60. package/.output/server/chunks/_/line-scope.mjs.map +1 -0
  61. package/.output/server/chunks/_/mes-console.mjs +1 -1
  62. package/.output/server/chunks/_/nitro.mjs +2429 -1726
  63. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  64. package/.output/server/chunks/_/ocap.mjs +1 -1
  65. package/.output/server/chunks/_/rest-auth.mjs +1 -1
  66. package/.output/server/chunks/_/spc.mjs +1 -1
  67. package/.output/server/chunks/build/TownView-BWMDbosY.mjs +1 -1
  68. package/.output/server/chunks/build/daq-CdxcfY_G.mjs +1 -1
  69. package/.output/server/chunks/build/dcw-BlDQtS4q.mjs +1 -1
  70. package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
  71. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs +1 -1
  72. package/.output/server/chunks/build/useDaqDetailNode-DeOsDxK5.mjs +1 -1
  73. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs +1 -1
  74. package/.output/server/chunks/build/useDaqFilters-CctmO03p.mjs +1 -1
  75. package/.output/server/chunks/build/useDaqStream-B9ZBVQrI.mjs +1 -1
  76. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs +1 -1
  77. package/.output/server/chunks/build/useDcwAddNode-DACVcEHs.mjs +1 -1
  78. package/.output/server/chunks/build/useDcwStream-Dir5ufAU.mjs +1 -1
  79. package/.output/server/chunks/routes/api/mcp/workshop.mjs +1 -1
  80. package/.output/server/chunks/routes/api/system/backup/run.post.mjs +2 -2
  81. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +17 -9
  82. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
  83. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +3 -0
  84. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs.map +1 -1
  85. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  86. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +6 -0
  87. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs.map +1 -1
  88. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +5 -0
  89. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs.map +1 -1
  90. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +5 -2
  91. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs.map +1 -1
  92. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +7 -1
  93. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs.map +1 -1
  94. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +3 -1
  95. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs.map +1 -1
  96. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +8 -6
  97. package/.output/server/chunks/routes/api/workshop/channels.post.mjs.map +1 -1
  98. package/.output/server/chunks/routes/api/workshop/daq/_id/ingest.post.mjs +29 -49
  99. package/.output/server/chunks/routes/api/workshop/daq/_id/ingest.post.mjs.map +1 -1
  100. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
  101. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +6 -1
  102. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
  103. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +4 -2
  104. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs.map +1 -1
  105. package/.output/server/chunks/routes/api/workshop/daq/index2.post.mjs +1 -1
  106. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +14 -5
  107. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs.map +1 -1
  108. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
  109. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
  110. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
  111. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +7 -4
  112. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs.map +1 -1
  113. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
  114. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
  115. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +6 -2
  116. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs.map +1 -1
  117. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +6 -2
  118. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs.map +1 -1
  119. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
  120. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
  121. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
  122. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +6 -1
  123. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs.map +1 -1
  124. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
  125. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +7 -4
  126. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs.map +1 -1
  127. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
  128. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
  129. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
  130. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +6 -2
  131. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs.map +1 -1
  132. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
  133. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +7 -4
  134. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
  135. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
  136. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
  137. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
  138. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +6 -2
  139. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs.map +1 -1
  140. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
  141. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +1 -1
  142. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
  143. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
  144. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
  145. package/.output/server/chunks/routes/api/workshop/dcw/mes-artifacts/file.get.mjs +6 -2
  146. package/.output/server/chunks/routes/api/workshop/dcw/mes-artifacts/file.get.mjs.map +1 -1
  147. package/.output/server/chunks/routes/api/workshop/dcw/mes-hook-test.post.mjs +1 -1
  148. package/.output/server/chunks/routes/api/workshop/dcw/mes-test-read.post.mjs +1 -1
  149. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
  150. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
  151. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +6 -2
  152. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs.map +1 -1
  153. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +4 -2
  154. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs.map +1 -1
  155. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +5 -2
  156. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs.map +1 -1
  157. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +1 -1
  158. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
  159. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
  160. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
  161. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
  162. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
  163. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
  164. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +7 -3
  165. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs.map +1 -1
  166. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +8 -1
  167. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs.map +1 -1
  168. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +6 -2
  169. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs.map +1 -1
  170. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
  171. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
  172. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  173. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  174. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +7 -4
  175. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs.map +1 -1
  176. package/.output/server/chunks/routes/api/workshop/eda/commonality.get.mjs +1 -1
  177. package/.output/server/chunks/routes/api/workshop/eda/vm/predict.post.mjs +1 -1
  178. package/.output/server/chunks/routes/api/workshop/exp/confirmations/_id/decide.post.mjs +1 -1
  179. package/.output/server/chunks/routes/api/workshop/exp/index.get.mjs +1 -1
  180. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +1 -1
  181. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  182. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  183. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  184. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  185. package/.output/server/chunks/routes/api/workshop/index.mjs +1 -1
  186. package/.output/server/chunks/routes/api/workshop/index.post.mjs +2 -0
  187. package/.output/server/chunks/routes/api/workshop/index.post.mjs.map +1 -1
  188. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  189. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +8 -3
  190. package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
  191. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
  192. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
  193. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
  194. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
  195. package/.output/server/chunks/routes/api/workshop/mes/datasets.get.mjs +1 -1
  196. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/autofix.mjs +1 -1
  197. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/compile.mjs +1 -1
  198. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/evidence.mjs +1 -1
  199. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/publish.mjs +1 -1
  200. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/approval-decision.mjs +1 -1
  201. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/approval.mjs +1 -1
  202. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/transition.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/subgraph.mjs +1 -1
  204. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/validate.mjs +1 -1
  205. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId_.mjs +1 -1
  206. package/.output/server/chunks/routes/api/workshop/ontology/export/_ontologyId_.mjs +1 -1
  207. package/.output/server/chunks/routes/api/workshop/ontology/index.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/ontology/scene.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/ontology/traces/_ontologyId_.mjs +1 -1
  210. package/.output/server/chunks/routes/api/workshop/ontology/versions/_ontologyId/compare.mjs +1 -1
  211. package/.output/server/chunks/routes/api/workshop/ontology/versions/_ontologyId_.mjs +1 -1
  212. package/.output/server/chunks/routes/api/workshop/optimization/capabilities.get.mjs +1 -1
  213. package/.output/server/chunks/routes/api/workshop/optimization/index.get.mjs +1 -1
  214. package/.output/server/chunks/routes/api/workshop/optimization/index.mjs +1 -1
  215. package/.output/server/chunks/routes/api/workshop/optimization/index2.mjs +1 -1
  216. package/.output/server/chunks/routes/api/workshop/optimization/profiles/_id/publish.post.mjs +1 -1
  217. package/.output/server/chunks/routes/api/workshop/optimization/recommendations/_id/crosscheck.post.mjs +1 -1
  218. package/.output/server/chunks/routes/api/workshop/optimization/recommendations/_id/dispatch.post.mjs +1 -1
  219. package/.output/server/chunks/routes/api/workshop/optimization/solve.post.mjs +1 -1
  220. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  221. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  222. package/.output/server/chunks/routes/api/workshop/process-model/datasets.post.mjs +1 -1
  223. package/.output/server/chunks/routes/api/workshop/process-model/eligibility.mjs +1 -1
  224. package/.output/server/chunks/routes/api/workshop/process-model/index.mjs +1 -1
  225. package/.output/server/chunks/routes/api/workshop/process-model/specs/_id/publish.post.mjs +1 -1
  226. package/.output/server/chunks/routes/api/workshop/process-model/train.post.mjs +1 -1
  227. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  228. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  229. package/.output/server/chunks/routes/api/workshop/tools/sync.post.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  231. package/.output/server/chunks/routes/renderer.mjs +2 -2
  232. package/.output/server/chunks/virtual/entry.mjs +1 -1
  233. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  234. package/.output/server/package.json +1 -1
  235. package/README-zh.md +4 -2
  236. package/README.md +9 -2
  237. package/config.yml +1 -1
  238. package/docker-compose.yml +4 -2
  239. package/docs/cli.en.md +2 -2
  240. package/docs/cli.md +2 -2
  241. package/docs/plugins.en.md +1 -1
  242. package/docs/plugins.md +1 -1
  243. package/docs/sdk.en.md +1 -1
  244. package/docs/sdk.md +1 -1
  245. package/package.json +1 -1
  246. package/scripts/_audit/_live-mqtt-e2e-20261028.mjs +219 -0
  247. package/scripts/_audit/prompt-injection-probe.mts +76 -0
  248. package/scripts/api-live-e2e.mjs +9 -3
  249. package/scripts/e2e-multiexpert-remediation-real.mjs +453 -0
  250. package/scripts/e2e-node-binding-3mode-real.mjs +697 -0
  251. package/scripts/e2e-node-binding-authz.mjs +332 -0
  252. package/scripts/security-acceptance.mjs +218 -0
  253. package/server/api/workshop/agent-tools/bindings/index.post.ts +33 -17
  254. package/server/api/workshop/agents/[id].patch.ts +3 -0
  255. package/server/api/workshop/agents/index.post.ts +3 -0
  256. package/server/api/workshop/channel-templates/[id].patch.ts +5 -0
  257. package/server/api/workshop/channel-templates/index.post.ts +6 -0
  258. package/server/api/workshop/channels/[id]/agents/[agentId].patch.ts +5 -0
  259. package/server/api/workshop/channels/[id]/agents/index.get.ts +8 -2
  260. package/server/api/workshop/channels/[id]/agents/index.post.ts +7 -0
  261. package/server/api/workshop/channels/[id]/index.get.ts +10 -4
  262. package/server/api/workshop/channels.post.ts +3 -0
  263. package/server/api/workshop/daq/[id]/ingest.post.ts +26 -22
  264. package/server/api/workshop/daq/[id].patch.ts +8 -0
  265. package/server/api/workshop/daq/alarms.get.ts +18 -16
  266. package/server/api/workshop/daq/infra/reconnect.post.ts +21 -5
  267. package/server/api/workshop/daq/test-driver.post.ts +10 -3
  268. package/server/api/workshop/dcw/[id]/param-ledger.get.ts +7 -1
  269. package/server/api/workshop/dcw/[id]/read.post.ts +6 -1
  270. package/server/api/workshop/dcw/[id].patch.ts +49 -40
  271. package/server/api/workshop/dcw/journal/index.get.ts +7 -3
  272. package/server/api/workshop/dcw/mes-artifacts/file.get.ts +7 -1
  273. package/server/api/workshop/dcw/mes-artifacts/index.get.ts +7 -1
  274. package/server/api/workshop/dcw/optimizations/[id]/series.get.ts +6 -1
  275. package/server/api/workshop/dcw/optimizations/[id].get.ts +3 -1
  276. package/server/api/workshop/dcw/optimizations/index.get.ts +6 -3
  277. package/server/api/workshop/dcw/params/[id]/read.post.ts +22 -17
  278. package/server/api/workshop/dcw/recipes/[id]/versions.get.ts +20 -14
  279. package/server/api/workshop/dcw/recipes/[id].delete.ts +33 -25
  280. package/server/api/workshop/dcw/recipes/index.get.ts +17 -12
  281. package/server/api/workshop/dcw/runs/[id]/close.post.ts +21 -15
  282. package/server/api/workshop/dcw/test-driver.post.ts +21 -16
  283. package/server/api/workshop/ws/hub.ts +2 -1
  284. package/server/plugins/01-instance-guard.ts +82 -0
  285. package/server/plugins/daq.ts +40 -8
  286. package/server/plugins/workshop.ts +12 -0
  287. package/server/services/workshop/agents/adapters/line-spawn.ts +24 -1
  288. package/server/services/workshop/agents/agent-dto.ts +54 -0
  289. package/server/services/workshop/agents/harness-spawn-policy.ts +114 -0
  290. package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +22 -0
  291. package/server/services/workshop/agents/host-tool-bridge/index.ts +1 -1
  292. package/server/services/workshop/agents/host-tool-bridge/per-agent.ts +17 -3
  293. package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +1 -1
  294. package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +5 -1
  295. package/server/services/workshop/agents/industrial/dcw-tools.ts +6 -2
  296. package/server/services/workshop/agents/industrial/ops-tools.ts +54 -12
  297. package/server/services/workshop/agents/industrial/recipe-gate.ts +68 -15
  298. package/server/services/workshop/agents/industrial/tool-verify-legacy-specs.ts +2 -2
  299. package/server/services/workshop/agents/industrial/tool-verify.ts +31 -2
  300. package/server/services/workshop/agents/node-bindings.repo.ts +4 -3
  301. package/server/services/workshop/agents/node-delegation.ts +49 -4
  302. package/server/services/workshop/agents/tool-approvals.ts +23 -0
  303. package/server/services/workshop/agents/tool-reference-spec.ts +3 -0
  304. package/server/services/workshop/daq/bus/mqtt.adapter.ts +12 -0
  305. package/server/services/workshop/daq/daq-controller/crud.ts +5 -3
  306. package/server/services/workshop/daq/daq-controller/ingest.ts +23 -0
  307. package/server/services/workshop/daq/daq-controller/push.ts +24 -3
  308. package/server/services/workshop/daq/daq-controller/runtime-control.ts +6 -0
  309. package/server/services/workshop/daq/daq-controller/sweep-alarms.ts +3 -1
  310. package/server/services/workshop/daq/daq-controller/tsdb-twin.ts +21 -1
  311. package/server/services/workshop/daq/daq-node.repo.ts +10 -7
  312. package/server/services/workshop/daq/daq-node.ts +2 -0
  313. package/server/services/workshop/daq/daq-runtime.ts +10 -2
  314. package/server/services/workshop/daq/drivers/modbus-tcp.ts +8 -5
  315. package/server/services/workshop/daq/drivers/registry.ts +5 -4
  316. package/server/services/workshop/daq/infra.ts +13 -0
  317. package/server/services/workshop/daq/ingest-policy.ts +24 -1
  318. package/server/services/workshop/daq/storage/timescale.adapter.ts +42 -3
  319. package/server/services/workshop/db/database/migrations.ts +83 -68
  320. package/server/services/workshop/dcw/dcw-controller/crud.ts +27 -2
  321. package/server/services/workshop/dcw/dcw-controller/lines.ts +14 -3
  322. package/server/services/workshop/dcw/dcw-controller/recipes.ts +63 -5
  323. package/server/services/workshop/dcw/dcw-recipe.repo.ts +10 -1
  324. package/server/services/workshop/dcw/dcw-runtime.ts +37 -14
  325. package/server/services/workshop/dcw/drivers/shared.ts +62 -6
  326. package/server/services/workshop/dcw/recipe-op-anchor.ts +28 -0
  327. package/server/services/workshop/dcw/recipe-rollback-manager/rollback.ts +204 -190
  328. package/server/services/workshop/dcw/recipe-rollback-manager/sweep.ts +97 -77
  329. package/server/services/workshop/line-scope.ts +80 -0
  330. package/server/services/workshop/optimization/dispatch.service.ts +18 -2
  331. package/server/services/workshop/permissions.ts +2 -0
  332. package/server/services/workshop/runtime/agent-runtime/message.ts +17 -0
  333. package/server/services/workshop/runtime/agent-runtime/state.ts +9 -3
  334. package/server/services/workshop/runtime/agent-runtime/types.ts +2 -1
  335. package/server/services/workshop/runtime/channel-runtime.ts +3 -1
  336. package/server/services/workshop/runtime/mailbox.ts +6 -3
  337. package/server/services/workshop/runtime/manager/a2a.ts +4 -2
  338. package/server/services/workshop/runtime/manager/admin-channel.ts +1 -1
  339. package/server/services/workshop/runtime/manager/chat.ts +3 -1
  340. package/server/services/workshop/runtime/manager/host-tools.ts +1 -1
  341. package/server/services/workshop/runtime/manager/runtime-wiring.ts +31 -19
  342. package/server/services/workshop/runtime/manager/state.ts +43 -1
  343. package/server/services/workshop/runtime/permission-scope.ts +21 -0
  344. package/server/services/workshop/runtime/scheduler-loop/tick.ts +16 -4
  345. package/server/services/workshop/scene-events.ts +19 -0
  346. package/shared/daq-protocol.ts +24 -5
  347. package/shared/dcw-protocol/catalog.ts +4 -4
  348. package/.output/public/_nuxt/CCI-fwcS2.js +0 -1
  349. package/.output/public/_nuxt/builds/meta/5cd11284-05bf-4fcd-9a69-56a01c9f56dd.json +0 -1
@@ -9,6 +9,7 @@ import { zValidator } from '../../../utils/validate'
9
9
  import { defineApiHandler } from '../../../utils/response'
10
10
  import { AppError } from '../../../utils/errors'
11
11
  import { getWorkshopManager } from '../../../plugins/workshop'
12
+ import { assertSpawnConfigAllowed } from '../../../services/workshop/agents/harness-spawn-policy'
12
13
 
13
14
  const patchAgentSchema = z.object({
14
15
  name: z.string().min(1).optional(),
@@ -26,5 +27,7 @@ export default defineApiHandler(async (event) => {
26
27
  const agent = manager.getAgent(agentId)
27
28
  if (!agent) throw new AppError(404, 'NOT_FOUND', `Agent 不存在: ${agentId}`)
28
29
  manager.requireWritable(agent.ownerUserId, user, 'Agent 模板')
30
+ // 启动面收权(2026-10-28):command/args/cwd/env 只有 admin 能改,且命令须与引擎同族
31
+ assertSpawnConfigAllowed(String(body.harness ?? agent.harness), body.config, user)
29
32
  return manager.updateAgent(agentId, body)
30
33
  })
@@ -8,6 +8,7 @@ import { readValidatedBody } from 'h3'
8
8
  import { zValidator } from '../../../utils/validate'
9
9
  import { defineApiHandler } from '../../../utils/response'
10
10
  import { getWorkshopManager } from '../../../plugins/workshop'
11
+ import { assertSpawnConfigAllowed } from '../../../services/workshop/agents/harness-spawn-policy'
11
12
 
12
13
  const createAgentSchema = z.object({
13
14
  name: z.string().min(1, 'name 必填'),
@@ -19,6 +20,8 @@ const createAgentSchema = z.object({
19
20
  export default defineApiHandler(async (event) => {
20
21
  const user = resolveUser(event)
21
22
  const body = await readValidatedBody(event, zValidator(createAgentSchema))
23
+ // 启动面收权(2026-10-28):非 admin 不得指定 command/args/cwd/env
24
+ assertSpawnConfigAllowed(body.harness, body.config, user)
22
25
  return getWorkshopManager().createAgent({
23
26
  name: body.name,
24
27
  harness: body.harness,
@@ -9,6 +9,7 @@ import { defineApiHandler } from '../../../utils/response'
9
9
  import { AppError } from '../../../utils/errors'
10
10
  import { resolveUser } from '../caller'
11
11
  import { getWorkshopManager } from '../../../plugins/workshop'
12
+ import { assertSpawnConfigAllowed } from '../../../services/workshop/agents/harness-spawn-policy'
12
13
 
13
14
  const memberSchema = z.union([
14
15
  z.object({ templateId: z.string().min(1), role: z.enum(['lead', 'worker']) }),
@@ -44,5 +45,9 @@ export default defineApiHandler(async (event) => {
44
45
  const tpl = manager.getChannelTemplate(templateId)
45
46
  if (!tpl) throw new AppError(404, 'NOT_FOUND', `Channel 模板不存在: ${templateId}`)
46
47
  manager.requireWritable(tpl.ownerUserId, user, 'Channel 模板')
48
+ if (body.lead) assertSpawnConfigAllowed(body.lead.harness, body.lead.config, user)
49
+ for (const m of body.members ?? []) {
50
+ if ('inline' in m) assertSpawnConfigAllowed(m.inline.harness, m.inline.config, user)
51
+ }
47
52
  return manager.updateChannelTemplate(templateId, body)
48
53
  })
@@ -9,6 +9,7 @@ import { zValidator } from '../../../utils/validate'
9
9
  import { defineApiHandler } from '../../../utils/response'
10
10
  import { AppError } from '../../../utils/errors'
11
11
  import { getWorkshopManager } from '../../../plugins/workshop'
12
+ import { assertSpawnConfigAllowed } from '../../../services/workshop/agents/harness-spawn-policy'
12
13
 
13
14
  const memberSchema = z.union([
14
15
  z.object({ templateId: z.string().min(1), role: z.enum(['lead', 'worker']) }),
@@ -40,6 +41,11 @@ export default defineApiHandler(async (event) => {
40
41
  const user = resolveUser(event)
41
42
  const body = await readValidatedBody(event, zValidator(createSchema))
42
43
  const manager = getWorkshopManager()
44
+ // 启动面收权(2026-10-28):模板内联成员同样不得由非 admin 指定 command/args/cwd/env
45
+ if (body.lead) assertSpawnConfigAllowed(body.lead.harness, body.lead.config, user)
46
+ for (const m of body.members ?? []) {
47
+ if ('inline' in m) assertSpawnConfigAllowed(m.inline.harness, m.inline.config, user)
48
+ }
43
49
  // 成员模板引用校验:引用的 Agent 模板须操作者可读
44
50
  for (const m of body.members ?? []) {
45
51
  if ('templateId' in m) {
@@ -8,6 +8,7 @@ import { resolveUser } from '../../../caller'
8
8
  import { AppError } from '../../../../../utils/errors'
9
9
  import { defineApiHandler } from '../../../../../utils/response'
10
10
  import { getWorkshopManager } from '../../../../../plugins/workshop'
11
+ import { assertSpawnConfigAllowed } from '../../../../../services/workshop/agents/harness-spawn-policy'
11
12
 
12
13
  export default defineApiHandler(async (event) => {
13
14
  const channelId = getRouterParam(event, 'id')!
@@ -19,6 +20,10 @@ export default defineApiHandler(async (event) => {
19
20
  manager.requireWritable(channel.ownerUserId, user, 'channel')
20
21
  const members = await manager.listChannelAgents(channelId)
21
22
  if (!members.some(a => a.id === agentId)) throw new AppError(404, 'NOT_FOUND', `成员不存在: ${agentId}`)
23
+ if (body?.config) {
24
+ const member = members.find(a => a.id === agentId)!
25
+ assertSpawnConfigAllowed(member.harness, body.config, user)
26
+ }
22
27
  const patch: { name?: string, config?: Record<string, unknown>, enabled?: number } = {}
23
28
  if (typeof body?.name === 'string' && body.name.trim()) patch.name = body.name.trim()
24
29
  if (body?.config && typeof body.config === 'object') patch.config = body.config
@@ -2,19 +2,24 @@
2
2
  * GET /api/workshop/channels/:id/agents —— channel 成员列表。
3
3
  * 双轨鉴权:用户 token(owner/遗留公共可见)或 agent token(本 channel 成员)。
4
4
  * - channel 不存在 → 404 NOT_FOUND
5
+ *
6
+ * 2026-10-28 安全修复:响应不再回显 agent token(worker 借此冒充 lead);
7
+ * config 仅属主/admin 可见,且由 DTO 剔除启动类敏感键。
5
8
  */
6
9
  import { getRouterParam } from 'h3'
7
10
  import { resolveUser, resolveCallerOrNull } from '../../../caller'
8
11
  import { defineApiHandler } from '../../../../../utils/response'
9
12
  import { AppError } from '../../../../../utils/errors'
10
13
  import { getWorkshopManager } from '../../../../../plugins/workshop'
14
+ import { channelAgentSummaries } from '../../../../../services/workshop/agents/agent-dto'
11
15
 
12
16
  export default defineApiHandler(async (event) => {
13
17
  const channelId = getRouterParam(event, 'id')!
14
18
  const manager = getWorkshopManager()
15
19
  // 双轨:优先按用户 token;无用户 token 时接受本 channel 成员的 agent token
20
+ let user: { id: string, role: string } | null = null
16
21
  try {
17
- const user = resolveUser(event)
22
+ user = resolveUser(event)
18
23
  manager.getChannelForUser(channelId, user.id)
19
24
  }
20
25
  catch (err) {
@@ -23,5 +28,6 @@ export default defineApiHandler(async (event) => {
23
28
  }
24
29
  const channel = (await manager.listChannels()).find(c => c.id === channelId)
25
30
  if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
26
- return manager.listChannelAgents(channelId)
31
+ const includeConfig = Boolean(user && (user.role === 'admin' || channel.ownerUserId === user.id))
32
+ return channelAgentSummaries(await manager.listChannelAgents(channelId), { includeConfig })
27
33
  })
@@ -12,6 +12,7 @@ import { zValidator } from '../../../../../utils/validate'
12
12
  import { defineApiHandler } from '../../../../../utils/response'
13
13
  import { AppError } from '../../../../../utils/errors'
14
14
  import { getWorkshopManager, ensureLeadSchedulerLoop } from '../../../../../plugins/workshop'
15
+ import { assertSpawnConfigAllowed } from '../../../../../services/workshop/agents/harness-spawn-policy'
15
16
 
16
17
  const createAgentSchema = z.object({
17
18
  agentId: z.string().min(1).optional(),
@@ -32,6 +33,12 @@ export default defineApiHandler(async (event) => {
32
33
  const ch = manager.getChannelForUser(channelId, user.id)
33
34
  manager.requireWritable(ch.ownerUserId, user, 'channel')
34
35
  const role = body.role ?? 'worker'
36
+ // 启动面收权(2026-10-28):成员 config 的 command/args/cwd/env 同样只有 admin 可给
37
+ if (body.harness) assertSpawnConfigAllowed(body.harness, body.config, user)
38
+ else if (body.config) {
39
+ const tplHarness = body.agentId ? manager.getAgent(body.agentId)?.harness : undefined
40
+ if (tplHarness) assertSpawnConfigAllowed(tplHarness, body.config, user)
41
+ }
35
42
  // 克隆模板时校验模板可读(属主/public 含内置/admin;他人 private → 403)
36
43
  if (body.agentId) {
37
44
  const tpl = manager.getAgent(body.agentId)
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * GET /api/workshop/channels/:id —— channel 详情(含 workspace 与成员列表)。
3
3
  * - channel 不存在 → 404 NOT_FOUND
4
+ *
5
+ * 2026-10-28 安全修复:成员列表经 DTO 投影,永不回显 agent token;
6
+ * config 仅属主/admin 可见。
4
7
  */
5
- import { getRouterParam } from 'h3'
6
- import { resolveUser } from '../../caller'
8
+ import { getRouterParam } from 'h3'
9
+ import { resolveUser } from '../../caller'
7
10
  import { defineApiHandler } from '../../../../utils/response'
8
- import { getWorkshopManager, ensureLeadSchedulerLoop } from '../../../../plugins/workshop'
11
+ import { getWorkshopManager, ensureLeadSchedulerLoop } from '../../../../plugins/workshop'
12
+ import { channelAgentSummaries } from '../../../../services/workshop/agents/agent-dto'
13
+
9
14
  export default defineApiHandler(async (event) => {
10
15
  const channelId = getRouterParam(event, 'id')!
11
16
  const user = resolveUser(event)
@@ -14,5 +19,6 @@ export default defineApiHandler(async (event) => {
14
19
  const channel = await manager.getChannel(channelId)
15
20
  // 兜底:详情请求时确保 lead 的调度循环已装配(如启动恢复遗漏)
16
21
  ensureLeadSchedulerLoop(manager, channelId)
17
- return channel
22
+ const includeConfig = user.role === 'admin' || channel.ownerUserId === user.id
23
+ return { ...channel, agents: channelAgentSummaries(channel.agents, { includeConfig }) }
18
24
  })
@@ -9,6 +9,7 @@ import { readValidatedBody } from 'h3'
9
9
  import { zValidator } from '../../utils/validate'
10
10
  import { defineApiHandler } from '../../utils/response'
11
11
  import { getWorkshopManager, ensureLeadSchedulerLoop } from '../../plugins/workshop'
12
+ import { assertSpawnConfigAllowed } from '../../services/workshop/agents/harness-spawn-policy'
12
13
 
13
14
  const createChannelSchema = z.object({
14
15
  name: z.string().min(1, 'name 必填'),
@@ -38,6 +39,8 @@ const createChannelSchema = z.object({
38
39
  export default defineApiHandler(async (event) => {
39
40
  const user = resolveUser(event)
40
41
  const body = await readValidatedBody(event, zValidator(createChannelSchema))
42
+ // 启动面收权(2026-10-28):lead harness 的 command/args/cwd/env 只有 admin 能指定
43
+ if (body.leadAgent) assertSpawnConfigAllowed(body.leadAgent.harness, body.leadAgent.config, user)
41
44
  const manager = getWorkshopManager()
42
45
  const result = await manager.createChannel({
43
46
  name: body.name,
@@ -17,17 +17,14 @@
17
17
  * - 向量 1..4096 个有限数;图像 ≤10MB 且 MIME image/*;
18
18
  * - at 缺省=当前时间,回填窗默认 ±1h(env AW_DAQ_INGEST_BACKFILL_MS 可调,上限 7 天)。
19
19
  */
20
- import { createHash } from 'node:crypto'
21
20
  import { getHeader, getRouterParam, readBody } from 'h3'
22
21
  import { resolveUser } from '@/server/api/workshop/caller'
23
22
  import { defineApiHandler } from '@/server/utils/response'
24
23
  import { getDaqController } from '@/server/services/workshop/daq/daq-controller'
25
24
  import { findDaqTemplate } from '@/server/services/workshop/daq/daq-templates'
26
25
  import { getDaqQueue } from '@/server/services/workshop/daq/bus'
27
- import { getObjectStore } from '@/server/services/workshop/daq/objectstore'
28
- import { daqObjectKey } from '@/server/services/workshop/daq/objectstore/objectstore-port'
29
26
  import type { DaqSampleEnvelope } from '@/server/services/workshop/daq/bus/queue-port'
30
- import { ingestAuthMode, ingestBackfillWindowMs, isWideBackfillWindow, withinBackfillWindow } from '@/server/services/workshop/daq/ingest-policy'
27
+ import { ingestAuthMode, ingestBackfillWindowMs, ingestFutureSkewMs, ingestTimeVerdict, isWideBackfillWindow } from '@/server/services/workshop/daq/ingest-policy'
31
28
  import { recordOps } from '@/server/services/workshop/ops/ops'
32
29
  import { AppError } from '@/server/utils/errors'
33
30
 
@@ -116,8 +113,12 @@ export default defineApiHandler(async (event) => {
116
113
  const atMs = atRaw ? Date.parse(atRaw) : now
117
114
  if (!Number.isFinite(atMs)) throw new AppError(400, 'VALIDATION_ERROR', `at 不是合法时间: ${atRaw}(示例 2026-10-19T12:00:00+08:00)`)
118
115
  const windowMs = ingestBackfillWindowMs()
119
- if (!withinBackfillWindow(atMs, now, windowMs)) {
120
- throw new AppError(400, 'VALIDATION_ERROR', `at 超出允许范围(±${Math.round(windowMs / 60_000)} 分钟),请检查时区/时钟。`)
116
+ const verdict = ingestTimeVerdict(atMs, now, windowMs, ingestFutureSkewMs())
117
+ if (verdict === 'future') {
118
+ throw new AppError(400, 'FUTURE_TIMESTAMP', `at 超出当前时间允许的前瞻偏差(最多 ${Math.round(ingestFutureSkewMs() / 1000)}s);请校准上游时钟后重试。`)
119
+ }
120
+ if (verdict === 'out-of-window') {
121
+ throw new AppError(400, 'VALIDATION_ERROR', `at 超出允许的回填范围(${Math.round(windowMs / 60_000)} 分钟),请检查时区/时钟。`)
121
122
  }
122
123
  const at = new Date(atMs).toISOString()
123
124
  const state = ['ok', 'warn', 'alarm', 'offline'].includes(String(body.state ?? '')) ? String(body.state) : 'ok'
@@ -141,27 +142,27 @@ export default defineApiHandler(async (event) => {
141
142
  }
142
143
  if (buf.length === 0) throw new AppError(400, 'VALIDATION_ERROR', '图像内容为空。')
143
144
  if (buf.length > IMAGE_MAX_BYTES) throw new AppError(413, 'PAYLOAD_TOO_LARGE', `图像超过 ${IMAGE_MAX_BYTES / 1024 / 1024}MB 上限。`)
144
- const objectKey = daqObjectKey(node.id, atMs, mime.includes('jpeg') ? '.jpg' : mime.includes('webp') ? '.webp' : '.png')
145
- await getObjectStore().put(objectKey, buf, mime)
146
- const sha256 = createHash('sha256').update(buf).digest('hex')
147
145
  const width = Number(body.image && typeof body.image === 'object' ? body.image.width : NaN)
148
146
  const height = Number(body.image && typeof body.image === 'object' ? body.image.height : NaN)
147
+ // A-P1-3(2026-10-28 审查):外部推送与驱动采样/推送订阅走**同一个** processFrameSample
148
+ // —— 模板 sink 管线(thumbnail/deriveMetric/qualityGate)与落对象存储、sha256/size
149
+ // 计算都在服务端完成,绝不信任调用方自报的指标/指纹,也不绕过质量门。
150
+ const processed = await getDaqController().processExternalFrame(node, {
151
+ kind: 'image',
152
+ blob: buf,
153
+ mime,
154
+ width: Number.isFinite(width) ? width : undefined,
155
+ height: Number.isFinite(height) ? height : undefined,
156
+ metrics,
157
+ }, atMs)
158
+ if (!processed) throw new AppError(400, 'VALIDATION_ERROR', '图像帧被 sink 管线拒绝(模板/处理器配置不支持该帧)。')
149
159
  env = {
150
160
  nodeId: node.id,
151
161
  templateRef: node.templateRef,
152
- value: Number((metrics.avg ?? 0).toFixed(node.decimals)),
162
+ value: Number((processed.frame.metrics?.avg ?? metrics.avg ?? 0).toFixed(node.decimals)),
153
163
  state,
154
164
  at,
155
- frame: {
156
- kind: 'image',
157
- objectKey,
158
- mime,
159
- width: Number.isFinite(width) ? width : undefined,
160
- height: Number.isFinite(height) ? height : undefined,
161
- sha256,
162
- size: buf.length,
163
- metrics,
164
- },
165
+ frame: processed.frame,
165
166
  }
166
167
  }
167
168
  else if (kind === 'vector') {
@@ -169,13 +170,16 @@ export default defineApiHandler(async (event) => {
169
170
  if (!points || points.length === 0) throw new AppError(400, 'VALIDATION_ERROR', '向量节点的载荷必须提供 points 数组。')
170
171
  if (points.length > VECTOR_MAX_POINTS) throw new AppError(413, 'PAYLOAD_TOO_LARGE', `向量点数 ${points.length} 超过 ${VECTOR_MAX_POINTS} 上限。`)
171
172
  const avg = points.reduce((a, b) => a + b, 0) / points.length
173
+ // 同上:派生指标由模板 sink 处理器产生(调用方只提供原始点列/可选初值)
174
+ const processed = await getDaqController().processExternalFrame(node, { kind: 'vector', points, metrics }, atMs)
175
+ if (!processed) throw new AppError(400, 'VALIDATION_ERROR', '向量帧被 sink 管线拒绝(模板/处理器配置不支持该帧)。')
172
176
  env = {
173
177
  nodeId: node.id,
174
178
  templateRef: node.templateRef,
175
- value: Number((metrics.avg ?? avg).toFixed(node.decimals)),
179
+ value: Number((processed.frame.metrics?.avg ?? metrics.avg ?? avg).toFixed(node.decimals)),
176
180
  state,
177
181
  at,
178
- frame: { kind: 'vector', points, metrics },
182
+ frame: processed.frame,
179
183
  }
180
184
  }
181
185
  else {
@@ -5,6 +5,7 @@ import { getRouterParam, readBody } from 'h3'
5
5
  import { resolveUser } from '@/server/api/workshop/caller'
6
6
  import { requireLineMode } from '@/server/services/workshop/permissions'
7
7
  import { defineApiHandler } from '@/server/utils/response'
8
+ import { AppError } from '@/server/utils/errors'
8
9
  import { bindDaqHost } from '@/server/services/workshop/daq/host-bindings'
9
10
  import { getDaqController, type DaqPatchInput } from '@/server/services/workshop/daq/daq-controller'
10
11
  import { broadcastSceneEvent } from '../../../services/workshop/scene-events'
@@ -17,6 +18,13 @@ export default defineApiHandler(async (event) => {
17
18
  const body = await readBody<DaqPatchInput>(event) ?? {}
18
19
  // 产线权限:参数下发=操控能力(readonly/无权用户 403)
19
20
  requireLineMode(user, getDaqController().byId(id)?.lineId, 'operate')
21
+ // 驱动/连接配置分权(2026-10-28):http/mqtt 驱动的 URL/topic 由 driverConfig 决定,
22
+ // operate 可借此让服务端连接任意目标;与节点 create 同口径收敛到 admin。
23
+ const DAQ_ADMIN_ONLY = ['driver', 'driverConfig'] as const
24
+ const denied = DAQ_ADMIN_ONLY.filter(k => (body as Record<string, unknown>)[k] !== undefined)
25
+ if (denied.length > 0 && user.role !== 'admin') {
26
+ throw new AppError(403, 'DAQ_CONFIG_ADMIN_ONLY', `字段「${denied.join('/')}」决定采集落点与协议参数,仅管理员可修改(当前角色 ${user.role})。`)
27
+ }
20
28
  const node = getDaqController().patch(id, body)
21
29
  recordOps({
22
30
  actor: user.id,
@@ -1,16 +1,18 @@
1
- /**
2
- * GET /api/workshop/daq/alarms?scope=open|all&limit= —— 报警列表(S5)。
3
- * open = 未确认(默认);all = 含已确认历史(审计/复盘)。
4
- */
5
- import { getQuery } from 'h3'
6
- import { resolveUser } from '@/server/api/workshop/caller'
7
- import { defineApiHandler } from '@/server/utils/response'
8
- import { getDaqController } from '@/server/services/workshop/daq/daq-controller'
9
-
10
- export default defineApiHandler(async (event) => {
11
- resolveUser(event)
12
- const q = getQuery(event)
13
- const scope = q.scope === 'all' ? 'all' : 'open'
14
- const limit = Math.min(500, Math.max(1, Number(q.limit) || 100))
15
- return { alarms: getDaqController().listAlarms(scope, limit) }
16
- })
1
+ /**
2
+ * GET /api/workshop/daq/alarms?scope=open|all&limit= —— 报警列表(S5)。
3
+ * open = 未确认(默认);all = 含已确认历史(审计/复盘)。
4
+ */
5
+ import { getQuery } from 'h3'
6
+ import { resolveUser } from '@/server/api/workshop/caller'
7
+ import { defineApiHandler } from '@/server/utils/response'
8
+ import { getDaqController } from '@/server/services/workshop/daq/daq-controller'
9
+ import { daqNodeLineId, filterRowsByLine } from '@/server/services/workshop/line-scope'
10
+
11
+ export default defineApiHandler(async (event) => {
12
+ const user = resolveUser(event)
13
+ const q = getQuery(event)
14
+ const scope = q.scope === 'all' ? 'all' : 'open'
15
+ const limit = Math.min(500, Math.max(1, Number(q.limit) || 100))
16
+ const alarms = getDaqController().listAlarms(scope, limit)
17
+ return { alarms: filterRowsByLine(user, alarms, a => daqNodeLineId(a.nodeId)) }
18
+ })
@@ -1,17 +1,33 @@
1
1
  /**
2
2
  * POST /api/workshop/daq/infra/reconnect —— 手动重连(探测→Docker 拉起→重建后端→恢复/停用采集)。
3
+ *
4
+ * 2026-10-28 安全修复:此前仅 resolveUser —— 任意登录用户都能触发 docker compose、
5
+ * 重建后端并全局启停采样;总控 /daq/controller 却要求 admin/editor,口径不一致。
6
+ * 同时加单飞:并发 reconnect 会互相打断采集。
3
7
  */
4
- import { resolveUser } from '@/server/api/workshop/caller'
8
+ import { requireRole } from '@/server/api/workshop/caller'
5
9
  import { defineApiHandler } from '@/server/utils/response'
10
+ import { AppError } from '@/server/utils/errors'
6
11
  import { daqInfraConfig, daqInfraStatus, type DaqInfraConfig } from '@/server/services/workshop/daq/infra'
7
12
 
13
+ const g = globalThis as unknown as { __daqReconnectInFlight?: boolean }
14
+
8
15
  export default defineApiHandler(async (event) => {
9
- resolveUser(event)
16
+ requireRole(event, ['admin', 'editor'])
10
17
  const apply = (globalThis as unknown as { __daqApplyInfra?: (c: DaqInfraConfig) => Promise<void> }).__daqApplyInfra
11
18
  if (!apply) {
12
19
  return { infra: { ...daqInfraStatus(), warning: '启动插件未就绪,稍后重试' } }
13
20
  }
14
- // cfg 由启动插件闭包持有(与运行配置同源);此处触发一次完整装配
15
- await apply(daqInfraConfig())
16
- return { infra: daqInfraStatus() }
21
+ if (g.__daqReconnectInFlight) {
22
+ throw new AppError(409, 'RECONNECT_IN_FLIGHT', '已有一次基础设施重连在执行,请等待完成后再试')
23
+ }
24
+ g.__daqReconnectInFlight = true
25
+ try {
26
+ // cfg 由启动插件闭包持有(与运行配置同源);此处触发一次完整装配
27
+ await apply(daqInfraConfig())
28
+ return { infra: daqInfraStatus() }
29
+ }
30
+ finally {
31
+ g.__daqReconnectInFlight = false
32
+ }
17
33
  })
@@ -3,9 +3,13 @@
3
3
  * body: { driver: DaqDriverKind, driverConfig: Record<string, string|number|boolean> }
4
4
  * → DriverTestResult { ok, message, sampleValue?, latencyMs? }
5
5
  * 前端添加节点向导"测试连接"直达;通过后可直接创建节点开始采集。
6
+ *
7
+ * 2026-10-28 安全修复:仅 admin/editor 可调用(此前任意登录用户可提交任意连接配置
8
+ * 让服务端连内网目标);driverConfig.allowPrivateHost 不再接受调用方自填,
9
+ * 私网白名单只认服务端开关 AW_TEST_DRIVER_ALLOW_PRIVATE=1。
6
10
  */
7
11
  import { readBody } from 'h3'
8
- import { resolveUser } from '@/server/api/workshop/caller'
12
+ import { requireRole } from '@/server/api/workshop/caller'
9
13
  import { defineApiHandler } from '@/server/utils/response'
10
14
  import { bindDaqHost } from '@/server/services/workshop/daq/host-bindings'
11
15
  import { getDaqController } from '@/server/services/workshop/daq/daq-controller'
@@ -14,10 +18,13 @@ import { requireDriverKind } from '@/server/services/workshop/daq/drivers'
14
18
  import type { DaqDriverKind } from '#shared/daq-protocol'
15
19
 
16
20
  export default defineApiHandler(async (event) => {
17
- resolveUser(event)
21
+ requireRole(event, ['admin', 'editor'])
18
22
  bindDaqHost(broadcastSceneEvent)
19
23
  const body = await readBody<{ driver?: DaqDriverKind, driverConfig?: Record<string, string | number | boolean> }>(event) ?? {}
20
24
  if (!body.driver) return { ok: false, message: '缺少 driver' }
21
- const result = await getDaqController().testDriver(requireDriverKind(body.driver), body.driverConfig ?? {})
25
+ const cfg: Record<string, string | number | boolean> = { ...(body.driverConfig ?? {}) }
26
+ delete cfg.allowPrivateHost
27
+ if (process.env.AW_TEST_DRIVER_ALLOW_PRIVATE === '1') cfg.allowPrivateHost = 'true'
28
+ const result = await getDaqController().testDriver(requireDriverKind(body.driver), cfg)
22
29
  return { test: result }
23
30
  })
@@ -6,10 +6,16 @@ import { getRouterParam } from 'h3'
6
6
  import { resolveUser } from '@/server/api/workshop/caller'
7
7
  import { defineApiHandler } from '@/server/utils/response'
8
8
  import { getRecipeRollBackManager } from '@/server/services/workshop/dcw/recipe-rollback-manager'
9
+ import { getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
10
+ import { AppError, ErrorCodes } from '@/server/utils/errors'
11
+ import { requireLineForResource } from '@/server/services/workshop/line-scope'
9
12
 
10
13
  export default defineApiHandler(async (event) => {
11
- resolveUser(event)
14
+ const user = resolveUser(event)
12
15
  const id = getRouterParam(event, 'id') ?? ''
16
+ const node = getDcwController().byId(id)
17
+ if (!node) throw new AppError(404, ErrorCodes.NOT_FOUND, `控制节点不存在: ${id}`)
18
+ requireLineForResource(user, node.lineId, '数控节点', 'readonly')
13
19
  const ledger = getRecipeRollBackManager().ledger(id)
14
20
  return { ledger }
15
21
  })
@@ -8,11 +8,16 @@ import { resolveUser } from '@/server/api/workshop/caller'
8
8
  import { defineApiHandler } from '@/server/utils/response'
9
9
  import { bindDcwBroadcast, getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
10
10
  import { broadcastSceneEvent } from '@/server/services/workshop/scene-events'
11
+ import { AppError, ErrorCodes } from '@/server/utils/errors'
12
+ import { requireLineForResource } from '@/server/services/workshop/line-scope'
11
13
 
12
14
  export default defineApiHandler(async (event) => {
13
- resolveUser(event)
15
+ const user = resolveUser(event)
14
16
  bindDcwBroadcast(broadcastSceneEvent)
15
17
  const id = getRouterParam(event, 'id') ?? ''
18
+ const node = getDcwController().byId(id)
19
+ if (!node) throw new AppError(404, ErrorCodes.NOT_FOUND, `控制节点不存在: ${id}`)
20
+ requireLineForResource(user, node.lineId, '数控节点', 'readonly')
16
21
  const read = await getDcwController().readNow(id)
17
22
  return { read }
18
23
  })
@@ -1,40 +1,49 @@
1
- /**
2
- * PATCH /api/workshop/dcw/:id —— 单节点参数(名称/驱动/保写周期/量程/启停/落点)。
3
- *
4
- * 鉴权:与 write/test/bind 同口径 requireLineMode(..., 'operate')。
5
- * 本端点可改 driverConfig(落点 host:register)、min/max(直接决定 writeTolerance)、
6
- * holdIntervalMs(保写心跳周期)与 enabled —— 改完之后**网关自己的心跳**就会把
7
- * 该节点的既有设定值写进攻击者指定的目标。即「改参数」等价于「远程写 PLC」,
8
- * 早先此处只有 resolveUser,任何登录用户(零产线授权)都能改任意节点。
9
- */
10
- import { createError, getRouterParam, readBody } from 'h3'
11
- import type { DcwPatchInput } from '@/server/services/workshop/dcw/dcw-controller'
12
- import { resolveUser } from '@/server/api/workshop/caller'
13
- import { defineApiHandler } from '@/server/utils/response'
14
- import { requireLineMode } from '@/server/services/workshop/permissions'
15
- import { bindDcwBroadcast, getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
16
- import { broadcastSceneEvent } from '@/server/services/workshop/scene-events'
17
- import { recordOps } from '@/server/services/workshop/ops/ops'
18
-
19
- export default defineApiHandler(async (event) => {
20
- const user = resolveUser(event)
21
- bindDcwBroadcast(broadcastSceneEvent)
22
- const id = getRouterParam(event, 'id') ?? ''
23
- const body = await readBody<DcwPatchInput>(event) ?? {}
24
- const node0 = getDcwController().byId(id)
25
- if (!node0) throw createError({ statusCode: 404, statusMessage: `控制节点不存在: ${id}` })
26
- // 目标产线:允许本次 PATCH 迁移产线,则新产线也须有操控权(防止把节点搬到无权产线)
27
- const targetLine = body.lineId !== undefined ? String(body.lineId || '') || null : node0.lineId
28
- requireLineMode(user, targetLine, 'operate')
29
- const node = getDcwController().patch(id, body)
30
- // 节点参数/落点/量程/启停变更 = 产线可写面变更,必须进产线日志(含跨线迁移)
31
- const changed = Object.keys(body)
32
- recordOps({
33
- actor: user.id, actorName: user.name, actorKind: 'user',
34
- action: 'dcw.patch', kind: 'line', targetKind: 'dcw-node', targetId: id,
35
- lineId: node.lineId ?? '',
36
- summary: `修改数控节点「${node.name}」(${changed.join('/') || '无变更'})${node0.lineId !== node.lineId ? `:产线 ${node0.lineId || '(无)'} → ${node.lineId || '(无)'}` : ''}`,
37
- detail: { keys: changed, fromLine: node0.lineId ?? '', toLine: node.lineId ?? '' },
38
- })
39
- return { node: node.toView() }
40
- })
1
+ /**
2
+ * PATCH /api/workshop/dcw/:id —— 单节点参数(名称/驱动/保写周期/量程/启停/落点)。
3
+ *
4
+ * 鉴权:与 write/test/bind 同口径 requireLineMode(..., 'operate')。
5
+ * 本端点可改 driverConfig(落点 host:register)、min/max(直接决定 writeTolerance)、
6
+ * holdIntervalMs(保写心跳周期)与 enabled —— 改完之后**网关自己的心跳**就会把
7
+ * 该节点的既有设定值写进攻击者指定的目标。即「改参数」等价于「远程写 PLC」,
8
+ * 早先此处只有 resolveUser,任何登录用户(零产线授权)都能改任意节点。
9
+ */
10
+ import { createError, getRouterParam, readBody } from 'h3'
11
+ import type { DcwPatchInput } from '@/server/services/workshop/dcw/dcw-controller'
12
+ import { resolveUser } from '@/server/api/workshop/caller'
13
+ import { defineApiHandler } from '@/server/utils/response'
14
+ import { AppError } from '@/server/utils/errors'
15
+ import { requireLineMode } from '@/server/services/workshop/permissions'
16
+ import { bindDcwBroadcast, getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
17
+ import { broadcastSceneEvent } from '@/server/services/workshop/scene-events'
18
+ import { recordOps } from '@/server/services/workshop/ops/ops'
19
+
20
+ export default defineApiHandler(async (event) => {
21
+ const user = resolveUser(event)
22
+ bindDcwBroadcast(broadcastSceneEvent)
23
+ const id = getRouterParam(event, 'id') ?? ''
24
+ const body = await readBody<DcwPatchInput>(event) ?? {}
25
+ const node0 = getDcwController().byId(id)
26
+ if (!node0) throw createError({ statusCode: 404, statusMessage: `控制节点不存在: ${id}` })
27
+ // 目标产线:允许本次 PATCH 迁移产线,则新产线也须有操控权(防止把节点搬到无权产线)
28
+ const targetLine = body.lineId !== undefined ? String(body.lineId || '') || null : node0.lineId
29
+ requireLineMode(user, targetLine, 'operate')
30
+ // 落点/安全配置分权(2026-10-28):operate 只能改运行参数,不能改"往哪个设备写、
31
+ // 量程/步限/保持窗、标定函数"。driverConfig 支持 hook/任意 host,等价于代码执行与
32
+ // 跨线重定向,必须与 create 同权(admin)。此前这里只校验 operate。
33
+ const ADMIN_ONLY_FIELDS = ['driver', 'driverConfig', 'transform', 'min', 'max', 'decimals', 'stepLimit', 'writeLockSeconds', 'lineId'] as const
34
+ const deniedFields = ADMIN_ONLY_FIELDS.filter(k => body[k] !== undefined)
35
+ if (deniedFields.length > 0 && user.role !== 'admin') {
36
+ throw new AppError(403, 'DCW_CONFIG_ADMIN_ONLY', `字段「${deniedFields.join('/')}」决定设备落点与安全限界,仅管理员可修改(当前角色 ${user.role})。运行参数(name/enabled/holdIntervalMs/readIntervalMs/semantics/位置)可由产线操控者调整。`)
37
+ }
38
+ const node = getDcwController().patch(id, body)
39
+ // 节点参数/落点/量程/启停变更 = 产线可写面变更,必须进产线日志(含跨线迁移)
40
+ const changed = Object.keys(body)
41
+ recordOps({
42
+ actor: user.id, actorName: user.name, actorKind: 'user',
43
+ action: 'dcw.patch', kind: 'line', targetKind: 'dcw-node', targetId: id,
44
+ lineId: node.lineId ?? '',
45
+ summary: `修改数控节点「${node.name}」(${changed.join('/') || '无变更'})${node0.lineId !== node.lineId ? `:产线 ${node0.lineId || '(无)'} → ${node.lineId || '(无)'}` : ''}`,
46
+ detail: { keys: changed, fromLine: node0.lineId ?? '', toLine: node.lineId ?? '' },
47
+ })
48
+ return { node: node.toView() }
49
+ })
@@ -1,21 +1,25 @@
1
1
  /**
2
2
  * GET /api/workshop/dcw/journal —— 参数变更账本查询(在册历史;append-only)。
3
3
  * 查询参数:nodeId / lineId / source / limit。
4
+ * 2026-10-28:显式 lineId 需只读授权;未指定时按调用者可见产线过滤。
4
5
  */
5
6
  import { getQuery } from 'h3'
6
7
  import { resolveUser } from '@/server/api/workshop/caller'
7
8
  import { defineApiHandler } from '@/server/utils/response'
8
9
  import { getRecipeRollBackManager } from '@/server/services/workshop/dcw/recipe-rollback-manager'
10
+ import { filterRowsByLine, requireLineForResource } from '@/server/services/workshop/line-scope'
9
11
 
10
12
  export default defineApiHandler(async (event) => {
11
- resolveUser(event)
13
+ const user = resolveUser(event)
12
14
  const q = getQuery(event)
15
+ const lineId = q.lineId ? String(q.lineId) : undefined
16
+ if (lineId) requireLineForResource(user, lineId, '产线', 'readonly')
13
17
  const limit = Number(q.limit ?? 100)
14
18
  const anchors = getRecipeRollBackManager().journal({
15
19
  nodeId: q.nodeId ? String(q.nodeId) : undefined,
16
- lineId: q.lineId ? String(q.lineId) : undefined,
20
+ lineId,
17
21
  source: q.source ? String(q.source) : undefined,
18
22
  limit: Number.isFinite(limit) ? Math.min(limit, 500) : 100,
19
23
  })
20
- return { anchors }
24
+ return { anchors: filterRowsByLine(user, anchors, a => a.lineId) }
21
25
  })
@@ -10,6 +10,9 @@ import { readFileSync, statSync } from 'node:fs'
10
10
  import { basename, join, resolve, sep } from 'node:path'
11
11
  import { resolveUser } from '@/server/api/workshop/caller'
12
12
  import { mesArtifactsRoot } from '@/server/services/workshop/mes/mes-hook'
13
+ import { getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
14
+ import { AppError, ErrorCodes } from '@/server/utils/errors'
15
+ import { requireLineForResource } from '@/server/services/workshop/line-scope'
13
16
 
14
17
  const MIME_OF = (name: string): string => {
15
18
  const n = name.toLowerCase()
@@ -22,13 +25,16 @@ const MIME_OF = (name: string): string => {
22
25
  }
23
26
 
24
27
  export default defineEventHandler(async (event) => {
25
- resolveUser(event)
28
+ const user = resolveUser(event)
26
29
  const q = getQuery(event)
27
30
  const nodeId = String(q.node_id ?? '').trim().slice(0, 64)
28
31
  const name = basename(String(q.name ?? '').trim())
29
32
  if (!nodeId || !name) {
30
33
  throw createError({ statusCode: 400, statusMessage: 'node_id 与 name 必填' })
31
34
  }
35
+ const node = getDcwController().byId(nodeId)
36
+ if (!node) throw new AppError(404, ErrorCodes.NOT_FOUND, `控制节点不存在: ${nodeId}`)
37
+ requireLineForResource(user, node.lineId, 'MES 点位', 'readonly')
32
38
  const root = resolve(join(mesArtifactsRoot(), nodeId))
33
39
  const file = resolve(join(root, name))
34
40
  if (file !== root && !file.startsWith(root + sep)) {