agentworkshop 0.7.51 → 0.7.53

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 (482) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +2097 -1955
  2. package/.output/.AgentWorkShop/prompts/host-tools.json +2097 -1955
  3. package/.output/.AgentWorkShop/schema.json +2 -0
  4. package/.output/nitro.json +1 -1
  5. package/.output/public/_nuxt/{D0ldVwl-.js → 77DRSnQv.js} +1 -1
  6. package/.output/public/_nuxt/8oRmGaAV.js +1 -0
  7. package/.output/public/_nuxt/{BPou3U7b.js → BLnLjzka.js} +1 -1
  8. package/.output/public/_nuxt/{CFQyYMEn2.js → BSdJTnk12.js} +1 -1
  9. package/.output/public/_nuxt/{C4lagVdN2.js → BUD1CNvB2.js} +1 -1
  10. package/.output/public/_nuxt/BXR3tgEk.js +1 -0
  11. package/.output/public/_nuxt/{B9QzrmgE.js → BhlRInVa.js} +1 -1
  12. package/.output/public/_nuxt/{DhFv8S2Z.js → BkfA3BbD.js} +1 -1
  13. package/.output/public/_nuxt/{ChGuLxwW2.js → BpcQDwKM2.js} +1 -1
  14. package/.output/public/_nuxt/{DQMbdg4t.js → BwlGxRxA.js} +1 -1
  15. package/.output/public/_nuxt/{Bt2ZL5332.js → C4sQKuhk2.js} +1 -1
  16. package/.output/public/_nuxt/{zh-S_7rN2.js → CBUIODly2.js} +1 -1
  17. package/.output/public/_nuxt/CR-ILcRu2.js +1 -0
  18. package/.output/public/_nuxt/CZLnEnbE.js +14 -0
  19. package/.output/public/_nuxt/{jRTz0hjN2.js → Chxx-DIE2.js} +1 -1
  20. package/.output/public/_nuxt/{BGAaKBeo2.js → CjwxhpwR2.js} +1 -1
  21. package/.output/public/_nuxt/{D89BUtx6.js → CvGYm7w8.js} +1 -1
  22. package/.output/public/_nuxt/{B9BmiUil.js → DAGuPgXa.js} +1 -1
  23. package/.output/public/_nuxt/{DefDtlKK.js → DE6H1HdJ.js} +1 -1
  24. package/.output/public/_nuxt/{DzfVS8N72.js → DFhyhDGa2.js} +1 -1
  25. package/.output/public/_nuxt/{BXx9AxdF2.js → DSqMyLCV2.js} +1 -1
  26. package/.output/public/_nuxt/{asmJ99nX2.js → DV5joWTn2.js} +1 -1
  27. package/.output/public/_nuxt/{DClNt1uS.js → DVOR2pWg.js} +1 -1
  28. package/.output/public/_nuxt/DWsgRq2c.js +1 -0
  29. package/.output/public/_nuxt/{CU-mhG0-.js → DZDi8inD.js} +1 -1
  30. package/.output/public/_nuxt/{DMYYS5sK.js → Dep0Hc9w.js} +1 -1
  31. package/.output/public/_nuxt/{JAM4aNC_.js → DffgG8vT.js} +1 -1
  32. package/.output/public/_nuxt/{CFQSjB1h.js → DlCktWDT.js} +1 -1
  33. package/.output/public/_nuxt/{CP0I2l-6.js → DmzmgYHb.js} +1 -1
  34. package/.output/public/_nuxt/PluginSlot.CGH0vb95.css +1 -0
  35. package/.output/public/_nuxt/{lWYQbIR3.js → WmMwIS4y.js} +1 -1
  36. package/.output/public/_nuxt/{_id_.DamiFT0Q.css → _id_.rdGx-UDx.css} +1 -1
  37. package/.output/public/_nuxt/{BgEDwFMf.js → _kUzq9VF.js} +1 -1
  38. package/.output/public/_nuxt/_wsId_.XjmieZaJ.css +1 -0
  39. package/.output/public/_nuxt/{B7jlMWsz.js → aV6YPjg0.js} +1 -1
  40. package/.output/public/_nuxt/builds/latest.json +1 -1
  41. package/.output/public/_nuxt/builds/meta/5ccc21c2-aba0-4b63-9a13-410e0569e345.json +1 -0
  42. package/.output/public/_nuxt/channel-templates.DkNZg-lF.css +1 -0
  43. package/.output/public/_nuxt/{default.CXb_zoN6.css → default.CyLpQD1C.css} +1 -1
  44. package/.output/public/_nuxt/o9rJf00k.js +1 -0
  45. package/.output/public/_nuxt/sl1EEoCr2.js +21 -0
  46. package/.output/public/robots.txt +3 -0
  47. package/.output/server/chunks/_/binding-authz.mjs +1 -1
  48. package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
  49. package/.output/server/chunks/_/entity.mjs +1 -1
  50. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  51. package/.output/server/chunks/_/nitro.mjs +2268 -1501
  52. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  53. package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
  54. package/.output/server/chunks/build/{PluginSlot-D2WUZgbp.mjs → PluginSlot-CT4YaNrB.mjs} +5 -5
  55. package/.output/server/chunks/build/{PluginSlot-D2WUZgbp.mjs.map → PluginSlot-CT4YaNrB.mjs.map} +1 -1
  56. package/.output/server/chunks/build/TownView-fP9BiALv.mjs +1 -1
  57. package/.output/server/chunks/build/{_id_-BUpQSlzo.mjs → _id_-CK-QFrDV.mjs} +55 -51
  58. package/.output/server/chunks/build/_id_-CK-QFrDV.mjs.map +1 -0
  59. package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs → _wsId_-DdqXzycE.mjs} +320 -202
  60. package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs.map → _wsId_-DdqXzycE.mjs.map} +1 -1
  61. package/.output/server/chunks/build/{agents-CDLcboCv.mjs → agents-DqICy4AL.mjs} +6 -6
  62. package/.output/server/chunks/build/{agents-CDLcboCv.mjs.map → agents-DqICy4AL.mjs.map} +1 -1
  63. package/.output/server/chunks/build/{channel-templates-DjEsj0_v.mjs → channel-templates-gdCLajKy.mjs} +114 -25
  64. package/.output/server/chunks/build/channel-templates-gdCLajKy.mjs.map +1 -0
  65. package/.output/server/chunks/build/daq-N69AOtgw.mjs +1 -1
  66. package/.output/server/chunks/build/dcw-CN9d3Rs7.mjs +1 -1
  67. package/.output/server/chunks/build/{default-DCf9tn1i.mjs → default-CXUe4HL7.mjs} +65 -62
  68. package/.output/server/chunks/build/{default-DCf9tn1i.mjs.map → default-CXUe4HL7.mjs.map} +1 -1
  69. package/.output/server/chunks/build/{pages-rZKH72eC.mjs → pages-CRMeXrxG.mjs} +3 -3
  70. package/.output/server/chunks/build/{pages-rZKH72eC.mjs.map → pages-CRMeXrxG.mjs.map} +1 -1
  71. package/.output/server/chunks/build/{plugins-DSka7-vS.mjs → plugins-NAS9MQ5r.mjs} +2 -2
  72. package/.output/server/chunks/build/{plugins-DSka7-vS.mjs.map → plugins-NAS9MQ5r.mjs.map} +1 -1
  73. package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs → schedules-D8vYHgQ5.mjs} +2 -2
  74. package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs.map → schedules-D8vYHgQ5.mjs.map} +1 -1
  75. package/.output/server/chunks/build/{settings-CAJWvul5.mjs → settings-B7HA-sdb.mjs} +3 -3
  76. package/.output/server/chunks/build/{settings-CAJWvul5.mjs.map → settings-B7HA-sdb.mjs.map} +1 -1
  77. package/.output/server/chunks/build/{teams-DBBvIToa.mjs → teams-wM-MdLv9.mjs} +8 -8
  78. package/.output/server/chunks/build/{teams-DBBvIToa.mjs.map → teams-wM-MdLv9.mjs.map} +1 -1
  79. package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
  80. package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs → useAgentHarnessOptions-BnFCh23W.mjs} +2 -2
  81. package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs.map → useAgentHarnessOptions-BnFCh23W.mjs.map} +1 -1
  82. package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs → useAgentTemplateActions-DsBRUQni.mjs} +2 -2
  83. package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs.map → useAgentTemplateActions-DsBRUQni.mjs.map} +1 -1
  84. package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs → useAgentTemplateForm-DzQ_t2Ue.mjs} +2 -2
  85. package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs.map → useAgentTemplateForm-DzQ_t2Ue.mjs.map} +1 -1
  86. package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs → useAgentTemplatesCatalog-Q7LgG1Af.mjs} +2 -2
  87. package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs.map → useAgentTemplatesCatalog-Q7LgG1Af.mjs.map} +1 -1
  88. package/.output/server/chunks/build/useDaqAddNode-kW7uTSMQ.mjs +1 -1
  89. package/.output/server/chunks/build/useDaqDetailNode-D_vhG0jF.mjs +1 -1
  90. package/.output/server/chunks/build/useDaqDetailParams-JfqHvTxr.mjs +1 -1
  91. package/.output/server/chunks/build/useDaqFilters-BUQtZ82a.mjs +1 -1
  92. package/.output/server/chunks/build/useDaqStream-wOxZcMDA.mjs +1 -1
  93. package/.output/server/chunks/build/useDaqTemplates-BqQRdrIm.mjs +1 -1
  94. package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs → useDashboardData-DWJ6vHjm.mjs} +2 -2
  95. package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs.map → useDashboardData-DWJ6vHjm.mjs.map} +1 -1
  96. package/.output/server/chunks/build/useDcwAddNode-C1HDP3yG.mjs +1 -1
  97. package/.output/server/chunks/build/useDcwStream-D04kCV3J.mjs +1 -1
  98. package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs → useTeamActions-BOLQkYxg.mjs} +2 -2
  99. package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs.map → useTeamActions-BOLQkYxg.mjs.map} +1 -1
  100. package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs → useTeamAddMemberDialog-BCgrLPxI.mjs} +2 -2
  101. package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs.map → useTeamAddMemberDialog-BCgrLPxI.mjs.map} +1 -1
  102. package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs → useTeamCreateDialog-CJk40LqS.mjs} +2 -2
  103. package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs.map → useTeamCreateDialog-CJk40LqS.mjs.map} +1 -1
  104. package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs → useTeamDeployDialog-49hdUXQP.mjs} +2 -2
  105. package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs.map → useTeamDeployDialog-49hdUXQP.mjs.map} +1 -1
  106. package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs → useTeamPluginDialog-Dh-QOoiU.mjs} +2 -2
  107. package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs.map → useTeamPluginDialog-Dh-QOoiU.mjs.map} +1 -1
  108. package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs → useTeamsCatalog-HBSyKt5P.mjs} +2 -2
  109. package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs.map → useTeamsCatalog-HBSyKt5P.mjs.map} +1 -1
  110. package/.output/server/chunks/build/{useWorkshopApi-B1B9vd4m.mjs → useWorkshopApi-C9sTYu1F.mjs} +13 -2
  111. package/.output/server/chunks/build/useWorkshopApi-C9sTYu1F.mjs.map +1 -0
  112. package/.output/server/chunks/build/useWorkshopWs-Bm80bLn7.mjs.map +1 -1
  113. package/.output/server/chunks/routes/api/index.get.mjs +1 -1
  114. package/.output/server/chunks/routes/api/index.post.mjs +14 -3
  115. package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
  116. package/.output/server/chunks/routes/api/mcp/workshop.mjs +43 -14
  117. package/.output/server/chunks/routes/api/mcp/workshop.mjs.map +1 -1
  118. package/.output/server/chunks/routes/api/metrics.mjs +2 -0
  119. package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
  120. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -1
  121. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
  122. package/.output/server/chunks/routes/api/system/backup/list.get.mjs +47 -0
  123. package/.output/server/chunks/routes/api/system/backup/list.get.mjs.map +1 -0
  124. package/.output/server/chunks/routes/api/system/backup/run.post.mjs +35 -0
  125. package/.output/server/chunks/routes/api/system/backup/run.post.mjs.map +1 -0
  126. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +1 -1
  127. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +1 -1
  128. package/.output/server/chunks/routes/api/system/index.get.mjs +1 -1
  129. package/.output/server/chunks/routes/api/system/index.patch.mjs +15 -4
  130. package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
  131. package/.output/server/chunks/routes/api/system/index.post.mjs +1 -1
  132. package/.output/server/chunks/routes/api/system/index2.get.mjs +1 -1
  133. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +1 -1
  134. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +1 -1
  135. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +1 -1
  136. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +15 -3
  137. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
  138. package/.output/server/chunks/routes/api/system/timezone.get.mjs +1 -1
  139. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +14 -3
  140. package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
  141. package/.output/server/chunks/routes/api/users/_id_.get.mjs +1 -1
  142. package/.output/server/chunks/routes/api/users/_id_.put.mjs +14 -3
  143. package/.output/server/chunks/routes/api/users/_id_.put.mjs.map +1 -1
  144. package/.output/server/chunks/routes/api/users/index.get.mjs +1 -1
  145. package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
  146. package/.output/server/chunks/routes/api/users/login.post.mjs +3 -2
  147. package/.output/server/chunks/routes/api/users/login.post.mjs.map +1 -1
  148. package/.output/server/chunks/routes/api/users/logout.post.mjs +1 -1
  149. package/.output/server/chunks/routes/api/users/me.get.mjs +1 -1
  150. package/.output/server/chunks/routes/api/users/register.post.mjs +4 -1
  151. package/.output/server/chunks/routes/api/users/register.post.mjs.map +1 -1
  152. package/.output/server/chunks/routes/api/users/setup-status.get.mjs +1 -1
  153. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +1 -1
  154. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +1 -1
  155. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
  156. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +1 -1
  157. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +19 -15
  158. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs.map +1 -1
  159. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
  160. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +1 -1
  161. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +1 -1
  162. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +1 -1
  163. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs +54 -0
  164. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs.map +1 -0
  165. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +51 -0
  166. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs.map +1 -0
  167. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +1 -1
  168. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +1 -1
  169. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
  170. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +1 -1
  171. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +1 -1
  172. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
  173. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
  174. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +1 -1
  175. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +1 -1
  176. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +1 -1
  177. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +1 -1
  178. package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +1 -1
  179. package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +1 -1
  180. package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +1 -1
  181. package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +1 -1
  182. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +1 -1
  183. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +1 -1
  184. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +1 -1
  185. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +1 -1
  186. package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs +1 -1
  187. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +1 -1
  188. package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +1 -1
  189. package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +1 -1
  190. package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs +1 -1
  191. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +1 -1
  192. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +1 -1
  193. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +1 -1
  194. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +1 -1
  195. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +1 -1
  196. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +1 -1
  197. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +1 -1
  198. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +1 -1
  199. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +1 -1
  200. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs +1 -1
  201. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs +1 -1
  202. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs +1 -1
  204. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +1 -1
  205. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +1 -1
  206. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
  207. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/caller.mjs +1 -1
  210. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +10 -4
  211. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs.map +1 -1
  212. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
  213. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
  214. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +1 -1
  215. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
  216. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
  217. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs +1 -1
  218. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +1 -1
  219. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
  220. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
  221. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +1 -1
  222. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
  223. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  224. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +1 -1
  225. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  226. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -1
  227. package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs +37 -0
  228. package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs.map +1 -0
  229. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs +1 -1
  231. package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs +1 -1
  232. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +1 -1
  233. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
  234. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +4 -4
  235. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +1 -1
  236. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +1 -1
  237. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +1 -1
  238. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +1 -1
  239. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
  240. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +1 -1
  241. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +1 -1
  242. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +1 -1
  243. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +1 -1
  244. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +1 -1
  245. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +1 -1
  246. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +1 -1
  247. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +1 -1
  248. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
  249. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
  250. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
  251. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +1 -1
  252. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
  253. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
  254. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +1 -1
  255. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +1 -1
  256. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
  257. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
  258. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
  259. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +1 -1
  260. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
  261. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +1 -1
  262. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
  263. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
  264. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
  265. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +1 -1
  266. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
  267. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +1 -1
  268. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
  269. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
  270. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
  271. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +1 -1
  272. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
  273. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +6 -1
  274. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
  275. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
  276. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
  277. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
  278. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +1 -1
  279. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
  280. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
  281. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +1 -1
  282. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +1 -1
  283. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +1 -1
  284. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +1 -1
  285. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
  286. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
  287. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
  288. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
  289. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
  290. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +1 -1
  291. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +3 -3
  292. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs.map +1 -1
  293. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
  294. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +1 -1
  295. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +1 -1
  296. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +1 -1
  297. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +1 -1
  298. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
  299. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
  300. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  301. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  302. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +1 -1
  303. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
  304. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
  305. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +1 -1
  306. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +1 -1
  307. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +14 -2
  308. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs.map +1 -1
  309. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  310. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  311. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  312. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  313. package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
  314. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  315. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +1 -1
  316. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
  317. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
  318. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +1 -1
  319. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +1 -1
  320. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +1 -1
  321. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +1 -1
  322. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
  323. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
  324. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +1 -1
  325. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
  326. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
  327. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +1 -1
  328. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
  329. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +3 -3
  330. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  331. package/.output/server/chunks/routes/api/workshop/index9.post.mjs +1 -1
  332. package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs +1 -1
  333. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  334. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  335. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  336. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  337. package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs +1 -1
  338. package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs +1 -1
  339. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
  340. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
  341. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
  342. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +1 -1
  343. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
  344. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
  345. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +1 -1
  346. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +1 -1
  347. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
  348. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +4 -1
  349. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs.map +1 -1
  350. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
  351. package/.output/server/chunks/routes/renderer.mjs +2 -2
  352. package/.output/server/chunks/virtual/entry.mjs +350 -52
  353. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  354. package/.output/server/package.json +1 -1
  355. package/README-zh.md +7 -3
  356. package/README.md +11 -5
  357. package/app/components/app-header/HitlBell.vue +9 -9
  358. package/app/components/dcw/DcwAddNodeModal.vue +3 -3
  359. package/app/components/dcw/DcwNodesTable.vue +4 -4
  360. package/app/components/dcw/DcwRecipeEditModal.vue +2 -2
  361. package/app/components/workshop/ChatMemberPanel.vue +39 -38
  362. package/app/components/workshop/ChatTimeline.vue +33 -24
  363. package/app/components/workshop/Composer.vue +7 -7
  364. package/app/components/workshop/NotificationCenter.vue +22 -13
  365. package/app/components/workshop/PluginSlot.vue +1 -1
  366. package/app/components/workshop/TaskInspectorDrawer.vue +5 -5
  367. package/app/components/workshop/blocks/ClusterTool.vue +1 -1
  368. package/app/components/workshop/composer/ComposerToolbar.vue +2 -2
  369. package/app/components/workshop/composer/MentionMenu.vue +1 -1
  370. package/app/components/workshop/composer/ReplyChip.vue +2 -2
  371. package/app/components/workshop/composer/StatusChip.vue +7 -7
  372. package/app/components/workshop/console/LineOperationsPanel.vue +15 -14
  373. package/app/components/workshop/lanes/LaneHeader.vue +5 -3
  374. package/app/components/workshop/session-list/ChannelSettingsModal.vue +43 -1
  375. package/app/composables/useCodeCopy.ts +16 -2
  376. package/app/composables/workshop/useWorkshopApi.ts +11 -2
  377. package/app/pages/workshop/channel-templates.vue +43 -4
  378. package/app/stores/workshop/notifications.ts +43 -17
  379. package/config.yml +1 -1
  380. package/docs/cli.en.md +3 -3
  381. package/docs/cli.md +2 -2
  382. package/docs/plugins.en.md +1 -1
  383. package/docs/plugins.md +1 -1
  384. package/docs/sdk.en.md +1 -1
  385. package/docs/sdk.md +1 -1
  386. package/i18n/dicts/_en.json +1551 -1557
  387. package/i18n/dicts/_en2.json +300 -300
  388. package/i18n/dicts/_en4.json +114 -115
  389. package/i18n/dicts/agentLanesView.json +61 -57
  390. package/i18n/dicts/appHeader.json +17 -7
  391. package/i18n/dicts/channelSessionList.json +51 -48
  392. package/i18n/dicts/chat.json +79 -0
  393. package/i18n/dicts/clusterTool.json +4 -3
  394. package/i18n/dicts/composer.json +38 -38
  395. package/i18n/dicts/ctpl.json +37 -32
  396. package/i18n/dicts/dcwDetail.json +219 -209
  397. package/i18n/dicts/lineOps.json +14 -0
  398. package/i18n/dicts/multiChannelView.json +13 -13
  399. package/i18n/dicts/notifications.json +13 -0
  400. package/i18n/dicts/taskInspectorDrawer.json +25 -19
  401. package/i18n/locales/en.ts +157 -8
  402. package/i18n/locales/zh-CN.ts +157 -8
  403. package/package.json +1 -1
  404. package/public/robots.txt +3 -0
  405. package/scripts/_audit/kb-team-mock-e2e.mjs +146 -0
  406. package/scripts/_audit/kb-team-omp-e2e.mjs +229 -0
  407. package/server/api/mcp/workshop.ts +8 -1
  408. package/server/api/metrics.ts +4 -1
  409. package/server/api/plugins/[name]/[...path].ts +4 -3
  410. package/server/api/system/backup/list.get.ts +32 -0
  411. package/server/api/system/backup/run.post.ts +21 -0
  412. package/server/api/system/settings/index.patch.ts +12 -2
  413. package/server/api/system/settings/reset.post.ts +11 -2
  414. package/server/api/users/[id].delete.ts +9 -2
  415. package/server/api/users/[id].put.ts +9 -2
  416. package/server/api/users/index.post.ts +9 -2
  417. package/server/api/users/login.post.ts +3 -3
  418. package/server/api/users/register.post.ts +11 -1
  419. package/server/api/workshop/a2a/[agentId]/rpc/index.post.ts +23 -13
  420. package/server/api/workshop/agent-tools/bindings/grant.post.ts +45 -0
  421. package/server/api/workshop/agent-tools/bindings/revoke.post.ts +42 -0
  422. package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +8 -1
  423. package/server/api/workshop/channels/[id]/line.put.ts +30 -0
  424. package/server/api/workshop/dcw/line/query.get.ts +6 -0
  425. package/server/api/workshop/dcw/recipes/[id]/revert.post.ts +3 -2
  426. package/server/api/workshop/fs/dirs.get.ts +19 -1
  427. package/server/api/workshop/ops-logs/index.get.ts +3 -2
  428. package/server/api/workshop/users/register.post.ts +7 -0
  429. package/server/mcp/workshop-server.ts +36 -13
  430. package/server/middleware/00-security-headers.ts +38 -0
  431. package/server/middleware/01-rate-guard.ts +101 -0
  432. package/server/plugins/backup.ts +56 -1
  433. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +18 -11
  434. package/server/repositories/user.repository.ts +10 -5
  435. package/server/services/user.service.ts +24 -1
  436. package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +7 -2
  437. package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +4 -2
  438. package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +15 -2
  439. package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +104 -0
  440. package/server/services/workshop/agents/industrial/index.ts +1 -1
  441. package/server/services/workshop/agents/industrial/ops-tools.ts +168 -26
  442. package/server/services/workshop/agents/node-bindings.repo.ts +10 -1
  443. package/server/services/workshop/agents/node-delegation.ts +150 -0
  444. package/server/services/workshop/agents/tool-classes.ts +4 -0
  445. package/server/services/workshop/aml/dataset-builder.ts +4 -2
  446. package/server/services/workshop/aml/job-orchestrator/process.ts +1 -0
  447. package/server/services/workshop/aml/job-orchestrator/shared.ts +2 -0
  448. package/server/services/workshop/aml/job-orchestrator/start-job.ts +5 -2
  449. package/server/services/workshop/db/channel.repo.ts +11 -1
  450. package/server/services/workshop/db/database/migrations.ts +2 -0
  451. package/server/services/workshop/db/database/rows.ts +2 -0
  452. package/server/services/workshop/db/database/seed.ts +30 -0
  453. package/server/services/workshop/dcw/dcw-controller/recipes.ts +60 -4
  454. package/server/services/workshop/dcw/dcw-controller/write.ts +35 -6
  455. package/server/services/workshop/dcw/dcw-recipe.repo.ts +4 -3
  456. package/server/services/workshop/dcw/param-map.repo.ts +3 -0
  457. package/server/services/workshop/plugins/host/init.mjs +9 -1
  458. package/server/services/workshop/plugins/host/load.mjs +2 -2
  459. package/server/services/workshop/runtime/manager/admin-channel.ts +27 -1
  460. package/server/services/workshop/runtime/manager/channel-templates.ts +27 -2
  461. package/server/services/workshop/runtime/manager/runtime-wiring.ts +17 -1
  462. package/server/services/workshop/runtime/manager/types.ts +2 -0
  463. package/shared/config/schema.json +2 -0
  464. package/.output/public/_nuxt/8FXd9As6.js +0 -1
  465. package/.output/public/_nuxt/BOmDHp5L.js +0 -14
  466. package/.output/public/_nuxt/BWU1pvLL.js +0 -1
  467. package/.output/public/_nuxt/CdIsmU5a2.js +0 -21
  468. package/.output/public/_nuxt/D0SNhlnt.js +0 -1
  469. package/.output/public/_nuxt/DnH9SRMW2.js +0 -1
  470. package/.output/public/_nuxt/ON2x-t6n.js +0 -1
  471. package/.output/public/_nuxt/PluginSlot.DmjNbrcX.css +0 -1
  472. package/.output/public/_nuxt/_wsId_.DkrQkT6r.css +0 -1
  473. package/.output/public/_nuxt/builds/meta/912eb5bb-670e-4cc8-b21d-7fc097723466.json +0 -1
  474. package/.output/public/_nuxt/channel-templates.DplM1pJ3.css +0 -1
  475. package/.output/server/chunks/build/_id_-BUpQSlzo.mjs.map +0 -1
  476. package/.output/server/chunks/build/channel-templates-DjEsj0_v.mjs.map +0 -1
  477. package/.output/server/chunks/build/useWorkshopApi-B1B9vd4m.mjs.map +0 -1
  478. package/scripts/.chk-tok +0 -1
  479. package/scripts/.retrain-body.json +0 -1
  480. package/scripts/.retrain3-body.json +0 -1
  481. package/scripts/.rt-tok +0 -1
  482. package/scripts/.rt3-tok +0 -1
@@ -17,10 +17,26 @@ import { fanoutQuery, windowOf } from './audit-query'
17
17
  // 运维日志 / Recipe 变更史查询(Agent 自查面:负责产线 scoped)
18
18
  // ================================================================
19
19
 
20
- /** Agent 负责范围 = 绑定节点的全集(节点 id 集 + 这些节点所属产线集);无绑定 = 无范围 */
21
- export function agentOpsScope(agentId: string): { lineIds: string[], nodeIds: Set<string> } | null {
20
+ /** v18:频道绑定产线(只读扩权)——经全局 manager 读;manager 未装配/未绑定 = null */
21
+ function channelBoundLineId(agentId: string): string | null {
22
+ try {
23
+ const g = globalThis as typeof globalThis & {
24
+ __workshopManager?: { channelLineBindingOf(id: string): string | null }
25
+ }
26
+ return g.__workshopManager?.channelLineBindingOf(agentId) ?? null
27
+ }
28
+ catch {
29
+ return null
30
+ }
31
+ }
32
+
33
+ /** Agent 负责范围 = 绑定节点的全集(节点 id 集 + 这些节点所属产线集;写权限依据)
34
+ * ∪ 频道绑定产线(boundLineIds;v18 只读扩权:日志/配方史/上下文可读,写仍走节点授权)。 */
35
+ export function agentOpsScope(agentId: string): { lineIds: string[], nodeIds: Set<string>, boundLineIds: string[] } | null {
22
36
  const bindings = getAgentNodeBindingRepo().byAgent(agentId)
23
- if (bindings.length === 0) return null
37
+ const boundLine = channelBoundLineId(agentId)
38
+ const boundLineIds = boundLine ? [boundLine] : []
39
+ if (bindings.length === 0 && boundLineIds.length === 0) return null
24
40
  const lineIds = new Set<string>()
25
41
  const nodeIds = new Set<string>()
26
42
  for (const b of bindings) {
@@ -31,7 +47,17 @@ export function agentOpsScope(agentId: string): { lineIds: string[], nodeIds: Se
31
47
  }
32
48
  catch { /* 节点刚被删等情况忽略 */ }
33
49
  }
34
- return { lineIds: [...lineIds], nodeIds }
50
+ return { lineIds: [...lineIds], nodeIds, boundLineIds }
51
+ }
52
+
53
+ /** 读工具的可见产线全集 = 节点授权线 ∪ 频道绑定线(去重) */
54
+ function readableLineIds(scope: { lineIds: string[], boundLineIds: string[] }): string[] {
55
+ return [...new Set([...scope.lineIds, ...scope.boundLineIds])]
56
+ }
57
+
58
+ /** 产线展示标注:仅频道绑定(非节点授权)的线标注只读来源 */
59
+ function lineTag(lid: string, scope: { lineIds: string[], boundLineIds: string[] }): string {
60
+ return scope.lineIds.includes(lid) ? '' : '(频道绑定,只读)'
35
61
  }
36
62
 
37
63
  /** 配方参数的节点失效态(数据一致性展示/Agent 提示共用):null=正常 */
@@ -63,19 +89,20 @@ export async function toolOpsLog(agentId: string, args: {
63
89
  const audit = getOps()?.audit
64
90
  if (!audit) return { text: '审计仓储未装配(服务未就绪),请稍后重试。', isError: true }
65
91
  const scope = agentOpsScope(agentId)
66
- if (!scope) return { text: '你尚未绑定任何工业节点,无日志可查(日志权限跟随节点绑定)。', isError: true }
92
+ if (!scope) return { text: '你尚未绑定任何工业节点,所在频道也未绑定产线,无日志可查(日志权限跟随节点绑定或频道绑线)。', isError: true }
67
93
  const nodeId = String(args.node_id ?? '').trim()
68
94
  const lineId = String(args.line_id ?? '').trim()
95
+ const readable = readableLineIds(scope)
69
96
  if (nodeId && !scope.nodeIds.has(nodeId))
70
97
  return { text: `无权查询节点 ${nodeId} 的日志(仅可查自己绑定的节点;用 my_industrial_nodes 查看绑定)。`, isError: true }
71
- if (lineId && !scope.lineIds.includes(lineId))
72
- return { text: `无权查询产线 ${lineId} 的日志(你的负责产线:${scope.lineIds.join(', ') || '(绑定节点均未分配产线)'})。`, isError: true }
98
+ if (lineId && !readable.includes(lineId))
99
+ return { text: `无权查询产线 ${lineId} 的日志(你的可读产线:${readable.join(', ') || '(无)'})。`, isError: true }
73
100
  const kind = String(args.kind ?? '').trim() || undefined
74
101
  const actorKind = String(args.actor_kind ?? '').trim() || undefined
75
102
  const mine = args.mine === true || args.mine === 'true'
76
103
  const { minutes, limit, from } = windowOf(args)
77
104
 
78
- const lines = lineId ? [lineId] : scope.lineIds
105
+ const lines = lineId ? [lineId] : readable
79
106
  let rows = fanoutQuery(audit, lines, lid => ({ lineId: lid, kind, actorKind, actor: mine ? agentId : undefined, from, limit }))
80
107
  if (nodeId) rows = rows.filter(r => r.targetId === nodeId)
81
108
  rows.sort((a, b) => String(b.at).localeCompare(String(a.at)))
@@ -86,7 +113,7 @@ export async function toolOpsLog(agentId: string, args: {
86
113
  const src = OPS_ACTOR_LABEL[String(r.actorKind)] ?? String(r.actorKind)
87
114
  return `- [${fmtAuditAt(String(r.at))}] 来源=${src} 操作者=${String(r.actorName) || String(r.actor)} | ${String(r.action)} | ${String(r.summary)}`
88
115
  })
89
- const scopeNote = lineId ? `产线 ${lineId}` : `负责产线 ${scope.lineIds.length} 条`
116
+ const scopeNote = lineId ? `产线 ${lineId}` : `可读产线 ${readable.length} 条`
90
117
  return {
91
118
  text: `运维日志(${scopeNote},近 ${minutes} 分钟,${rows.length} 条,新→旧):\n${body.join('\n')}\n\n说明:来源=Agent 的操作者格式为「Channel名/成员名」;需要节点级参数值变更史用 dcw_journal,配方下发/回退专门视图用 recipe_log。`,
92
119
  }
@@ -103,14 +130,15 @@ export async function toolRecipeLog(agentId: string, args: {
103
130
  const audit = getOps()?.audit
104
131
  if (!audit) return { text: '审计仓储未装配(服务未就绪),请稍后重试。', isError: true }
105
132
  const scope = agentOpsScope(agentId)
106
- if (!scope) return { text: '你尚未绑定任何工业节点,无 Recipe 历史可查(权限跟随节点绑定)。', isError: true }
133
+ if (!scope) return { text: '你尚未绑定任何工业节点,所在频道也未绑定产线,无 Recipe 历史可查(权限跟随节点绑定或频道绑线)。', isError: true }
107
134
  const lineId = String(args.line_id ?? '').trim()
108
- if (lineId && !scope.lineIds.includes(lineId))
109
- return { text: `无权查询产线 ${lineId} 的 Recipe 历史(你的负责产线:${scope.lineIds.join(', ') || '(无)'})。`, isError: true }
135
+ const readable = readableLineIds(scope)
136
+ if (lineId && !readable.includes(lineId))
137
+ return { text: `无权查询产线 ${lineId} 的 Recipe 历史(你的可读产线:${readable.join(', ') || '(无)'})。`, isError: true }
110
138
  const recipeId = String(args.recipe_id ?? '').trim() || undefined
111
139
  const { minutes, limit, from } = windowOf(args)
112
140
 
113
- const lines = lineId ? [lineId] : scope.lineIds
141
+ const lines = lineId ? [lineId] : readable
114
142
  const rows = fanoutQuery(audit, lines, lid => [
115
143
  { lineId: lid, kind: 'recipe', recipeId, from, limit },
116
144
  { lineId: lid, kind: 'rollback', recipeId, from, limit },
@@ -131,9 +159,8 @@ export async function toolRecipeLog(agentId: string, args: {
131
159
  : action
132
160
  return `- [${fmtAuditAt(String(r.at))}] ${tag} 来源=${src} 操作者=${String(r.actorName) || String(r.actor)} | ${String(r.summary)}${r.recipeId ? `(配方 ${String(r.recipeId).slice(0, 8)})` : ''}`
133
161
  })
134
- return {
135
- text: `Recipe 变更史(${lineId ? `产线 ${lineId}` : `负责产线 ${scope.lineIds.length} 条`},近 ${minutes} 分钟,${rows.length} 条,新→旧):\n${body.join('\n')}\n\n说明:配方下发=整批参数写命令;优化开窗=单次设定变更(含 Agent 假设);回退执行=已恢复基线值。节点级参数值逐笔历史用 dcw_journal(node_id)。`,
136
- }
162
+ const text = `Recipe 变更史(${lineId ? `产线 ${lineId}` : `可读产线 ${readable.length} 条`},近 ${minutes} 分钟,${rows.length} 条,新→旧):\n${body.join('\n')}\n\n说明:配方下发=整批参数写命令;优化开窗=单次设定变更(含 Agent 假设);回退执行=已恢复基线值。节点级参数值逐笔历史用 dcw_journal(node_id)。`
163
+ return { text }
137
164
  }
138
165
 
139
166
  // ================================================================
@@ -145,11 +172,12 @@ export async function toolRecipeLog(agentId: string, args: {
145
172
  * 配方目标 vs PLC 当前值对照、lastGood 批次。 */
146
173
  export async function toolLineContext(agentId: string, args: { line_id?: string } = {}): Promise<{ text: string, isError?: boolean }> {
147
174
  const scope = agentOpsScope(agentId)
148
- if (!scope) return { text: '你尚未绑定任何工业节点,暂无产线上下文(请先在数字孪生界面绑定节点)。' }
175
+ if (!scope) return { text: '你尚未绑定任何工业节点,所在频道也未绑定产线,暂无产线上下文(可在频道设置绑定产线获得只读上下文,或在数字孪生界面绑定节点)。' }
149
176
  const wanted = String(args.line_id ?? '').trim()
150
- const lineIds = wanted ? [wanted] : scope.lineIds
151
- if (wanted && !scope.lineIds.includes(wanted)) {
152
- return { text: `产线 ${wanted} 不在你的负责范围(你绑定节点覆盖的产线:${scope.lineIds.join(', ') || '无'})。`, isError: true }
177
+ const readable = readableLineIds(scope)
178
+ const lineIds = wanted ? [wanted] : readable
179
+ if (wanted && !readable.includes(wanted)) {
180
+ return { text: `产线 ${wanted} 不在你的可读范围(节点授权与频道绑定覆盖:${readable.join(', ') || '无'})。`, isError: true }
153
181
  }
154
182
  if (lineIds.length === 0) return { text: '你绑定的节点均未分配产线(未挂线的节点没有产线/产品/配方上下文)。' }
155
183
 
@@ -159,7 +187,7 @@ export async function toolLineContext(agentId: string, args: { line_id?: string
159
187
  const run = getActiveLineRun(lid)
160
188
  const recipe = run?.recipeId ? getDcwController().listRecipes().find(r => r.id === run.recipeId) : undefined
161
189
  const parts: string[] = []
162
- parts.push(`■ 产线 ${line?.name ?? lid}(${lid})· 状态:${run ? '运行中' : '待机/停线'}`)
190
+ parts.push(`■ 产线 ${line?.name ?? lid}(${lid})${lineTag(lid, scope)} · 状态:${run ? '运行中' : '待机/停线'}`)
163
191
  if (run) {
164
192
  parts.push(` 活动批次 ${run.runId.slice(0, 8)} · 产品「${run.productName}」(${run.productId}) · 开跑 ${run.startedAt.slice(11, 19)} · 已打标 ${run.taggedSamples} 样本`)
165
193
  }
@@ -210,7 +238,7 @@ export async function toolLineContext(agentId: string, args: { line_id?: string
210
238
  sections.push(parts.join('\n'))
211
239
  }
212
240
  return {
213
- text: `你控制的产线全景(${sections.length} 条):\n\n${sections.join('\n\n')}\n\n说明:配方目标=开跑批次冻结的工艺窗口;PLC 当前值=实时读数。把验证过的最佳参数固化到配方用 recipe_update;回退配方到稳定版本用 recipe_rollback;逐节点参数变更史用 dcw_journal;配方版本史用 recipe_versions。`,
241
+ text: `你控制的产线全景(${sections.length} 条):\n\n${sections.join('\n\n')}\n\n说明:配方目标=开跑批次冻结的工艺窗口;PLC 当前值=实时读数;(频道绑定,只读)= 该线来自频道绑定的只读授权,可看日志/配方/状态,参数下发仍需节点授权。把验证过的最佳参数固化到配方用 recipe_update;回退配方到稳定版本用 recipe_rollback;逐节点参数变更史用 dcw_journal;配方版本史用 recipe_versions。`,
214
242
  }
215
243
  }
216
244
 
@@ -221,9 +249,11 @@ export async function toolRecipeVersions(agentId: string, args: { recipe_id?: st
221
249
  if (!recipeId) return { text: 'recipe_id 必填(line_context 可看到当前配方的 id)。', isError: true }
222
250
  const recipe = getDcwController().listRecipes().find(r => r.id === recipeId)
223
251
  if (!recipe) return { text: `配方 ${recipeId} 不存在。`, isError: true }
252
+ // 只读面:节点授权线 ∪ 频道绑定线均可看版本史(回退走 toolRecipeRollback 的写门)
224
253
  const scope = agentOpsScope(agentId)
225
- if (!scope || !recipe.lineId || !scope.lineIds.includes(recipe.lineId)) {
226
- return { text: `无权查看配方 ${recipeId} 的版本史(该配方不在你负责的产线上)。`, isError: true }
254
+ const readable = scope ? readableLineIds(scope) : []
255
+ if (!recipe.lineId || !readable.includes(recipe.lineId)) {
256
+ return { text: `无权查看配方 ${recipeId} 的版本史(该配方不在你可读的产线上)。`, isError: true }
227
257
  }
228
258
  const rows = getDcwController().recipeVersions(recipeId)
229
259
  const limit = Math.min(Number(args.limit) || 20, 50)
@@ -327,16 +357,19 @@ export async function toolRecipeUpdate(agentId: string, args: {
327
357
  }
328
358
 
329
359
  /** 工具:recipe_rollback —— 回退配方参数到稳定版本(指定历史版本或已知良好批次快照)。
330
- * 生成新版本(非破坏,历史保留);不改运行中 PLC 当前值。 */
360
+ * 生成新版本(非破坏,历史保留);不改运行中 PLC 当前值。
361
+ * v19 dispatch=true = **统一回退**:定义回退 + 该版本参数整批重下发到 PLC(批次级恢复)。 */
331
362
  export async function toolRecipeRollback(agentId: string, args: {
332
363
  recipe_id?: string
333
364
  version?: number | string
334
365
  to_last_good?: boolean | string
366
+ dispatch?: boolean | string
335
367
  reason?: string
336
368
  }): Promise<{ text: string, isError?: boolean }> {
337
369
  const recipeId = String(args.recipe_id ?? '').trim()
338
370
  const reason = String(args.reason ?? '').trim()
339
371
  const toLastGood = args.to_last_good === true || args.to_last_good === 'true'
372
+ const dispatch = args.dispatch === true || args.dispatch === 'true'
340
373
  const version = Number(args.version)
341
374
  if (!recipeId) return { text: 'recipe_id 必填。', isError: true }
342
375
  if (!reason) return { text: 'reason 必填:回退必须说明原因(如优化翻车/越限),便于版本史追溯。', isError: true }
@@ -351,6 +384,20 @@ export async function toolRecipeRollback(agentId: string, args: {
351
384
  return { text: `不能回退到 v${version}(当前已是 v${recipe.version ?? 1};回退目标是更早的版本)。`, isError: true }
352
385
  }
353
386
  try {
387
+ if (dispatch) {
388
+ const { recipe: updated, run } = await getDcwController().rollbackRecipeAndDispatch(recipeId, {
389
+ version: toLastGood ? undefined : version,
390
+ toLastGood,
391
+ by: 'agent',
392
+ actorName: agentBadgeLabel(agentId),
393
+ actor: agentId,
394
+ description: reason,
395
+ })
396
+ const okN = run.results.filter(r => r.ok).length
397
+ return {
398
+ text: `统一回退完成:配方「${updated.name}」已生成 v${updated.version ?? 1},参数恢复为目标版本(${toLastGood ? '已知良好批次冻结' : `v${version}`}),并已整批重下发到 PLC(${okN}/${run.results.length} 参数成功);原因:${reason}。\n用 daq_query 复测确认恢复效果;版本史用 recipe_versions 复核。`,
399
+ }
400
+ }
354
401
  const updated = getDcwController().revertRecipe(recipeId, {
355
402
  version: toLastGood ? undefined : version,
356
403
  toLastGood,
@@ -361,10 +408,105 @@ export async function toolRecipeRollback(agentId: string, args: {
361
408
  description: reason,
362
409
  })
363
410
  return {
364
- text: `回退完成:配方「${updated.name}」已生成 v${updated.version ?? 1},参数恢复为目标版本(${toLastGood ? '已知良好批次冻结' : `v${version}`});原因:${reason}。\n运行中批次不受影响(仍按开跑冻结参数);新参数下次开跑生效。版本史用 recipe_versions 复核。`,
411
+ text: `回退完成:配方「${updated.name}」已生成 v${updated.version ?? 1},参数恢复为目标版本(${toLastGood ? '已知良好批次冻结' : `v${version}`});原因:${reason}。\n注意:仅回退了配方定义,运行中 PLC 未变动;要把恢复参数写入产线(统一回退),用 recipe_rollback 并带 dispatch=true。版本史用 recipe_versions 复核。`,
365
412
  }
366
413
  }
367
414
  catch (err) {
368
415
  return { text: `回退失败:${err instanceof Error ? err.message : String(err)}`, isError: true }
369
416
  }
370
417
  }
418
+
419
+ /** 工具:recipe_trial —— 多参数候选整批试验下发(v19 配方链路核心)。
420
+ * 候选值只覆盖列出节点(**必须是自己绑定的数控节点**);整批一次落产线,**不写配方版本** ——
421
+ * 复测判读:有进步/达标 → recipe_update 固化(同 id 版本+1);劣化 → recipe_rollback(dispatch=true) 统一回退。
422
+ * 受同线试验节拍卡控(默认 ≥5 分钟,防连发震荡);四层限界(量程∩参数∩产品)照常拦截。 */
423
+ export async function toolRecipeTrial(agentId: string, args: {
424
+ recipe_id?: string
425
+ params?: Array<{ node_id?: string, value?: number | string }>
426
+ hypothesis?: string
427
+ }): Promise<{ text: string, isError?: boolean }> {
428
+ const recipeId = String(args.recipe_id ?? '').trim()
429
+ const hypothesis = String(args.hypothesis ?? '').trim()
430
+ if (!recipeId) return { text: 'recipe_id 必填(line_context 可看到当前配方 id)。', isError: true }
431
+ if (!hypothesis) return { text: 'hypothesis 必填:试验必须声明依据(知识库条目/数据分析结论),便于审计追溯。', isError: true }
432
+ const list = (args.params ?? []).filter(p => p && String(p.node_id ?? '').trim() && Number.isFinite(Number(p.value)))
433
+ .map(p => ({ nodeId: String(p.node_id).trim(), value: Number(p.value) }))
434
+ if (list.length === 0) return { text: 'params 至少提供一条 {node_id, value}(value 必须为数字);试验的意义就是多参数一次整批改动。', isError: true }
435
+ const recipe = getDcwController().listRecipes().find(r => r.id === recipeId)
436
+ if (!recipe) return { text: `配方 ${recipeId} 不存在。`, isError: true }
437
+ const repo = getAgentNodeBindingRepo()
438
+ for (const p of list) {
439
+ const node = getDcwController().byId(p.nodeId)
440
+ if (!node) return { text: `节点 ${p.nodeId} 已删除,不能纳入试验。`, isError: true }
441
+ if (node.lineId !== recipe.lineId) return { text: `节点「${node.name}」不在配方「${recipe.name}」所在产线,不可混入试验。`, isError: true }
442
+ if (!node.enabled) return { text: `节点「${node.name}」已停用,试验被拒。`, isError: true }
443
+ if (!repo.find(agentId, p.nodeId, 'dcw')) {
444
+ return { text: `无权试验节点「${node.name}」(仅可改自己绑定的数控节点;缺授权找 lead 用 team_grant_nodes 授予)。`, isError: true }
445
+ }
446
+ }
447
+ try {
448
+ const run = await getDcwController().applyRecipe(recipeId, { overrides: list, trial: true })
449
+ const okN = run.results.filter(r => r.ok).length
450
+ // 批次级留痕:试验动作入审计(逐参数写已有 write-audit;这里是"一次试验"粒度)
451
+ try {
452
+ const { recordOps } = await import('../../ops/ops')
453
+ recordOps({
454
+ actor: agentId, actorName: agentBadgeLabel(agentId), actorKind: 'agent',
455
+ action: 'recipe.trial', kind: 'recipe', targetKind: 'recipe', targetId: recipeId, recipeId, lineId: recipe.lineId,
456
+ summary: `配方试验整批下发(${okN}/${run.results.length} 成功,批次 ${run.id.slice(0, 8)}):${list.map(p => `${p.nodeId.slice(0, 8)}→${p.value}`).join(';')} | 假设:${hypothesis}`,
457
+ })
458
+ }
459
+ catch { /* 审计失败不影响试验结果 */ }
460
+ const changed = run.results.map((r) => {
461
+ const node = r.nodeId ? getDcwController().byId(r.nodeId) : undefined
462
+ const reason = r.ok ? '' : `(${String(r.message).slice(0, 60)})`
463
+ return `${node?.name ?? r.templateRef}→${r.value}${node?.unit ?? ''}${r.ok ? '' : ` 被拒${reason}`}`
464
+ }).join(';')
465
+ return {
466
+ text: `试验已整批下发(${okN}/${run.results.length} 成功,批次 ${run.id.slice(0, 8)}):${changed}。假设:${hypothesis}。注意:本次试验**未写入配方版本** —— 等待工艺惯性后 daq_query 复测判读:有进步/达标 → recipe_update 把候选值固化进配方(同 id 版本+1);无进步/劣化 → recipe_rollback(recipe_id, dispatch=true, reason=…) 统一回退(定义回退+PLC 整批恢复)。`,
467
+ }
468
+ }
469
+ catch (err) {
470
+ return { text: `试验下发失败:${err instanceof Error ? err.message : String(err)}`, isError: true }
471
+ }
472
+ }
473
+
474
+ /** 工具:recipe_apply —— 把配方当前已固化参数整批下发到产线(改配方(recipe_update)之后用)。
475
+ * 与 recipe_trial 的区别:apply 下发的是**已固化版本**(无候选覆盖),用于"改配方 → 配方下发"链路的正式下发。 */
476
+ export async function toolRecipeApply(agentId: string, args: {
477
+ recipe_id?: string
478
+ reason?: string
479
+ }): Promise<{ text: string, isError?: boolean }> {
480
+ const recipeId = String(args.recipe_id ?? '').trim()
481
+ if (!recipeId) return { text: 'recipe_id 必填(line_context 可看到当前配方 id)。', isError: true }
482
+ const recipe = getDcwController().listRecipes().find(r => r.id === recipeId)
483
+ if (!recipe) return { text: `配方 ${recipeId} 不存在。`, isError: true }
484
+ const scope = agentOpsScope(agentId)
485
+ if (!scope || !recipe.lineId || !scope.lineIds.includes(recipe.lineId)) {
486
+ return { text: `无权下发配方 ${recipeId}(该配方不在你负责的产线上)。`, isError: true }
487
+ }
488
+ const boundInRecipe = getAgentNodeBindingRepo().byAgent(agentId)
489
+ .some(b => b.kind === 'dcw' && recipe.params.some(p => p.nodeId === b.nodeId))
490
+ if (!boundInRecipe) {
491
+ return { text: `无权下发配方 ${recipeId}(需持有该配方至少一个数控节点的授权;找 lead 用 team_grant_nodes 授予)。`, isError: true }
492
+ }
493
+ try {
494
+ const run = await getDcwController().applyRecipe(recipeId)
495
+ const okN = run.results.filter(r => r.ok).length
496
+ try {
497
+ const { recordOps } = await import('../../ops/ops')
498
+ recordOps({
499
+ actor: agentId, actorName: agentBadgeLabel(agentId), actorKind: 'agent',
500
+ action: 'recipe.apply', kind: 'recipe', targetKind: 'recipe', targetId: recipeId, recipeId, lineId: recipe.lineId,
501
+ summary: `Agent 整批下发配方 v${recipe.version ?? 1}(${okN}/${run.results.length} 参数成功,批次 ${run.id.slice(0, 8)})${args.reason ? ` | 原因:${String(args.reason).trim()}` : ''}`,
502
+ })
503
+ }
504
+ catch { /* 审计失败不影响下发结果 */ }
505
+ return {
506
+ text: `配方「${recipe.name}」v${recipe.version ?? 1} 已整批下发(${okN}/${run.results.length} 参数成功,批次 ${run.id.slice(0, 8)})。用 daq_query 复测确认工艺响应。`,
507
+ }
508
+ }
509
+ catch (err) {
510
+ return { text: `配方下发失败:${err instanceof Error ? err.message : String(err)}`, isError: true }
511
+ }
512
+ }
@@ -38,6 +38,10 @@ export interface AgentNodeBinding {
38
38
  kind: AgentNodeBindingKind
39
39
  mode: AgentNodeBindingMode
40
40
  tuning?: AgentNodeBindingTuning
41
+ /** 委派来源:lead 经 team_grant_nodes / dispatch_task(grant_node_ids) 授予时 = lead 成员实例 id */
42
+ grantedByAgentId?: string
43
+ /** 委派时间(ISO;仅委派产生的绑定携带) */
44
+ grantedAt?: string
41
45
  createdAt: string
42
46
  }
43
47
 
@@ -83,7 +87,7 @@ export class AgentNodeBindingRepo {
83
87
  return this.list.find(b => b.agentId === agentId && b.nodeId === nodeId && b.kind === kind)
84
88
  }
85
89
 
86
- bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode, tuning?: AgentNodeBindingTuning): AgentNodeBinding {
90
+ bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode, tuning?: AgentNodeBindingTuning, provenance?: { grantedByAgentId?: string }): AgentNodeBinding {
87
91
  if (!agentId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'agentId 必填')
88
92
  if (!nodeId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'nodeId 必填')
89
93
  if (kind !== 'dcw' && kind !== 'daq') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知节点类型: ${kind}`)
@@ -92,6 +96,10 @@ export class AgentNodeBindingRepo {
92
96
  if (prev) {
93
97
  prev.mode = mode
94
98
  if (tuning !== undefined) prev.tuning = normalizeTuning(tuning)
99
+ if (provenance?.grantedByAgentId) {
100
+ prev.grantedByAgentId = provenance.grantedByAgentId
101
+ prev.grantedAt = new Date().toISOString()
102
+ }
95
103
  this.flush()
96
104
  return prev
97
105
  }
@@ -102,6 +110,7 @@ export class AgentNodeBindingRepo {
102
110
  kind,
103
111
  mode,
104
112
  ...(tuning ? { tuning: normalizeTuning(tuning) } : {}),
113
+ ...(provenance?.grantedByAgentId ? { grantedByAgentId: provenance.grantedByAgentId, grantedAt: new Date().toISOString() } : {}),
105
114
  createdAt: new Date().toISOString(),
106
115
  }
107
116
  this.list.push(binding)
@@ -0,0 +1,150 @@
1
+ /**
2
+ * node-delegation —— lead → worker 节点权限委派(核心校验面,宿主工具与 REST 共用)。
3
+ *
4
+ * 语义:lead 把**自己已绑定**的 DAQ/DCW 节点授权给同 Channel 的 worker:
5
+ * - 节点必须是 leader 本人已有绑定的节点(权限不可超越授予者,hard rule);
6
+ * - 目标必须是同 Channel 的启用 worker(不能授给 lead 自己/其他频道成员);
7
+ * - 绑定逐 (nodeId, kind) 复制 leader 的 kind/tuning;mode 缺省随 leader,
8
+ * 显式传 mode 可覆盖(auto↔manual 均允许 —— mode 只决定是否走 HITL,不放大节点面);
9
+ * - 委派产生的绑定带 grantedByAgentId/grantedAt 溯源;撤销时 leader 只能撤
10
+ * 「自己授予的」或「自己也持有的」绑定。
11
+ * 校验全部 fail-closed:任何节点不满足 → 整单拒绝并列出明细,不做部分授予。
12
+ */
13
+ import { AppError, ErrorCodes } from '../../../utils/errors'
14
+ import { getAgentNodeBindingRepo, type AgentNodeBinding, type AgentNodeBindingMode } from './node-bindings.repo'
15
+
16
+ export interface DelegationMember {
17
+ id: string
18
+ role: 'lead' | 'worker'
19
+ enabled?: number
20
+ }
21
+
22
+ export interface DelegationGrantInput {
23
+ leaderAgentId: string
24
+ channelId: string
25
+ targetAgentId: string
26
+ nodeIds: string[]
27
+ members: DelegationMember[]
28
+ mode?: AgentNodeBindingMode
29
+ }
30
+
31
+ export interface DelegationPlanItem {
32
+ nodeId: string
33
+ kind: 'dcw' | 'daq'
34
+ mode: AgentNodeBindingMode
35
+ tuning?: AgentNodeBinding['tuning']
36
+ }
37
+
38
+ export interface DelegationPlan {
39
+ targetAgentId: string
40
+ grants: DelegationPlanItem[]
41
+ }
42
+
43
+ /** 前置校验 + 逐节点计划(fail-closed;不落库 —— 落库由调用方按计划执行) */
44
+ export function planDelegation(input: DelegationGrantInput): DelegationPlan {
45
+ const leaderAgentId = String(input.leaderAgentId ?? '')
46
+ const targetAgentId = String(input.targetAgentId ?? '')
47
+ const nodeIds = (Array.isArray(input.nodeIds) ? input.nodeIds : []).map(x => String(x ?? '').trim()).filter(Boolean)
48
+ if (!leaderAgentId || !targetAgentId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'leaderAgentId 与 targetAgentId 必填')
49
+ if (!nodeIds.length) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'node_ids 必填(要授予的节点 id 列表)')
50
+
51
+ const members = Array.isArray(input.members) ? input.members : []
52
+ const leader = members.find(m => m.id === leaderAgentId)
53
+ if (!leader || leader.role !== 'lead') {
54
+ throw new AppError(403, 'DELEGATION_NOT_LEAD', '只有频道 lead 可以分发节点权限')
55
+ }
56
+ const target = members.find(m => m.id === targetAgentId)
57
+ if (!target) {
58
+ throw new AppError(404, ErrorCodes.NOT_FOUND, `目标成员不在本频道: ${targetAgentId}(需传频道成员实例 id,可经 GET /api/workshop/channels/:id/agents 获取)`)
59
+ }
60
+ if (target.id === leaderAgentId) {
61
+ throw new AppError(400, ErrorCodes.VALIDATION_ERROR, '不能把节点权限授予 lead 自己(绑定面在 lead 名下已存在)')
62
+ }
63
+ if (target.role !== 'worker') {
64
+ throw new AppError(400, ErrorCodes.VALIDATION_ERROR, '只能向 worker 分发节点权限')
65
+ }
66
+ if (target.enabled === 0) {
67
+ throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `目标成员已被停用: ${targetAgentId}`)
68
+ }
69
+
70
+ const repo = getAgentNodeBindingRepo()
71
+ const leaderBindings = repo.byAgent(leaderAgentId)
72
+ const missing: string[] = []
73
+ const grants: DelegationPlanItem[] = []
74
+ const seen = new Set<string>()
75
+ for (const nodeId of nodeIds) {
76
+ if (seen.has(nodeId)) continue
77
+ seen.add(nodeId)
78
+ const held = leaderBindings.filter(b => b.nodeId === nodeId)
79
+ if (!held.length) {
80
+ missing.push(nodeId)
81
+ continue
82
+ }
83
+ for (const h of held) {
84
+ grants.push({
85
+ nodeId,
86
+ kind: h.kind,
87
+ mode: input.mode ?? h.mode,
88
+ tuning: h.tuning ? { ...h.tuning } : undefined,
89
+ })
90
+ }
91
+ }
92
+ if (missing.length) {
93
+ throw new AppError(403, 'DELEGATION_NOT_OWNED', `以下节点不在 lead 的绑定面内,拒绝授予(权限不可超越授予者):${missing.join('、')}`)
94
+ }
95
+ return { targetAgentId, grants }
96
+ }
97
+
98
+ /** 执行授予:按计划逐条落库(已存在的绑定更新 mode/溯源,不重复建行) */
99
+ export function applyDelegation(plan: DelegationPlan, leaderAgentId: string): AgentNodeBinding[] {
100
+ const repo = getAgentNodeBindingRepo()
101
+ return plan.grants.map((g) => {
102
+ const binding = repo.bind(plan.targetAgentId, g.nodeId, g.kind, g.mode, g.tuning, { grantedByAgentId: leaderAgentId })
103
+ return binding
104
+ })
105
+ }
106
+
107
+ export interface DelegationRevokeInput {
108
+ leaderAgentId: string
109
+ targetAgentId: string
110
+ nodeIds: string[]
111
+ members: DelegationMember[]
112
+ }
113
+
114
+ /** 撤销授予:可撤「自己授予的」或「自己也持有的」绑定;两者都不是 → 拒绝该节点 */
115
+ export function revokeDelegation(input: DelegationRevokeInput): Array<{ nodeId: string, kind: 'dcw' | 'daq', revoked: boolean }> {
116
+ const leaderAgentId = String(input.leaderAgentId ?? '')
117
+ const targetAgentId = String(input.targetAgentId ?? '')
118
+ const nodeIds = (Array.isArray(input.nodeIds) ? input.nodeIds : []).map(x => String(x ?? '').trim()).filter(Boolean)
119
+ if (!leaderAgentId || !targetAgentId || !nodeIds.length) {
120
+ throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'leaderAgentId / targetAgentId / node_ids 必填')
121
+ }
122
+ const members = Array.isArray(input.members) ? input.members : []
123
+ const leader = members.find(m => m.id === leaderAgentId)
124
+ if (!leader || leader.role !== 'lead') {
125
+ throw new AppError(403, 'DELEGATION_NOT_LEAD', '只有频道 lead 可以撤销节点权限')
126
+ }
127
+ if (!members.some(m => m.id === targetAgentId)) {
128
+ throw new AppError(404, ErrorCodes.NOT_FOUND, `目标成员不在本频道: ${targetAgentId}`)
129
+ }
130
+
131
+ const repo = getAgentNodeBindingRepo()
132
+ const leaderNodes = new Set(repo.byAgent(leaderAgentId).map(b => b.nodeId))
133
+ const out: Array<{ nodeId: string, kind: 'dcw' | 'daq', revoked: boolean }> = []
134
+ for (const nodeId of nodeIds) {
135
+ const workerBindings = repo.byAgent(targetAgentId).filter(b => b.nodeId === nodeId)
136
+ if (!workerBindings.length) {
137
+ for (const kind of ['dcw', 'daq'] as const) out.push({ nodeId, kind, revoked: false })
138
+ continue
139
+ }
140
+ for (const b of workerBindings) {
141
+ const allowed = b.grantedByAgentId === leaderAgentId || leaderNodes.has(nodeId)
142
+ if (!allowed) {
143
+ out.push({ nodeId, kind: b.kind, revoked: false })
144
+ continue
145
+ }
146
+ out.push({ nodeId, kind: b.kind, revoked: repo.unbind(b.id) })
147
+ }
148
+ }
149
+ return out
150
+ }
@@ -16,6 +16,8 @@ export const LEAD_ONLY_TOOL_NAMES = new Set([
16
16
  'update_team_agent',
17
17
  'remove_team_agent',
18
18
  'aml_model_promote',
19
+ 'team_grant_nodes',
20
+ 'team_revoke_nodes',
19
21
  ])
20
22
 
21
23
  /** Hybrid Twin 的直接写入工具:权限面(permission-scope)与目录注入面(host-tool-bridge/catalog)fail-closed 同源于本集合;dispatch 分发层的同款守卫为并行在飞改动,待其收敛后接入(勿在此重复第三份清单)。 */
@@ -25,4 +27,6 @@ export const HYBRID_TWIN_DIRECT_WRITE_TOOL_NAMES = new Set([
25
27
  'dcw_rollback',
26
28
  'recipe_update',
27
29
  'recipe_rollback',
30
+ 'recipe_trial',
31
+ 'recipe_apply',
28
32
  ])
@@ -194,7 +194,9 @@ export async function buildDataset(spec: AmlDatasetSpec, by: { id: string, kind:
194
194
  continue
195
195
  }
196
196
 
197
- // 公共网格:[max(t0), min(t1)];逐节点最近邻对齐,网格点缺失计 NaN
197
+ // 公共网格:[max(t0), min(t1)];逐节点最近邻对齐,网格点缺失计 NaN。
198
+ // 全节点查空(如该 run 采样缺失/时序库丢数)时 g0/g1 保持 ±Infinity,
199
+ // 必须按丢弃处理 —— 否则 steps=Infinity 会把网格循环推到 RangeError(500)。
198
200
  let g0 = -Infinity
199
201
  let g1 = Infinity
200
202
  for (const n of order) {
@@ -206,7 +208,7 @@ export async function buildDataset(spec: AmlDatasetSpec, by: { id: string, kind:
206
208
  g0 = Math.max(g0, first.at)
207
209
  g1 = Math.min(g1, last.at)
208
210
  }
209
- const steps = g1 > g0 ? Math.floor((g1 - g0) / beat) + 1 : 0
211
+ const steps = Number.isFinite(g0) && Number.isFinite(g1) && g1 > g0 ? Math.floor((g1 - g0) / beat) + 1 : 0
210
212
  if (steps < spec.window.historySteps + spec.window.horizonSteps + 2) {
211
213
  runsDropped.push({ runId: run.id, reason: `有效网格 ${steps} 步不足一个窗口` })
212
214
  continue
@@ -96,5 +96,6 @@ export function handleProtocolLine(run: RunningJob, rawLine: string): void {
96
96
  }
97
97
  else if (evt.type === 'error' && evt.message) {
98
98
  pushLog(run, `[error] ${evt.message}`)
99
+ run.lastProtocolError = String(evt.message).slice(0, 300) // 结题失败原因优先用它(见 start-job 评估段)
99
100
  }
100
101
  }
@@ -31,6 +31,8 @@ export interface RunningJob {
31
31
  logLines: string[]
32
32
  protocolBadLines: number
33
33
  killed: boolean
34
+ /** 最近一条 ##AML error 协议消息(评估器的人读失败原因走 stdout;stderr 尾常为空) */
35
+ lastProtocolError?: string
34
36
  }
35
37
 
36
38
  export interface OrchestratorState {
@@ -140,8 +140,11 @@ export async function startJob(row: AmlJobRow): Promise<void> {
140
140
  const exit2 = await runPython(run, vpy, [evalScript, '--job', join(jobDir, 'job.json')], jobDir)
141
141
  if (run.killed) return
142
142
  if (exit2.code !== 0) {
143
- rt.repo.job.fail(row.id, 'failed', `评估失败:${lastErrLine(exit2.errTail)}(永久错误不重试)`, new Date().toISOString())
144
- experimentFail(run, `评估失败:${lastErrLine(exit2.errTail)}`)
143
+ // 失败原因优先取评估器的 ##AML error 协议消息(如「test 切分为空…」,人读可操作);
144
+ // stderr 尾兜底 —— 评估器把错误走 stdout 协议行时 errTail 常为空,只给 "exit" 无从排查。
145
+ const reason = run.lastProtocolError || lastErrLine(exit2.errTail)
146
+ rt.repo.job.fail(row.id, 'failed', `评估失败:${reason}(永久错误不重试)`, new Date().toISOString())
147
+ experimentFail(run, `评估失败:${reason}`)
145
148
  finishRun(run)
146
149
  return
147
150
  }
@@ -11,7 +11,7 @@ import type { DatabaseSync } from 'node:sqlite'
11
11
  import type { ChannelRow } from './database'
12
12
 
13
13
  /** 查询列(蛇形列名 → 驼峰行字段) */
14
- const COLS = 'id, name, description, scenario_prompt AS scenarioPrompt, llm_json AS llmJson, lead_agent_id AS leadAgentId, workspace, enabled, owner_user_id AS ownerUserId, visibility, join_policy AS joinPolicy, approval_policy AS approvalPolicy, chat_enabled AS chatEnabled, version, created_at AS createdAt, updated_at AS updatedAt'
14
+ const COLS = 'id, name, description, scenario_prompt AS scenarioPrompt, llm_json AS llmJson, lead_agent_id AS leadAgentId, workspace, enabled, owner_user_id AS ownerUserId, visibility, join_policy AS joinPolicy, approval_policy AS approvalPolicy, chat_enabled AS chatEnabled, version, line_id AS lineId, created_at AS createdAt, updated_at AS updatedAt'
15
15
 
16
16
  export interface ChannelCreateInput {
17
17
  name: string
@@ -99,6 +99,7 @@ export function createChannelRepo(db: DatabaseSync) {
99
99
  approvalPolicy: input.approvalPolicy ?? 'owner_only',
100
100
  chatEnabled: input.chatEnabled ?? 0,
101
101
  version: 1,
102
+ lineId: '',
102
103
  createdAt: now,
103
104
  updatedAt: now,
104
105
  }
@@ -189,5 +190,14 @@ export function createChannelRepo(db: DatabaseSync) {
189
190
  remove(id: string): void {
190
191
  removeStmt.run(id)
191
192
  },
193
+
194
+ /** v18:绑定/解绑产线(lineId=''=解绑)。只读扩权面:成员可读该线日志/配方/历史/状态;写仍走节点授权。 */
195
+ setLine(id: string, lineId: string): ChannelRow | undefined {
196
+ const current = selectById.get(id) as unknown as ChannelRow | undefined
197
+ if (!current) return undefined
198
+ db.prepare('UPDATE channels SET line_id = ?, updated_at = ? WHERE id = ?')
199
+ .run(lineId, new Date().toISOString(), id)
200
+ return { ...current, lineId, updatedAt: new Date().toISOString() }
201
+ },
192
202
  }
193
203
  }
@@ -10,6 +10,8 @@ export function migrateGroupChatV17(db: DatabaseSync): void {
10
10
  migrateAddColumn(db, 'channels', 'approval_policy', 'TEXT NOT NULL DEFAULT \'owner_only\'')
11
11
  migrateAddColumn(db, 'channels', 'chat_enabled', 'INTEGER NOT NULL DEFAULT 0')
12
12
  migrateAddColumn(db, 'channels', 'version', 'INTEGER NOT NULL DEFAULT 1')
13
+ // v18:Channel 绑定产线(空串=未绑定;只读扩权面,见 ops-tools agentOpsScope)
14
+ migrateAddColumn(db, 'channels', 'line_id', 'TEXT NOT NULL DEFAULT \'\'')
13
15
  // 规范化非法值(历史手改/测试数据):未知取值一律回落到最保守档,不放宽权限
14
16
  db.exec(`UPDATE channels SET visibility = 'private' WHERE visibility NOT IN ('private', 'public')`)
15
17
  db.exec(`UPDATE channels SET join_policy = 'owner_approve' WHERE join_policy NOT IN ('open', 'owner_approve')`)
@@ -27,6 +27,8 @@ export interface ChannelRow {
27
27
  chatEnabled: number
28
28
  /** v17 乐观锁版本(每次设置变更 +1) */
29
29
  version: number
30
+ /** v18 绑定产线(空串=未绑定;只读扩权:成员可读该线日志/配方/历史/状态,写仍走节点授权) */
31
+ lineId: string
30
32
  createdAt: string
31
33
  updatedAt: string
32
34
  }