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.
- package/.AgentWorkShop/prompts/host-tools.json +2097 -1955
- package/.output/.AgentWorkShop/prompts/host-tools.json +2097 -1955
- package/.output/.AgentWorkShop/schema.json +2 -0
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{D0ldVwl-.js → 77DRSnQv.js} +1 -1
- package/.output/public/_nuxt/8oRmGaAV.js +1 -0
- package/.output/public/_nuxt/{BPou3U7b.js → BLnLjzka.js} +1 -1
- package/.output/public/_nuxt/{CFQyYMEn2.js → BSdJTnk12.js} +1 -1
- package/.output/public/_nuxt/{C4lagVdN2.js → BUD1CNvB2.js} +1 -1
- package/.output/public/_nuxt/BXR3tgEk.js +1 -0
- package/.output/public/_nuxt/{B9QzrmgE.js → BhlRInVa.js} +1 -1
- package/.output/public/_nuxt/{DhFv8S2Z.js → BkfA3BbD.js} +1 -1
- package/.output/public/_nuxt/{ChGuLxwW2.js → BpcQDwKM2.js} +1 -1
- package/.output/public/_nuxt/{DQMbdg4t.js → BwlGxRxA.js} +1 -1
- package/.output/public/_nuxt/{Bt2ZL5332.js → C4sQKuhk2.js} +1 -1
- package/.output/public/_nuxt/{zh-S_7rN2.js → CBUIODly2.js} +1 -1
- package/.output/public/_nuxt/CR-ILcRu2.js +1 -0
- package/.output/public/_nuxt/CZLnEnbE.js +14 -0
- package/.output/public/_nuxt/{jRTz0hjN2.js → Chxx-DIE2.js} +1 -1
- package/.output/public/_nuxt/{BGAaKBeo2.js → CjwxhpwR2.js} +1 -1
- package/.output/public/_nuxt/{D89BUtx6.js → CvGYm7w8.js} +1 -1
- package/.output/public/_nuxt/{B9BmiUil.js → DAGuPgXa.js} +1 -1
- package/.output/public/_nuxt/{DefDtlKK.js → DE6H1HdJ.js} +1 -1
- package/.output/public/_nuxt/{DzfVS8N72.js → DFhyhDGa2.js} +1 -1
- package/.output/public/_nuxt/{BXx9AxdF2.js → DSqMyLCV2.js} +1 -1
- package/.output/public/_nuxt/{asmJ99nX2.js → DV5joWTn2.js} +1 -1
- package/.output/public/_nuxt/{DClNt1uS.js → DVOR2pWg.js} +1 -1
- package/.output/public/_nuxt/DWsgRq2c.js +1 -0
- package/.output/public/_nuxt/{CU-mhG0-.js → DZDi8inD.js} +1 -1
- package/.output/public/_nuxt/{DMYYS5sK.js → Dep0Hc9w.js} +1 -1
- package/.output/public/_nuxt/{JAM4aNC_.js → DffgG8vT.js} +1 -1
- package/.output/public/_nuxt/{CFQSjB1h.js → DlCktWDT.js} +1 -1
- package/.output/public/_nuxt/{CP0I2l-6.js → DmzmgYHb.js} +1 -1
- package/.output/public/_nuxt/PluginSlot.CGH0vb95.css +1 -0
- package/.output/public/_nuxt/{lWYQbIR3.js → WmMwIS4y.js} +1 -1
- package/.output/public/_nuxt/{_id_.DamiFT0Q.css → _id_.rdGx-UDx.css} +1 -1
- package/.output/public/_nuxt/{BgEDwFMf.js → _kUzq9VF.js} +1 -1
- package/.output/public/_nuxt/_wsId_.XjmieZaJ.css +1 -0
- package/.output/public/_nuxt/{B7jlMWsz.js → aV6YPjg0.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/5ccc21c2-aba0-4b63-9a13-410e0569e345.json +1 -0
- package/.output/public/_nuxt/channel-templates.DkNZg-lF.css +1 -0
- package/.output/public/_nuxt/{default.CXb_zoN6.css → default.CyLpQD1C.css} +1 -1
- package/.output/public/_nuxt/o9rJf00k.js +1 -0
- package/.output/public/_nuxt/sl1EEoCr2.js +21 -0
- package/.output/public/robots.txt +3 -0
- package/.output/server/chunks/_/binding-authz.mjs +1 -1
- package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
- package/.output/server/chunks/_/entity.mjs +1 -1
- package/.output/server/chunks/_/host-bindings.mjs +1 -1
- package/.output/server/chunks/_/nitro.mjs +2268 -1501
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
- package/.output/server/chunks/build/{PluginSlot-D2WUZgbp.mjs → PluginSlot-CT4YaNrB.mjs} +5 -5
- package/.output/server/chunks/build/{PluginSlot-D2WUZgbp.mjs.map → PluginSlot-CT4YaNrB.mjs.map} +1 -1
- package/.output/server/chunks/build/TownView-fP9BiALv.mjs +1 -1
- package/.output/server/chunks/build/{_id_-BUpQSlzo.mjs → _id_-CK-QFrDV.mjs} +55 -51
- package/.output/server/chunks/build/_id_-CK-QFrDV.mjs.map +1 -0
- package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs → _wsId_-DdqXzycE.mjs} +320 -202
- package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs.map → _wsId_-DdqXzycE.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-CDLcboCv.mjs → agents-DqICy4AL.mjs} +6 -6
- package/.output/server/chunks/build/{agents-CDLcboCv.mjs.map → agents-DqICy4AL.mjs.map} +1 -1
- package/.output/server/chunks/build/{channel-templates-DjEsj0_v.mjs → channel-templates-gdCLajKy.mjs} +114 -25
- package/.output/server/chunks/build/channel-templates-gdCLajKy.mjs.map +1 -0
- package/.output/server/chunks/build/daq-N69AOtgw.mjs +1 -1
- package/.output/server/chunks/build/dcw-CN9d3Rs7.mjs +1 -1
- package/.output/server/chunks/build/{default-DCf9tn1i.mjs → default-CXUe4HL7.mjs} +65 -62
- package/.output/server/chunks/build/{default-DCf9tn1i.mjs.map → default-CXUe4HL7.mjs.map} +1 -1
- package/.output/server/chunks/build/{pages-rZKH72eC.mjs → pages-CRMeXrxG.mjs} +3 -3
- package/.output/server/chunks/build/{pages-rZKH72eC.mjs.map → pages-CRMeXrxG.mjs.map} +1 -1
- package/.output/server/chunks/build/{plugins-DSka7-vS.mjs → plugins-NAS9MQ5r.mjs} +2 -2
- package/.output/server/chunks/build/{plugins-DSka7-vS.mjs.map → plugins-NAS9MQ5r.mjs.map} +1 -1
- package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs → schedules-D8vYHgQ5.mjs} +2 -2
- package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs.map → schedules-D8vYHgQ5.mjs.map} +1 -1
- package/.output/server/chunks/build/{settings-CAJWvul5.mjs → settings-B7HA-sdb.mjs} +3 -3
- package/.output/server/chunks/build/{settings-CAJWvul5.mjs.map → settings-B7HA-sdb.mjs.map} +1 -1
- package/.output/server/chunks/build/{teams-DBBvIToa.mjs → teams-wM-MdLv9.mjs} +8 -8
- package/.output/server/chunks/build/{teams-DBBvIToa.mjs.map → teams-wM-MdLv9.mjs.map} +1 -1
- package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
- package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs → useAgentHarnessOptions-BnFCh23W.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs.map → useAgentHarnessOptions-BnFCh23W.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs → useAgentTemplateActions-DsBRUQni.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs.map → useAgentTemplateActions-DsBRUQni.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs → useAgentTemplateForm-DzQ_t2Ue.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs.map → useAgentTemplateForm-DzQ_t2Ue.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs → useAgentTemplatesCatalog-Q7LgG1Af.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs.map → useAgentTemplatesCatalog-Q7LgG1Af.mjs.map} +1 -1
- package/.output/server/chunks/build/useDaqAddNode-kW7uTSMQ.mjs +1 -1
- package/.output/server/chunks/build/useDaqDetailNode-D_vhG0jF.mjs +1 -1
- package/.output/server/chunks/build/useDaqDetailParams-JfqHvTxr.mjs +1 -1
- package/.output/server/chunks/build/useDaqFilters-BUQtZ82a.mjs +1 -1
- package/.output/server/chunks/build/useDaqStream-wOxZcMDA.mjs +1 -1
- package/.output/server/chunks/build/useDaqTemplates-BqQRdrIm.mjs +1 -1
- package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs → useDashboardData-DWJ6vHjm.mjs} +2 -2
- package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs.map → useDashboardData-DWJ6vHjm.mjs.map} +1 -1
- package/.output/server/chunks/build/useDcwAddNode-C1HDP3yG.mjs +1 -1
- package/.output/server/chunks/build/useDcwStream-D04kCV3J.mjs +1 -1
- package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs → useTeamActions-BOLQkYxg.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs.map → useTeamActions-BOLQkYxg.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs → useTeamAddMemberDialog-BCgrLPxI.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs.map → useTeamAddMemberDialog-BCgrLPxI.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs → useTeamCreateDialog-CJk40LqS.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs.map → useTeamCreateDialog-CJk40LqS.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs → useTeamDeployDialog-49hdUXQP.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs.map → useTeamDeployDialog-49hdUXQP.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs → useTeamPluginDialog-Dh-QOoiU.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs.map → useTeamPluginDialog-Dh-QOoiU.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs → useTeamsCatalog-HBSyKt5P.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs.map → useTeamsCatalog-HBSyKt5P.mjs.map} +1 -1
- package/.output/server/chunks/build/{useWorkshopApi-B1B9vd4m.mjs → useWorkshopApi-C9sTYu1F.mjs} +13 -2
- package/.output/server/chunks/build/useWorkshopApi-C9sTYu1F.mjs.map +1 -0
- package/.output/server/chunks/build/useWorkshopWs-Bm80bLn7.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post.mjs +14 -3
- package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/mcp/workshop.mjs +43 -14
- package/.output/server/chunks/routes/api/mcp/workshop.mjs.map +1 -1
- package/.output/server/chunks/routes/api/metrics.mjs +2 -0
- package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/backup/list.get.mjs +47 -0
- package/.output/server/chunks/routes/api/system/backup/list.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/system/backup/run.post.mjs +35 -0
- package/.output/server/chunks/routes/api/system/backup/run.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/system/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/index.patch.mjs +15 -4
- package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/system/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +1 -1
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +15 -3
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/timezone.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs +14 -3
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.put.mjs +14 -3
- package/.output/server/chunks/routes/api/users/_id_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/login.post.mjs +3 -2
- package/.output/server/chunks/routes/api/users/login.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/logout.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/me.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/register.post.mjs +4 -1
- package/.output/server/chunks/routes/api/users/register.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/setup-status.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +19 -15
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs +54 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +51 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/caller.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +10 -4
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs +37 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +6 -1
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +3 -3
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +14 -2
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs +3 -3
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +4 -1
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
- package/.output/server/chunks/routes/renderer.mjs +2 -2
- package/.output/server/chunks/virtual/entry.mjs +350 -52
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/package.json +1 -1
- package/README-zh.md +7 -3
- package/README.md +11 -5
- package/app/components/app-header/HitlBell.vue +9 -9
- package/app/components/dcw/DcwAddNodeModal.vue +3 -3
- package/app/components/dcw/DcwNodesTable.vue +4 -4
- package/app/components/dcw/DcwRecipeEditModal.vue +2 -2
- package/app/components/workshop/ChatMemberPanel.vue +39 -38
- package/app/components/workshop/ChatTimeline.vue +33 -24
- package/app/components/workshop/Composer.vue +7 -7
- package/app/components/workshop/NotificationCenter.vue +22 -13
- package/app/components/workshop/PluginSlot.vue +1 -1
- package/app/components/workshop/TaskInspectorDrawer.vue +5 -5
- package/app/components/workshop/blocks/ClusterTool.vue +1 -1
- package/app/components/workshop/composer/ComposerToolbar.vue +2 -2
- package/app/components/workshop/composer/MentionMenu.vue +1 -1
- package/app/components/workshop/composer/ReplyChip.vue +2 -2
- package/app/components/workshop/composer/StatusChip.vue +7 -7
- package/app/components/workshop/console/LineOperationsPanel.vue +15 -14
- package/app/components/workshop/lanes/LaneHeader.vue +5 -3
- package/app/components/workshop/session-list/ChannelSettingsModal.vue +43 -1
- package/app/composables/useCodeCopy.ts +16 -2
- package/app/composables/workshop/useWorkshopApi.ts +11 -2
- package/app/pages/workshop/channel-templates.vue +43 -4
- package/app/stores/workshop/notifications.ts +43 -17
- package/config.yml +1 -1
- package/docs/cli.en.md +3 -3
- package/docs/cli.md +2 -2
- package/docs/plugins.en.md +1 -1
- package/docs/plugins.md +1 -1
- package/docs/sdk.en.md +1 -1
- package/docs/sdk.md +1 -1
- package/i18n/dicts/_en.json +1551 -1557
- package/i18n/dicts/_en2.json +300 -300
- package/i18n/dicts/_en4.json +114 -115
- package/i18n/dicts/agentLanesView.json +61 -57
- package/i18n/dicts/appHeader.json +17 -7
- package/i18n/dicts/channelSessionList.json +51 -48
- package/i18n/dicts/chat.json +79 -0
- package/i18n/dicts/clusterTool.json +4 -3
- package/i18n/dicts/composer.json +38 -38
- package/i18n/dicts/ctpl.json +37 -32
- package/i18n/dicts/dcwDetail.json +219 -209
- package/i18n/dicts/lineOps.json +14 -0
- package/i18n/dicts/multiChannelView.json +13 -13
- package/i18n/dicts/notifications.json +13 -0
- package/i18n/dicts/taskInspectorDrawer.json +25 -19
- package/i18n/locales/en.ts +157 -8
- package/i18n/locales/zh-CN.ts +157 -8
- package/package.json +1 -1
- package/public/robots.txt +3 -0
- package/scripts/_audit/kb-team-mock-e2e.mjs +146 -0
- package/scripts/_audit/kb-team-omp-e2e.mjs +229 -0
- package/server/api/mcp/workshop.ts +8 -1
- package/server/api/metrics.ts +4 -1
- package/server/api/plugins/[name]/[...path].ts +4 -3
- package/server/api/system/backup/list.get.ts +32 -0
- package/server/api/system/backup/run.post.ts +21 -0
- package/server/api/system/settings/index.patch.ts +12 -2
- package/server/api/system/settings/reset.post.ts +11 -2
- package/server/api/users/[id].delete.ts +9 -2
- package/server/api/users/[id].put.ts +9 -2
- package/server/api/users/index.post.ts +9 -2
- package/server/api/users/login.post.ts +3 -3
- package/server/api/users/register.post.ts +11 -1
- package/server/api/workshop/a2a/[agentId]/rpc/index.post.ts +23 -13
- package/server/api/workshop/agent-tools/bindings/grant.post.ts +45 -0
- package/server/api/workshop/agent-tools/bindings/revoke.post.ts +42 -0
- package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +8 -1
- package/server/api/workshop/channels/[id]/line.put.ts +30 -0
- package/server/api/workshop/dcw/line/query.get.ts +6 -0
- package/server/api/workshop/dcw/recipes/[id]/revert.post.ts +3 -2
- package/server/api/workshop/fs/dirs.get.ts +19 -1
- package/server/api/workshop/ops-logs/index.get.ts +3 -2
- package/server/api/workshop/users/register.post.ts +7 -0
- package/server/mcp/workshop-server.ts +36 -13
- package/server/middleware/00-security-headers.ts +38 -0
- package/server/middleware/01-rate-guard.ts +101 -0
- package/server/plugins/backup.ts +56 -1
- package/server/plugins-builtin/diag-bridge/host/plugin.mjs +18 -11
- package/server/repositories/user.repository.ts +10 -5
- package/server/services/user.service.ts +24 -1
- package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +7 -2
- package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +4 -2
- package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +15 -2
- package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +104 -0
- package/server/services/workshop/agents/industrial/index.ts +1 -1
- package/server/services/workshop/agents/industrial/ops-tools.ts +168 -26
- package/server/services/workshop/agents/node-bindings.repo.ts +10 -1
- package/server/services/workshop/agents/node-delegation.ts +150 -0
- package/server/services/workshop/agents/tool-classes.ts +4 -0
- package/server/services/workshop/aml/dataset-builder.ts +4 -2
- package/server/services/workshop/aml/job-orchestrator/process.ts +1 -0
- package/server/services/workshop/aml/job-orchestrator/shared.ts +2 -0
- package/server/services/workshop/aml/job-orchestrator/start-job.ts +5 -2
- package/server/services/workshop/db/channel.repo.ts +11 -1
- package/server/services/workshop/db/database/migrations.ts +2 -0
- package/server/services/workshop/db/database/rows.ts +2 -0
- package/server/services/workshop/db/database/seed.ts +30 -0
- package/server/services/workshop/dcw/dcw-controller/recipes.ts +60 -4
- package/server/services/workshop/dcw/dcw-controller/write.ts +35 -6
- package/server/services/workshop/dcw/dcw-recipe.repo.ts +4 -3
- package/server/services/workshop/dcw/param-map.repo.ts +3 -0
- package/server/services/workshop/plugins/host/init.mjs +9 -1
- package/server/services/workshop/plugins/host/load.mjs +2 -2
- package/server/services/workshop/runtime/manager/admin-channel.ts +27 -1
- package/server/services/workshop/runtime/manager/channel-templates.ts +27 -2
- package/server/services/workshop/runtime/manager/runtime-wiring.ts +17 -1
- package/server/services/workshop/runtime/manager/types.ts +2 -0
- package/shared/config/schema.json +2 -0
- package/.output/public/_nuxt/8FXd9As6.js +0 -1
- package/.output/public/_nuxt/BOmDHp5L.js +0 -14
- package/.output/public/_nuxt/BWU1pvLL.js +0 -1
- package/.output/public/_nuxt/CdIsmU5a2.js +0 -21
- package/.output/public/_nuxt/D0SNhlnt.js +0 -1
- package/.output/public/_nuxt/DnH9SRMW2.js +0 -1
- package/.output/public/_nuxt/ON2x-t6n.js +0 -1
- package/.output/public/_nuxt/PluginSlot.DmjNbrcX.css +0 -1
- package/.output/public/_nuxt/_wsId_.DkrQkT6r.css +0 -1
- package/.output/public/_nuxt/builds/meta/912eb5bb-670e-4cc8-b21d-7fc097723466.json +0 -1
- package/.output/public/_nuxt/channel-templates.DplM1pJ3.css +0 -1
- package/.output/server/chunks/build/_id_-BUpQSlzo.mjs.map +0 -1
- package/.output/server/chunks/build/channel-templates-DjEsj0_v.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkshopApi-B1B9vd4m.mjs.map +0 -1
- package/scripts/.chk-tok +0 -1
- package/scripts/.retrain-body.json +0 -1
- package/scripts/.retrain3-body.json +0 -1
- package/scripts/.rt-tok +0 -1
- package/scripts/.rt3-tok +0 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/_audit/kb-team-mock-e2e.mjs —— 知识库集成 Channel + lead→worker 节点委派(mock 阶段验收)。
|
|
4
|
+
*
|
|
5
|
+
* 覆盖(无 LLM 依赖):
|
|
6
|
+
* 1) 模板知识库能力面:chtpl-generic-optimize-default / chtpl-aml-optimization-default 标记 knowledgeBaseCapable;
|
|
7
|
+
* 2) 实例化 enableKnowledgeBase=true → 频道插件开关含 rag-bridge=on,场景提示词含 KB 作业段;
|
|
8
|
+
* 3) 实例化 enableKnowledgeBase=false → rag-bridge=off;缺省 → 无显式行(平台默认);
|
|
9
|
+
* 4) 委派 REST:lead 绑定面内节点授予 worker(grantedByAgentId 溯源);
|
|
10
|
+
* 5) fail-closed:越面授予 403 / 授予 lead 自己 400;
|
|
11
|
+
* 6) 执行中授予:worker 有在飞任务时仍可被授予新节点;
|
|
12
|
+
* 7) 撤销:收回授予的节点;非 lead 授予且 lead 不持有的绑定不被误撤。
|
|
13
|
+
*
|
|
14
|
+
* 用法:AW_BASE=http://127.0.0.1:3456 node scripts/_audit/kb-team-mock-e2e.mjs
|
|
15
|
+
* 前置:全新实例(首注册即 admin)。脚本自行注册 admin 账号并搭一条 mock 产线。
|
|
16
|
+
*/
|
|
17
|
+
const BASE = process.env.AW_BASE ?? 'http://127.0.0.1:3456'
|
|
18
|
+
const ADMIN = { email: process.env.AW_ADMIN_EMAIL ?? 'admin@awshop.local', password: process.env.AW_ADMIN_PASSWORD ?? 'Awshop@123!' }
|
|
19
|
+
|
|
20
|
+
let pass = 0
|
|
21
|
+
const fails = []
|
|
22
|
+
const ok = (name, cond, detail = '') => {
|
|
23
|
+
if (cond) { pass++; console.log(` PASS ${name}${detail ? ` — ${detail}` : ''}`) }
|
|
24
|
+
else { fails.push(name); console.log(` FAIL ${name}${detail ? ` — ${detail}` : ''}`) }
|
|
25
|
+
}
|
|
26
|
+
const section = t => console.log(`\n━━━ ${t} ━━━`)
|
|
27
|
+
const sleep = ms => new Promise(r => setTimeout(r, ms))
|
|
28
|
+
|
|
29
|
+
async function api(method, path, { body, token } = {}) {
|
|
30
|
+
const res = await fetch(BASE + path, {
|
|
31
|
+
method,
|
|
32
|
+
headers: { 'content-type': 'application/json', ...(token ? { authorization: `Bearer ${token}` } : {}) },
|
|
33
|
+
body: body != null ? JSON.stringify(body) : undefined,
|
|
34
|
+
signal: AbortSignal.timeout(30000),
|
|
35
|
+
})
|
|
36
|
+
const json = await res.json().catch(() => null)
|
|
37
|
+
return { status: res.status, json }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const TAG = `kbmock-${new Date().toISOString().slice(5, 16).replace(/[-T:]/g, '')}`
|
|
41
|
+
|
|
42
|
+
async function main() {
|
|
43
|
+
section('S0 管理员就绪(全新实例首注册即 admin)')
|
|
44
|
+
const reg = await api('POST', '/api/users/register', { body: { ...ADMIN, name: 'kb-mock-admin' } })
|
|
45
|
+
const token = reg.json?.data?.token ?? (await api('POST', '/api/users/login', { body: { email: ADMIN.email, password: ADMIN.password } })).json?.data?.token
|
|
46
|
+
ok('管理员 token 可用', Boolean(token))
|
|
47
|
+
const auth = { token }
|
|
48
|
+
|
|
49
|
+
section('S1 模板知识库能力面')
|
|
50
|
+
const tplList = (await api('GET', '/api/workshop/channel-templates', auth)).json?.data ?? []
|
|
51
|
+
const generic = tplList.find(t => t.id === 'chtpl-generic-optimize-default')
|
|
52
|
+
const optTpl = tplList.find(t => t.id === 'chtpl-aml-optimization-default')
|
|
53
|
+
ok('内置模板存在「通用闭环优化频道(标准)」', Boolean(generic), generic?.name)
|
|
54
|
+
ok('通用模板标记 knowledgeBaseCapable', generic?.knowledgeBaseCapable === true)
|
|
55
|
+
ok('工艺优化通道标记 knowledgeBaseCapable', optTpl?.knowledgeBaseCapable === true)
|
|
56
|
+
ok('其他模板不带该标记', tplList.find(t => t.id === 'chtpl-default-fullstack')?.knowledgeBaseCapable !== true)
|
|
57
|
+
|
|
58
|
+
section('S2 实例化:enableKnowledgeBase=true → rag-bridge 开 + KB 作业段')
|
|
59
|
+
const inst1 = (await api('POST', '/api/workshop/channel-templates/chtpl-generic-optimize-default/instantiate', { body: { name: `${TAG}-kb-on`, enableKnowledgeBase: true }, ...auth })).json?.data
|
|
60
|
+
ok('通用频道实例化成功', Boolean(inst1?.channelId), `agents=${inst1?.agentCount}`)
|
|
61
|
+
const ch1 = (await api('GET', `/api/workshop/channels/${inst1.channelId}`, auth)).json?.data
|
|
62
|
+
ok('场景提示词含知识库作业段', String(ch1?.scenarioPrompt ?? '').includes('知识库集成') && String(ch1?.scenarioPrompt ?? '').includes('kb_agent'))
|
|
63
|
+
const plug1 = (await api('GET', `/api/workshop/channels/${inst1.channelId}/plugins`, auth)).json?.data
|
|
64
|
+
const rb1 = (Array.isArray(plug1?.plugins) ? plug1.plugins : plug1 ?? []).find?.(p => p?.name === 'rag-bridge')
|
|
65
|
+
?? (Array.isArray(plug1) ? plug1 : []).find(p => p?.name === 'rag-bridge')
|
|
66
|
+
ok('频道插件开关含 rag-bridge=on', Boolean(rb1 && rb1.enabled !== false), JSON.stringify(rb1 ?? plug1 ?? {}).slice(0, 120))
|
|
67
|
+
const members1 = (await api('GET', `/api/workshop/channels/${inst1.channelId}/agents`, auth)).json?.data ?? []
|
|
68
|
+
ok('频道含 lead + worker', members1.some(m => m.role === 'lead') && members1.filter(m => m.role === 'worker').length >= 2, `members=${members1.length}`)
|
|
69
|
+
|
|
70
|
+
section('S3 实例化:enableKnowledgeBase=false 与缺省行为')
|
|
71
|
+
const inst2 = (await api('POST', '/api/workshop/channel-templates/chtpl-aml-optimization-default/instantiate', { body: { name: `${TAG}-kb-off`, enableKnowledgeBase: false }, ...auth })).json?.data
|
|
72
|
+
const plug2 = (await api('GET', `/api/workshop/channels/${inst2.channelId}/plugins`, auth)).json?.data
|
|
73
|
+
const flat2 = Array.isArray(plug2?.plugins) ? plug2.plugins : (Array.isArray(plug2) ? plug2 : [])
|
|
74
|
+
ok('显式 false → rag-bridge=off', flat2.some(p => p?.name === 'rag-bridge' && p.enabled === false), JSON.stringify(flat2).slice(0, 120))
|
|
75
|
+
const inst3 = (await api('POST', '/api/workshop/channel-templates/chtpl-aml-optimization-default/instantiate', { body: { name: `${TAG}-kb-default` }, ...auth })).json?.data
|
|
76
|
+
const plug3 = (await api('GET', `/api/workshop/channels/${inst3.channelId}/plugins`, auth)).json?.data
|
|
77
|
+
const flat3 = Array.isArray(plug3?.plugins) ? plug3.plugins : (Array.isArray(plug3) ? plug3 : [])
|
|
78
|
+
const rb3 = flat3.find(p => p?.name === 'rag-bridge')
|
|
79
|
+
ok('缺省 → rag-bridge 保持平台默认(未被显式停用)', !rb3 || rb3.enabled !== false, JSON.stringify(flat3).slice(0, 120))
|
|
80
|
+
|
|
81
|
+
section('S4 搭 mock 产线(建线 + 模板 + 数采/数控节点)')
|
|
82
|
+
const line = (await api('POST', '/api/workshop/dcw/lines', { body: { name: `KBMock线-${TAG}`, description: 'kb-team mock e2e' }, ...auth })).json?.data
|
|
83
|
+
const lineId = line?.line?.id ?? line?.id
|
|
84
|
+
ok('建线成功', Boolean(lineId), lineId)
|
|
85
|
+
const dcwTpl = (await api('POST', '/api/workshop/dcw/templates', { body: { name: `kbmock-sp-tpl-${TAG}`, ch: '温度设定', unit: '℃', min: 150, max: 220, decimals: 1 }, ...auth })).json?.data
|
|
86
|
+
const daqTpl = (await api('POST', '/api/workshop/daq/templates', { body: { name: `kbmock-temp-tpl-${TAG}`, ch: '温度', unit: '℃', min: 0, max: 300, decimals: 1 }, ...auth })).json?.data
|
|
87
|
+
const dcwTplRef = dcwTpl?.template?.key ?? dcwTpl?.key
|
|
88
|
+
const daqTplRef = daqTpl?.template?.key ?? daqTpl?.key
|
|
89
|
+
ok('节点模板创建成功', Boolean(dcwTplRef) && Boolean(daqTplRef), `dcw=${dcwTplRef} daq=${daqTplRef}`)
|
|
90
|
+
const dcw = (await api('POST', '/api/workshop/dcw', { body: { name: `kbmock-sp-${TAG}`, templateRef: dcwTplRef, driver: 'mock', unit: '℃', min: 150, max: 220, stepLimit: 5, lineId }, ...auth })).json
|
|
91
|
+
const daq = (await api('POST', '/api/workshop/daq', { body: { name: `kbmock-temp-${TAG}`, templateRef: daqTplRef, driver: 'mock', intervalMs: 1000, publishIntervalMs: 0, lineId }, ...auth })).json
|
|
92
|
+
const dcwId = dcw?.data?.node?.id
|
|
93
|
+
const daqId = daq?.data?.node?.id
|
|
94
|
+
ok('数采/数控节点创建成功', Boolean(daqId) && Boolean(dcwId), `daq=${daqId} dcw=${dcwId}`)
|
|
95
|
+
|
|
96
|
+
section('S5 lead 绑定 + 委派核心面')
|
|
97
|
+
const lead = members1.find(m => m.role === 'lead')
|
|
98
|
+
const worker = members1.find(m => m.role === 'worker')
|
|
99
|
+
const b1 = await api('POST', '/api/workshop/agent-tools/bindings', { body: { agentId: lead.id, nodeId: dcwId, kind: 'dcw', mode: 'manual' }, ...auth })
|
|
100
|
+
const b2 = await api('POST', '/api/workshop/agent-tools/bindings', { body: { agentId: lead.id, nodeId: daqId, kind: 'daq', mode: 'auto' }, ...auth })
|
|
101
|
+
ok('lead 绑定 dcw+daq 成功', b1.status === 200 && b2.status === 200, `dcw=${b1.status} daq=${b2.status}`)
|
|
102
|
+
|
|
103
|
+
const grant = await api('POST', '/api/workshop/agent-tools/bindings/grant', { body: { channelId: inst1.channelId, agentId: worker.id, nodeIds: [dcwId, daqId] }, ...auth })
|
|
104
|
+
ok('委派授予成功(整单)', grant.status === 200, JSON.stringify(grant.json?.data ?? grant.json).slice(0, 120))
|
|
105
|
+
const granted = grant.json?.data?.granted ?? []
|
|
106
|
+
ok('授予绑定带 lead 溯源', granted.length === 2 && granted.every(g => g.grantedByAgentId === lead.id), `n=${granted.length}`)
|
|
107
|
+
ok('dcw 委派缺省随 lead 的 manual 模式', granted.find(g => g.kind === 'dcw')?.mode === 'manual')
|
|
108
|
+
const workerBindings = (await api('GET', `/api/workshop/agent-tools/bindings?agentId=${worker.id}`, auth)).json?.data
|
|
109
|
+
const wbFlat = Array.isArray(workerBindings) ? workerBindings : (workerBindings?.bindings ?? [])
|
|
110
|
+
ok('worker 绑定面已含委派节点', wbFlat.some(b => b.nodeId === dcwId) && wbFlat.some(b => b.nodeId === daqId), `n=${wbFlat.length}`)
|
|
111
|
+
|
|
112
|
+
section('S6 fail-closed:越面授予 / 授予 lead 自己')
|
|
113
|
+
const bad = await api('POST', '/api/workshop/agent-tools/bindings/grant', { body: { channelId: inst1.channelId, agentId: worker.id, nodeIds: [`ghost-${TAG}`] }, ...auth })
|
|
114
|
+
const badCode = bad.json?.code ?? bad.json?.data?.code
|
|
115
|
+
ok('越面授予被拒(403 DELEGATION_NOT_OWNED)', bad.status === 403 && badCode === 'DELEGATION_NOT_OWNED', `status=${bad.status} code=${badCode}`)
|
|
116
|
+
const self = await api('POST', '/api/workshop/agent-tools/bindings/grant', { body: { channelId: inst1.channelId, agentId: lead.id, nodeIds: [dcwId] }, ...auth })
|
|
117
|
+
ok('授予 lead 自己被拒(400)', self.status === 400, `status=${self.status}`)
|
|
118
|
+
|
|
119
|
+
section('S7 执行中授予(worker 有在飞任务时仍可授权)')
|
|
120
|
+
const task = (await api('POST', `/api/workshop/channels/${inst1.channelId}/tasks`, { body: { title: `巡检-${TAG}`, description: '读取授权节点并汇报(委派执行中授予验证)', assigneeId: worker.id }, ...auth })).json?.data
|
|
121
|
+
ok('worker 根任务已创建', Boolean(task?.id), task?.id)
|
|
122
|
+
await sleep(500)
|
|
123
|
+
const midGrant = await api('POST', '/api/workshop/agent-tools/bindings/grant', { body: { channelId: inst1.channelId, agentId: worker.id, nodeIds: [dcwId], mode: 'auto' }, ...auth })
|
|
124
|
+
ok('执行中授予成功(模式覆盖 auto)', midGrant.status === 200, JSON.stringify(midGrant.json?.data ?? {}).slice(0, 100))
|
|
125
|
+
await api('POST', `/api/workshop/channels/${inst1.channelId}/tasks/${task.id}/cancel`, { ...auth }).catch(() => {})
|
|
126
|
+
|
|
127
|
+
section('S8 撤销')
|
|
128
|
+
const revoke = await api('POST', '/api/workshop/agent-tools/bindings/revoke', { body: { channelId: inst1.channelId, agentId: worker.id, nodeIds: [daqId] }, ...auth })
|
|
129
|
+
const results = revoke.json?.data?.results ?? []
|
|
130
|
+
ok('撤销 daq 委派成功', revoke.status === 200 && results.every(r => r.revoked), JSON.stringify(results).slice(0, 100))
|
|
131
|
+
const afterRevoke = (await api('GET', `/api/workshop/agent-tools/bindings?agentId=${worker.id}`, auth)).json?.data
|
|
132
|
+
const arFlat = Array.isArray(afterRevoke) ? afterRevoke : (afterRevoke?.bindings ?? [])
|
|
133
|
+
ok('撤销后 worker 不再持有该节点', !arFlat.some(b => b.nodeId === daqId), `剩余=${arFlat.length}`)
|
|
134
|
+
|
|
135
|
+
console.log(`\n════ 结果: ${pass} PASS / ${fails.length} FAIL ════`)
|
|
136
|
+
if (fails.length) {
|
|
137
|
+
console.log('失败项:')
|
|
138
|
+
for (const f of fails) console.log(` - ${f}`)
|
|
139
|
+
process.exit(1)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
main().catch((err) => {
|
|
144
|
+
console.error('E2E 致命异常:', err)
|
|
145
|
+
process.exit(1)
|
|
146
|
+
})
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/_audit/kb-team-omp-e2e.mjs —— 知识库集成通用闭环优化频道 × 真实 omp × 多 PLC 模拟场景。
|
|
4
|
+
*
|
|
5
|
+
* 每个 scenario:
|
|
6
|
+
* ① 模拟器建场(ensureScenarioLine) + 平台建线开跑(provisionScenarioLine,真实协议链路);
|
|
7
|
+
* ② 实例化「通用闭环优化频道(标准)」模板,enableKnowledgeBase=true(频道加载 rag-bridge);
|
|
8
|
+
* ③ lead 绑定 PV 数采节点 + 调节数控节点(auto);
|
|
9
|
+
* ④ 提交优化 goal(要求:先查知识库 → lead 委派节点权限 → 治理小步下发复测 → 判定 → 经验沉淀);
|
|
10
|
+
* ⑤ 期间轮询任务/消息/事件,全程转录落盘(transcript.md + 原始 JSON);
|
|
11
|
+
* ⑥ 验收:根任务收口 + worker 确实被授予节点(grantedBy 溯源) + 发生过治理写入
|
|
12
|
+
* + PV 回带 + 知识库经验新增(kb_agent 异步落库)。
|
|
13
|
+
*
|
|
14
|
+
* 用法:
|
|
15
|
+
* node scripts/_audit/kb-team-omp-e2e.mjs --base http://127.0.0.1:3456 --scenarios injection,wwtp
|
|
16
|
+
* 前置:目标实例为本仓库构建(内置通用模板 + rag-bridge);rag-bridge token 已配置(启 KB 鉴权时);
|
|
17
|
+
* omp CLI 在 PATH 且可用;模拟器可自举(bench/lib/sim.mjs ensureSimulator)。
|
|
18
|
+
*/
|
|
19
|
+
import { join, dirname, resolve } from 'node:path'
|
|
20
|
+
import { writeFileSync, appendFileSync } from 'node:fs'
|
|
21
|
+
import { fileURLToPath } from 'node:url'
|
|
22
|
+
import { makeApi, ensureDir, sleep } from '../../bench/lib/util.mjs'
|
|
23
|
+
import { ensureSimulator, simUp } from '../../bench/lib/sim.mjs'
|
|
24
|
+
import { SCENARIOS, ensureScenarioLine, provisionScenarioLine, readPvMean } from '../../bench/lib/scenarios.mjs'
|
|
25
|
+
|
|
26
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
27
|
+
const REPO = resolve(HERE, '../..')
|
|
28
|
+
const args = process.argv.slice(2)
|
|
29
|
+
const arg = (k, d) => { const i = args.indexOf(`--${k}`); return i >= 0 ? (args[i + 1] ?? '') : d }
|
|
30
|
+
|
|
31
|
+
const BASE = arg('base', process.env.AW_BASE ?? 'http://127.0.0.1:3456')
|
|
32
|
+
const list = (arg('scenarios', 'injection') || 'injection').split(',').map(s => s.trim()).filter(id => SCENARIOS[id])
|
|
33
|
+
const TASK_TIMEOUT_MS = Number(arg('timeout-min', '32')) * 60_000
|
|
34
|
+
const KB_WAIT_MS = Number(arg('kb-wait-min', '6')) * 60_000
|
|
35
|
+
const POLL_MS = 20_000
|
|
36
|
+
const sfx = arg('sfx', `kb${new Date().toISOString().slice(5, 16).replace(/[-T:]/g, '')}`)
|
|
37
|
+
|
|
38
|
+
const rid = `kb-team-omp-${new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '')}`
|
|
39
|
+
const outDir = ensureDir(join(REPO, 'bench', 'results', rid))
|
|
40
|
+
console.log(`=== kb-team × omp 闭环优化 × 多场景 ===\nbase=${BASE} scenarios=${list.join(',')} out=${outDir}\n`)
|
|
41
|
+
|
|
42
|
+
// ── 自举 ──
|
|
43
|
+
if (!(await simUp())) {
|
|
44
|
+
const r = await ensureSimulator({ log: console.log })
|
|
45
|
+
if (!r.started && !(await simUp())) { console.error(`✘ 模拟器自举失败: ${r.reason}`); process.exit(1) }
|
|
46
|
+
}
|
|
47
|
+
const api = makeApi(BASE)
|
|
48
|
+
const login = await api.login(process.env.AW_ADMIN_EMAIL ?? 'admin@awshop.local', process.env.AW_ADMIN_PASSWORD ?? 'Awshop@123!')
|
|
49
|
+
if (!login.ok) { console.error('✘ 平台登录失败'); process.exit(1) }
|
|
50
|
+
console.log(`平台就绪(${login.how},role=${login.role});模拟器就绪\n`)
|
|
51
|
+
|
|
52
|
+
const globalResult = { rid, base: BASE, scenarios: [] }
|
|
53
|
+
|
|
54
|
+
for (const id of list) {
|
|
55
|
+
const scen = SCENARIOS[id]
|
|
56
|
+
const dir = ensureDir(join(outDir, id))
|
|
57
|
+
const res = { scenario: id, zh: scen.zh, checks: {}, errors: [] }
|
|
58
|
+
globalResult.scenarios.push(res)
|
|
59
|
+
const log = (line) => { console.log(`[${id}] ${line}`); appendFileSync(join(dir, 'transcript.md'), `${line}\n`) }
|
|
60
|
+
writeFileSync(join(dir, 'transcript.md'), `# ${scen.zh}(kb-team × omp)作业转录\n\n- 开始: ${new Date().toISOString()}\n- 频道模板: chtl-generic-optimize-default(enableKnowledgeBase=true)\n\n`)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// ── ① 建场 + 建线 ──
|
|
64
|
+
log(`① 模拟器建场 ${scen.key} …`)
|
|
65
|
+
const ensure = await ensureScenarioLine(scen)
|
|
66
|
+
log(` 设备=${ensure.verified.devices}/${ensure.verified.expectDevices} SP=${ensure.verified.sp} PV=${ensure.verified.pv} 协议=${ensure.verified.protocols.join('/')}`)
|
|
67
|
+
const line = await provisionScenarioLine(api, scen, { sfx: `${sfx}-${id}` })
|
|
68
|
+
if (line.errors?.length || !line.ids?.lineId) throw new Error(`建线失败: ${line.errors?.join(';')}`)
|
|
69
|
+
res.line = { lineId: line.ids.lineId, recipeId: line.ids.recipeId, started: line.ids.started, reused: line.reused }
|
|
70
|
+
log(`① 平台建线 ${line.lineName} started=${line.ids.started} dcw=${Object.keys(line.dcw).length} daq=${Object.keys(line.daq).length}`)
|
|
71
|
+
|
|
72
|
+
// ── ② 实例化 KB 通用频道 ──
|
|
73
|
+
const inst = (await api.call('POST', '/api/workshop/channel-templates/chtpl-generic-optimize-default/instantiate', {
|
|
74
|
+
name: `KB闭环优化-${scen.zh}-${sfx}-${id}`,
|
|
75
|
+
enableKnowledgeBase: true,
|
|
76
|
+
}))
|
|
77
|
+
const channelId = inst.data?.channelId
|
|
78
|
+
if (!channelId) throw new Error(`频道实例化失败: ${inst.message}`)
|
|
79
|
+
const agents = (await api.call('GET', `/api/workshop/channels/${channelId}/agents`)).data ?? []
|
|
80
|
+
const lead = agents.find(a => a.role === 'lead')
|
|
81
|
+
res.channel = { channelId, leadId: lead?.id, leadHarness: lead?.harness }
|
|
82
|
+
log(`② 频道 ${channelId} 已实例化(lead=${lead?.name}/${lead?.harness},成员=${agents.length})`)
|
|
83
|
+
|
|
84
|
+
// ── ③ lead 绑定 PV 数采 + 调节数控(auto) ──
|
|
85
|
+
const pvNode = line.daq[scen.pv.sig]
|
|
86
|
+
const knobSigs = (scen.knobs ?? []).map(k => k.sig).slice(0, 2)
|
|
87
|
+
const knobNodes = knobSigs.map(s => line.dcw[s]).filter(Boolean)
|
|
88
|
+
if (!pvNode || !knobNodes.length) throw new Error(`关键节点缺失: pv=${pvNode} knobs=${knobNodes}`)
|
|
89
|
+
for (const [nodeId, kind] of [[pvNode, 'daq'], ...knobNodes.map(n => [n, 'dcw'])]) {
|
|
90
|
+
const r = await api.call('POST', '/api/workshop/agent-tools/bindings', { agentId: lead.id, nodeId, kind, mode: 'auto' })
|
|
91
|
+
if (r.status !== 200) throw new Error(`lead 绑定失败 ${kind} ${nodeId}: ${r.message}`)
|
|
92
|
+
}
|
|
93
|
+
res.leadBindings = { pvNode, knobNodes }
|
|
94
|
+
log(`③ lead 绑定:daq(${scen.pv.sig})=${pvNode} dcw=${knobNodes.join(',')}`)
|
|
95
|
+
|
|
96
|
+
// ── ④ 提交 goal ──
|
|
97
|
+
const knobText = (scen.knobs ?? []).slice(0, 2).map(k => `${k.sig}`).join('、')
|
|
98
|
+
const guardText = (scen.guards ?? []).map(g => `${g.label}≤${g.max}`).join('、') || '无'
|
|
99
|
+
const goal = [
|
|
100
|
+
`【产线闭环优化】${scen.zh}:${scen.story}`,
|
|
101
|
+
`目标:把「${scen.pv.label}(${scen.pv.sig})」稳定控制回 ${scen.pv.target}±${scen.pv.tol}${scen.pv.unit} 目标带;守卫约束:${guardText}。`,
|
|
102
|
+
`可调手段(数控节点,治理下发):${knobText}。`,
|
|
103
|
+
`作业要求:`,
|
|
104
|
+
`1. 开工先查知识库:lead 用 kb_agent(mode=sync) 检索「${scen.zh} 数据分析」「${scen.pv.label} 物理机理与设定影响」,把检索结论作为寻优方向与步长依据;`,
|
|
105
|
+
`2. lead 把自己已绑定的节点授权授予 worker(dispatch_task 带 grant_node_ids 随任务授予,或 team_grant_nodes),确保工艺工程师与数据分析师各自拿到所需节点权限,不要无权限空转;`,
|
|
106
|
+
`3. 工艺工程师单变量小步调整(每步 ≤ 量程 2%,尊重单步限幅与写入间隔),每次调整后等 ${Math.round(scen.settleMs / 1000)}s 再 daq_query 复测「${scen.pv.label}」;`,
|
|
107
|
+
`4. 进入目标带且复测稳定后 dcw_judge 落判定(keep),lead 用 kb_agent(mode=async) 把本次经验沉淀入知识库(含调整前后参数值与响应数据),随后完成收口汇报。`,
|
|
108
|
+
].join('\n')
|
|
109
|
+
const task = (await api.call('POST', `/api/workshop/channels/${channelId}/tasks`, { title: `${scen.zh}(KB 闭环)`, description: goal })).data
|
|
110
|
+
if (!task?.id) throw new Error(`根任务提交失败`)
|
|
111
|
+
res.rootTaskId = task.id
|
|
112
|
+
log(`④ 根任务 ${task.id} 已提交,开始作业(超时 ${Math.round(TASK_TIMEOUT_MS / 60000)}min)…\n`)
|
|
113
|
+
|
|
114
|
+
// ── ⑤ 轮询转录 ──
|
|
115
|
+
let seenMsg = new Set()
|
|
116
|
+
let seenTaskState = new Map()
|
|
117
|
+
let lastEventSeq = 0
|
|
118
|
+
let toolEvidence = { kbAgent: 0, grant: 0 }
|
|
119
|
+
const t0 = Date.now()
|
|
120
|
+
let terminal = null
|
|
121
|
+
const dump = async () => {
|
|
122
|
+
const msgs = (await api.call('GET', `/api/workshop/channels/${channelId}/messages?limit=200`)).data ?? []
|
|
123
|
+
for (const m of [...msgs].reverse()) {
|
|
124
|
+
const key = m.id ?? `${m.createdAt}:${m.fromAgentName}`
|
|
125
|
+
if (seenMsg.has(key)) continue
|
|
126
|
+
seenMsg.add(key)
|
|
127
|
+
const who = m.fromAgentName ?? m.from ?? '?'
|
|
128
|
+
const text = String(m.text ?? m.preview ?? '').slice(0, 600)
|
|
129
|
+
if (text.trim()) appendFileSync(join(dir, 'transcript.md'), `\n> **${who}** @ ${m.createdAt ?? ''}\n>\n${text.split('\n').map(l => `> ${l}`).join('\n')}\n`)
|
|
130
|
+
}
|
|
131
|
+
const tasks = (await api.call('GET', `/api/workshop/channels/${channelId}/tasks`)).data ?? []
|
|
132
|
+
const arr = Array.isArray(tasks) ? tasks : (tasks.tasks ?? [])
|
|
133
|
+
for (const t of arr) {
|
|
134
|
+
const st = `${t.id}:${t.state}:${t.progress ?? 0}`
|
|
135
|
+
if (seenTaskState.get(t.id) !== st) {
|
|
136
|
+
seenTaskState.set(t.id, st)
|
|
137
|
+
appendFileSync(join(dir, 'transcript.md'), `\n- [任务] ${t.id} 「${t.title}」 state=${t.state} progress=${t.progress ?? 0}% assignee=${t.assigneeId ?? '-'}`)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 事件流:记录工具调用证据(kb_agent / team_grant_nodes / grant_node_ids)与 lead 进度报告
|
|
141
|
+
const ev = (await api.call('GET', `/api/workshop/channels/${channelId}/events?limit=200&afterSeq=${lastEventSeq}`)).data ?? {}
|
|
142
|
+
for (const item of (ev.items ?? [])) {
|
|
143
|
+
lastEventSeq = Math.max(lastEventSeq, Number(item.seq ?? 0))
|
|
144
|
+
const text = String(item.payload?.text ?? item.payload?.summary ?? '')
|
|
145
|
+
if (!text) continue
|
|
146
|
+
const kbHits = (text.match(/kb_agent/g) ?? []).length
|
|
147
|
+
const grantHits = (text.match(/team_grant_nodes|grant_node_ids/g) ?? []).length
|
|
148
|
+
toolEvidence.kbAgent += kbHits
|
|
149
|
+
toolEvidence.grant += grantHits
|
|
150
|
+
if (kbHits || grantHits) {
|
|
151
|
+
appendFileSync(join(dir, 'transcript.md'), `\n- [工具证据] @ ${(item.at ?? item.createdAt ?? '').slice(11, 19)} ${text.replace(/\n+/g, ' ').slice(0, 220)}`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { tasks: arr, msgs }
|
|
155
|
+
}
|
|
156
|
+
while (Date.now() - t0 < TASK_TIMEOUT_MS) {
|
|
157
|
+
await sleep(POLL_MS)
|
|
158
|
+
try {
|
|
159
|
+
const { tasks } = await dump()
|
|
160
|
+
const root = tasks.find(t => t.id === task.id)
|
|
161
|
+
if (root && ['COMPLETED', 'FAILED', 'CANCELED'].includes(root.state)) { terminal = root; break }
|
|
162
|
+
log(`… 作业中(${Math.round((Date.now() - t0) / 60000)}min)root=${root?.state ?? '?'}`)
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
log(`… 轮询抖动(忽略): ${err?.message ?? err}`)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
await dump()
|
|
169
|
+
if (!terminal) { res.errors.push(`根任务超时(${Math.round(TASK_TIMEOUT_MS / 60000)}min)未收口`) }
|
|
170
|
+
else if (terminal.state !== 'COMPLETED') { res.errors.push(`根任务终态=${terminal.state}`) }
|
|
171
|
+
res.checks.rootTaskClosed = terminal?.state === 'COMPLETED'
|
|
172
|
+
log(`\n⑤ 根任务终态=${terminal?.state ?? 'TIMEOUT'}`)
|
|
173
|
+
|
|
174
|
+
// ── ⑥ 验收 ──
|
|
175
|
+
const workers = agents.filter(a => a.role === 'worker')
|
|
176
|
+
let delegated = 0
|
|
177
|
+
for (const w of workers) {
|
|
178
|
+
const bs = (await api.call('GET', `/api/workshop/agent-tools/bindings?agentId=${w.id}`)).data
|
|
179
|
+
const flat = Array.isArray(bs) ? bs : (bs?.bindings ?? [])
|
|
180
|
+
if (flat.some(b => b.grantedByAgentId === lead.id)) delegated++
|
|
181
|
+
}
|
|
182
|
+
res.checks.workerDelegated = delegated > 0
|
|
183
|
+
log(`⑥ 委派核验:${delegated}/${workers.length} 个 worker 持有 lead 授予的节点授权`)
|
|
184
|
+
|
|
185
|
+
const dcwNow = (await api.call('GET', '/api/workshop/dcw')).data?.nodes ?? []
|
|
186
|
+
const myDcw = dcwNow.filter(n => Object.values(line.dcw).includes(n.id))
|
|
187
|
+
const wrote = myDcw.some(n => n.lastWriteAt)
|
|
188
|
+
res.checks.governedWriteHappened = wrote
|
|
189
|
+
res.dcAfter = myDcw.map(n => ({ id: n.id, name: n.name, value: n.value, lastWriteAt: n.lastWriteAt ?? null }))
|
|
190
|
+
log(`⑥ 治理写入核验:${wrote ? '发生过 dcw 治理写入' : '无 dcw 写入痕迹'}`)
|
|
191
|
+
|
|
192
|
+
const pvMean = await readPvMean(api, pvNode, 5).catch(() => null)
|
|
193
|
+
const inBand = pvMean != null && Math.abs(Number(pvMean) - scen.pv.target) <= scen.pv.tol
|
|
194
|
+
res.checks.pvInBand = inBand
|
|
195
|
+
res.pvMean = pvMean
|
|
196
|
+
log(`⑥ PV 复测:均值=${pvMean} 目标带=${scen.pv.target}±${scen.pv.tol} → ${inBand ? '达标' : '未达标'}`)
|
|
197
|
+
|
|
198
|
+
res.toolEvidence = toolEvidence
|
|
199
|
+
res.checks.kbToolUsed = toolEvidence.kbAgent > 0
|
|
200
|
+
res.checks.grantToolUsed = toolEvidence.grant > 0 || delegated > 0
|
|
201
|
+
log(`⑥ 工具证据(事件流):kb_agent×${toolEvidence.kbAgent} 委派×${toolEvidence.grant}`)
|
|
202
|
+
|
|
203
|
+
log(`⑥ 等待知识库经验沉淀可检索(≤${Math.round(KB_WAIT_MS / 60000)}min)…`)
|
|
204
|
+
const kbQuery = encodeURIComponent(`${scen.zh.slice(0, 6)} ${scen.pv.label} 经验`)
|
|
205
|
+
const kbDeadline = Date.now() + KB_WAIT_MS
|
|
206
|
+
let kbHit = false
|
|
207
|
+
while (Date.now() < kbDeadline) {
|
|
208
|
+
await sleep(45_000)
|
|
209
|
+
const sr = (await api.call('GET', `/api/plugins/rag-bridge/search?q=${kbQuery}&top_k=5`).catch(() => null))?.data
|
|
210
|
+
if ((sr?.total_results ?? 0) > 0 || (sr?.results ?? []).length > 0) { kbHit = true; break }
|
|
211
|
+
log(` … 检索暂未命中(累计等待 ${Math.round((kbDeadline - Date.now()) / 60000)}min)`)
|
|
212
|
+
}
|
|
213
|
+
res.checks.kbExperience = kbHit
|
|
214
|
+
log(`⑥ 知识库经验检索:${kbHit ? '已检出本场景经验内容' : '超时未检出(检索面后端索引漂移时以转录工具证据为准)'}`)
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
res.errors.push(String(err?.message ?? err))
|
|
218
|
+
log(`✘ 异常: ${err?.message ?? err}`)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
res.ok = res.errors.length === 0 && Object.values(res.checks).every(Boolean)
|
|
222
|
+
log(`\n════ [${id}] 结果: ${res.ok ? 'PASS' : 'FAIL'} checks=${JSON.stringify(res.checks)}${res.errors.length ? ` errors=${res.errors.join(';')}` : ''}`)
|
|
223
|
+
writeFileSync(join(dir, 'final.json'), JSON.stringify(res, null, 2))
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
writeFileSync(join(outDir, 'kb-team-omp-result.json'), JSON.stringify(globalResult, null, 2))
|
|
227
|
+
const allOk = globalResult.scenarios.every(s => s.ok)
|
|
228
|
+
console.log(`\n════ 总结果: ${allOk ? '✅ 全场景 PASS' : '❌ 存在 FAIL'}(明细: ${outDir})`)
|
|
229
|
+
process.exit(allOk ? 0 : 1)
|
|
@@ -21,7 +21,8 @@ import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/
|
|
|
21
21
|
import { createWorkshopMcpServer } from '../../mcp/workshop-server'
|
|
22
22
|
import { getWorkshopManager } from '../../plugins/workshop'
|
|
23
23
|
|
|
24
|
-
/** 会话注册表:sessionId → transport(stateful 会话状态保留) */
|
|
24
|
+
/** 会话注册表:sessionId → transport(stateful 会话状态保留);上限防匿名刷爆内存 */
|
|
25
|
+
const MAX_MCP_SESSIONS = 64
|
|
25
26
|
const sessions = new Map<string, WebStandardStreamableHTTPServerTransport>()
|
|
26
27
|
|
|
27
28
|
/** h3 event → web Request(跨 h3 1.x/2.x 兼容:不用版本互异的转换助手) */
|
|
@@ -65,6 +66,12 @@ export default defineEventHandler(async (event) => {
|
|
|
65
66
|
|
|
66
67
|
// 新会话:预生成 sessionId,transport 在 initialize 时把它写入响应头
|
|
67
68
|
if (!transport) {
|
|
69
|
+
if (sessions.size >= MAX_MCP_SESSIONS) {
|
|
70
|
+
return new Response(JSON.stringify({ error: 'TOO_MANY_SESSIONS', message: `MCP 会话数已达上限 ${MAX_MCP_SESSIONS}` }), {
|
|
71
|
+
status: 429,
|
|
72
|
+
headers: { 'content-type': 'application/json' },
|
|
73
|
+
})
|
|
74
|
+
}
|
|
68
75
|
const newSessionId = randomUUID()
|
|
69
76
|
transport = new WebStandardStreamableHTTPServerTransport({
|
|
70
77
|
sessionIdGenerator: () => newSessionId,
|
package/server/api/metrics.ts
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* GET /api/metrics —— 运维指标端点(R4,production-readiness-plan)。
|
|
3
3
|
*
|
|
4
4
|
* text/plain 简易指标格式(键值行,Prometheus 可用 textfile/自定义采集器接入)。
|
|
5
|
-
*
|
|
5
|
+
* 鉴权:任意有效用户 token(Bearer)——聚合计数与时间戳不含业务数据,
|
|
6
|
+
* 但公网部署下不向匿名暴露运行面信息;采集器配 Token 头即可接入。
|
|
6
7
|
* 只读 globalThis 单例(不主动实例化),服务未装配时输出 0 —— 首次抓取即合法。
|
|
7
8
|
*/
|
|
8
9
|
import { defineEventHandler, setResponseHeader } from 'h3'
|
|
9
10
|
import { getOps } from '../services/workshop/ops/ops'
|
|
11
|
+
import { resolveUser } from './workshop/caller'
|
|
10
12
|
|
|
11
13
|
interface MetricLine { name: string, help: string, value: number | string }
|
|
12
14
|
|
|
@@ -15,6 +17,7 @@ function fmt(lines: MetricLine[]): string {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export default defineEventHandler(async (event) => {
|
|
20
|
+
resolveUser(event)
|
|
18
21
|
const g = globalThis as typeof globalThis & {
|
|
19
22
|
__daqController?: { controllerState(): Record<string, number | boolean>, running?: boolean }
|
|
20
23
|
__daqQueue?: { lost?: number }
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* /api/plugins/:name/** —— 插件自注册 API 的转发层(exact-match)。
|
|
3
3
|
* 插件经 ctx.route(method, path, handler) 注册;handler(event) 返回值由 nitro 序列化。
|
|
4
|
-
* 鉴权:插件在入口声明 auth:'user' | 'admin' | 'agent-or-user'
|
|
5
|
-
* (
|
|
4
|
+
* 鉴权:插件在入口声明 auth:'user' | 'admin' | 'agent-or-user' | 'none' 时由转发层统一校验。
|
|
5
|
+
* 安全默认 = 'user'(default-deny):未声明的插件不再匿名暴露,须显式声明 'none' 才开放
|
|
6
|
+
* (公网部署基线;确需匿名的只读面由插件作者显式声明并承担暴露责任)。
|
|
6
7
|
* 错误隔离:插件 handler 抛错 → 结构化日志(带插件归属)+ 干净 500 信封,不裸传堆栈。
|
|
7
8
|
*/
|
|
8
9
|
import { defineEventHandler, createError, readBody } from 'h3'
|
|
@@ -16,7 +17,7 @@ export default defineEventHandler(async (event) => {
|
|
|
16
17
|
const path = '/' + (event.context.params?.path ?? '').replace(/^\/+/, '')
|
|
17
18
|
const rec = host.plugins.get(name)
|
|
18
19
|
// 声明式鉴权门:在进入插件 handler 前统一校验(禁用插件的路由表已不含其路由,天然 404)
|
|
19
|
-
const authMode = String(rec?.auth ?? '
|
|
20
|
+
const authMode = String(rec?.auth ?? 'user')
|
|
20
21
|
if (authMode !== 'none') {
|
|
21
22
|
try {
|
|
22
23
|
if (authMode === 'admin') await requireAdmin(event)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /api/system/backup/list —— 备份清单(admin):库快照文件 + JSON/配置束目录。
|
|
3
|
+
* 只列文件名与大小/时间,不回传内容;恢复操作 = 停实例后由运维手工替换(安全优先不给在线恢复 API)。
|
|
4
|
+
*/
|
|
5
|
+
import { readdirSync, statSync } from 'node:fs'
|
|
6
|
+
import { resolve } from 'node:path'
|
|
7
|
+
import { defineApiHandler } from '../../../utils/response'
|
|
8
|
+
import { requireAdmin } from '../../workshop/caller'
|
|
9
|
+
import { ensureDataDir } from '@/shared/config/home.mjs'
|
|
10
|
+
|
|
11
|
+
export default defineApiHandler(async (event) => {
|
|
12
|
+
requireAdmin(event)
|
|
13
|
+
const backupDir = resolve(ensureDataDir(), 'backups')
|
|
14
|
+
let entries: Array<{ name: string, kind: 'db' | 'files', bytes: number, mtime: string }> = []
|
|
15
|
+
try {
|
|
16
|
+
entries = readdirSync(backupDir, { withFileTypes: true }).flatMap((e) => {
|
|
17
|
+
const full = resolve(backupDir, e.name)
|
|
18
|
+
try {
|
|
19
|
+
const st = statSync(full)
|
|
20
|
+
return [{
|
|
21
|
+
name: e.name,
|
|
22
|
+
kind: (e.isDirectory() ? 'files' : 'db') as 'db' | 'files',
|
|
23
|
+
bytes: st.size,
|
|
24
|
+
mtime: st.mtime.toISOString(),
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
27
|
+
catch { return [] }
|
|
28
|
+
}).sort((a, b) => b.mtime.localeCompare(a.mtime))
|
|
29
|
+
}
|
|
30
|
+
catch { /* 备份目录尚不存在 = 还没备过 */ }
|
|
31
|
+
return { backupDir, count: entries.length, entries: entries.slice(0, 200) }
|
|
32
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/system/backup/run —— 手动触发一次全量备份(admin)。
|
|
3
|
+
* 复用 server/plugins/backup.ts 的 backupOnce(三库在线快照 + JSON/配置面 + 保留轮转),
|
|
4
|
+
* 成败均落 audit_log(system.backup.*)。
|
|
5
|
+
*/
|
|
6
|
+
import { defineApiHandler } from '../../../utils/response'
|
|
7
|
+
import { requireAdmin } from '../../workshop/caller'
|
|
8
|
+
import { AppError } from '../../../utils/errors'
|
|
9
|
+
|
|
10
|
+
export default defineApiHandler(async (event) => {
|
|
11
|
+
requireAdmin(event)
|
|
12
|
+
const { backupOnce } = await import('../../../plugins/backup')
|
|
13
|
+
const { ensureDataDir } = await import('@/shared/config/home.mjs')
|
|
14
|
+
try {
|
|
15
|
+
await backupOnce(ensureDataDir())
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
throw new AppError(500, 'BACKUP_FAILED', `备份失败: ${err instanceof Error ? err.message : String(err)}`)
|
|
19
|
+
}
|
|
20
|
+
return { ok: true, at: new Date().toISOString() }
|
|
21
|
+
})
|
|
@@ -10,13 +10,23 @@ import { readBody } from 'h3'
|
|
|
10
10
|
import { defineApiHandler } from '../../../utils/response'
|
|
11
11
|
import { requireRole } from '../../workshop/caller'
|
|
12
12
|
import { getSystemConfigService } from '../../../services/system-config'
|
|
13
|
+
import { recordOps } from '../../../services/workshop/ops/ops'
|
|
13
14
|
|
|
14
15
|
export default defineApiHandler(async (event) => {
|
|
15
|
-
requireRole(event, ['admin'])
|
|
16
|
+
const user = requireRole(event, ['admin'])
|
|
16
17
|
const body = (await readBody<Record<string, unknown>>(event)) ?? {}
|
|
17
18
|
const overrides = body.override ?? body.overrides ?? body
|
|
18
19
|
if (!overrides || typeof overrides !== 'object' || Array.isArray(overrides)) {
|
|
19
20
|
return { ok: false, message: '请求体应为 { "override": { key: value } }' }
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
const res = getSystemConfigService().patch(overrides as Record<string, unknown>)
|
|
23
|
+
// 高危管理面留痕:改了哪些键(值不落审计——可能含凭据),谁改的
|
|
24
|
+
if (res.changed?.length) {
|
|
25
|
+
recordOps({
|
|
26
|
+
actor: user.id, actorName: user.name, actorKind: 'user',
|
|
27
|
+
action: 'system.settings.update', kind: 'system',
|
|
28
|
+
summary: `运行时设置变更:${res.changed.join(', ')}`,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
return { ok: true, ...res }
|
|
22
32
|
})
|
|
@@ -5,8 +5,17 @@
|
|
|
5
5
|
import { defineApiHandler } from '../../../utils/response'
|
|
6
6
|
import { requireRole } from '../../workshop/caller'
|
|
7
7
|
import { getSystemConfigService } from '../../../services/system-config'
|
|
8
|
+
import { recordOps } from '../../../services/workshop/ops/ops'
|
|
8
9
|
|
|
9
10
|
export default defineApiHandler((event) => {
|
|
10
|
-
requireRole(event, ['admin'])
|
|
11
|
-
|
|
11
|
+
const user = requireRole(event, ['admin'])
|
|
12
|
+
const res = getSystemConfigService().reset()
|
|
13
|
+
if (res.changed?.length) {
|
|
14
|
+
recordOps({
|
|
15
|
+
actor: user.id, actorName: user.name, actorKind: 'user',
|
|
16
|
+
action: 'system.settings.reset', kind: 'system',
|
|
17
|
+
summary: `清空运行时覆盖(${res.changed.length} 键回落 config.yml)`,
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
return { ok: true, ...res }
|
|
12
21
|
})
|
|
@@ -2,10 +2,17 @@ import { getRouterParam } from 'h3'
|
|
|
2
2
|
import { userService } from '../../services/user.service'
|
|
3
3
|
import { defineApiHandler } from '../../utils/response'
|
|
4
4
|
import { requireAdmin } from '../workshop/caller'
|
|
5
|
+
import { recordOps } from '../../services/workshop/ops/ops'
|
|
5
6
|
|
|
6
7
|
/** DELETE /api/users/:id —— 删除用户(仅 admin) */
|
|
7
8
|
export default defineApiHandler((event) => {
|
|
8
|
-
requireAdmin(event)
|
|
9
|
+
const admin = requireAdmin(event)
|
|
9
10
|
const id = getRouterParam(event, 'id') ?? ''
|
|
10
|
-
|
|
11
|
+
const res = userService.remove(id)
|
|
12
|
+
recordOps({
|
|
13
|
+
actor: admin.id, actorName: admin.name, actorKind: 'user',
|
|
14
|
+
action: 'user.delete', kind: 'system', targetKind: 'user', targetId: id,
|
|
15
|
+
summary: `删除用户 ${id}`,
|
|
16
|
+
})
|
|
17
|
+
return res
|
|
11
18
|
})
|
|
@@ -4,11 +4,18 @@ import { userService } from '../../services/user.service'
|
|
|
4
4
|
import { defineApiHandler } from '../../utils/response'
|
|
5
5
|
import { zValidator } from '../../utils/validate'
|
|
6
6
|
import { requireAdmin } from '../workshop/caller'
|
|
7
|
+
import { recordOps } from '../../services/workshop/ops/ops'
|
|
7
8
|
|
|
8
9
|
/** PUT /api/users/:id —— 更新用户(部分字段) */
|
|
9
10
|
export default defineApiHandler(async (event) => {
|
|
10
|
-
requireAdmin(event)
|
|
11
|
+
const admin = requireAdmin(event)
|
|
11
12
|
const id = getRouterParam(event, 'id') ?? ''
|
|
12
13
|
const body = await readValidatedBody(event, zValidator(userUpdateSchema)) as UserUpdate
|
|
13
|
-
|
|
14
|
+
const user = userService.update(id, body)
|
|
15
|
+
recordOps({
|
|
16
|
+
actor: admin.id, actorName: admin.name, actorKind: 'user',
|
|
17
|
+
action: 'user.update', kind: 'system', targetKind: 'user', targetId: id,
|
|
18
|
+
summary: `更新用户 ${id}(字段:${Object.keys(body).join(', ')})`,
|
|
19
|
+
})
|
|
20
|
+
return user
|
|
14
21
|
})
|
|
@@ -4,10 +4,17 @@ import { userService } from '../../services/user.service'
|
|
|
4
4
|
import { defineApiHandler } from '../../utils/response'
|
|
5
5
|
import { zValidator } from '../../utils/validate'
|
|
6
6
|
import { requireAdmin } from '../workshop/caller'
|
|
7
|
+
import { recordOps } from '../../services/workshop/ops/ops'
|
|
7
8
|
|
|
8
9
|
/** POST /api/users —— 创建用户 */
|
|
9
10
|
export default defineApiHandler(async (event) => {
|
|
10
|
-
requireAdmin(event)
|
|
11
|
+
const admin = requireAdmin(event)
|
|
11
12
|
const body = await readValidatedBody(event, zValidator(userCreateSchema)) as UserCreate
|
|
12
|
-
|
|
13
|
+
const user = userService.create(body)
|
|
14
|
+
recordOps({
|
|
15
|
+
actor: admin.id, actorName: admin.name, actorKind: 'user',
|
|
16
|
+
action: 'user.create', kind: 'system', targetKind: 'user', targetId: user.id,
|
|
17
|
+
summary: `创建用户 ${user.name}(${user.role})`,
|
|
18
|
+
})
|
|
19
|
+
return user
|
|
13
20
|
})
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { readValidatedBody } from 'h3'
|
|
1
|
+
import { getRequestIP, readValidatedBody } from 'h3'
|
|
2
2
|
import { userLoginSchema, type UserLogin } from '../../schemas/user.schema'
|
|
3
3
|
import { userService } from '../../services/user.service'
|
|
4
4
|
import { defineApiHandler } from '../../utils/response'
|
|
5
5
|
import { zValidator } from '../../utils/validate'
|
|
6
6
|
|
|
7
|
-
/** POST /api/users/login —— 公开登录(email + password),签发新会话 token */
|
|
7
|
+
/** POST /api/users/login —— 公开登录(email + password),签发新会话 token;带 IP 供防爆破锁定 */
|
|
8
8
|
export default defineApiHandler(async (event) => {
|
|
9
9
|
const body = await readValidatedBody(event, zValidator(userLoginSchema)) as UserLogin
|
|
10
|
-
return userService.login(body)
|
|
10
|
+
return userService.login(body, { ip: getRequestIP(event, { xForwardedFor: true }) ?? '' })
|
|
11
11
|
})
|