agentworkshop 0.7.52 → 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 +70 -1
- package/.output/.AgentWorkShop/prompts/host-tools.json +70 -1
- 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/{CTvh8v4T.js → BXR3tgEk.js} +1 -1
- package/.output/public/_nuxt/{Cbeifv55.js → BhlRInVa.js} +1 -1
- package/.output/public/_nuxt/{mNnuUoSy.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/{CkPxL4UX2.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/{qPsch_ny2.js → Chxx-DIE2.js} +1 -1
- package/.output/public/_nuxt/{BiUhxH3t2.js → CjwxhpwR2.js} +1 -1
- package/.output/public/_nuxt/{B9cGf8mg.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/{D_Ce9Fon2.js → DFhyhDGa2.js} +1 -1
- package/.output/public/_nuxt/{BXx9AxdF2.js → DSqMyLCV2.js} +1 -1
- package/.output/public/_nuxt/{B8zP7kaj2.js → DV5joWTn2.js} +1 -1
- package/.output/public/_nuxt/{Da90gveK.js → DVOR2pWg.js} +1 -1
- package/.output/public/_nuxt/DWsgRq2c.js +1 -0
- package/.output/public/_nuxt/{mgWHSRc8.js → DZDi8inD.js} +1 -1
- package/.output/public/_nuxt/{xQX5r6tW.js → Dep0Hc9w.js} +1 -1
- package/.output/public/_nuxt/{evt5VGDh.js → DffgG8vT.js} +1 -1
- package/.output/public/_nuxt/{B_opxrHJ.js → DlCktWDT.js} +1 -1
- package/.output/public/_nuxt/{BVzw5a_0.js → DmzmgYHb.js} +1 -1
- package/.output/public/_nuxt/PluginSlot.CGH0vb95.css +1 -0
- package/.output/public/_nuxt/{ty5W5QwO.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/{C00Rd6Cg.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/{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 +1945 -1420
- 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_-C4L9fVHC.mjs → _wsId_-DdqXzycE.mjs} +320 -202
- package/.output/server/chunks/build/{_wsId_-C4L9fVHC.mjs.map → _wsId_-DdqXzycE.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-ydYu-Ol9.mjs → agents-DqICy4AL.mjs} +6 -6
- package/.output/server/chunks/build/{agents-ydYu-Ol9.mjs.map → agents-DqICy4AL.mjs.map} +1 -1
- package/.output/server/chunks/build/{channel-templates-DP1ndA5K.mjs → channel-templates-gdCLajKy.mjs} +2 -2
- package/.output/server/chunks/build/{channel-templates-DP1ndA5K.mjs.map → channel-templates-gdCLajKy.mjs.map} +1 -1
- 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-BzmrmLL_.mjs → pages-CRMeXrxG.mjs} +3 -3
- package/.output/server/chunks/build/{pages-BzmrmLL_.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-BYR-lA1k.mjs → schedules-D8vYHgQ5.mjs} +2 -2
- package/.output/server/chunks/build/{schedules-BYR-lA1k.mjs.map → schedules-D8vYHgQ5.mjs.map} +1 -1
- package/.output/server/chunks/build/{settings-UyZ78w2e.mjs → settings-B7HA-sdb.mjs} +3 -3
- package/.output/server/chunks/build/{settings-UyZ78w2e.mjs.map → settings-B7HA-sdb.mjs.map} +1 -1
- package/.output/server/chunks/build/{teams-D-Y5mzU7.mjs → teams-wM-MdLv9.mjs} +8 -8
- package/.output/server/chunks/build/{teams-D-Y5mzU7.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-CRyQYYY0.mjs → useAgentHarnessOptions-BnFCh23W.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentHarnessOptions-CRyQYYY0.mjs.map → useAgentHarnessOptions-BnFCh23W.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateActions-CaRsOBmB.mjs → useAgentTemplateActions-DsBRUQni.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateActions-CaRsOBmB.mjs.map → useAgentTemplateActions-DsBRUQni.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateForm-ChiIuPYr.mjs → useAgentTemplateForm-DzQ_t2Ue.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateForm-ChiIuPYr.mjs.map → useAgentTemplateForm-DzQ_t2Ue.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-Bf5hk6Jf.mjs → useAgentTemplatesCatalog-Q7LgG1Af.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-Bf5hk6Jf.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-CNOY4Bi3.mjs → useDashboardData-DWJ6vHjm.mjs} +2 -2
- package/.output/server/chunks/build/{useDashboardData-CNOY4Bi3.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-C51ciLb0.mjs → useTeamActions-BOLQkYxg.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamActions-C51ciLb0.mjs.map → useTeamActions-BOLQkYxg.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamAddMemberDialog-DthpCMP8.mjs → useTeamAddMemberDialog-BCgrLPxI.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamAddMemberDialog-DthpCMP8.mjs.map → useTeamAddMemberDialog-BCgrLPxI.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamCreateDialog-Dc2KTwyg.mjs → useTeamCreateDialog-CJk40LqS.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamCreateDialog-Dc2KTwyg.mjs.map → useTeamCreateDialog-CJk40LqS.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamDeployDialog-CXpvPnJD.mjs → useTeamDeployDialog-49hdUXQP.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamDeployDialog-CXpvPnJD.mjs.map → useTeamDeployDialog-49hdUXQP.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamPluginDialog-DTs-7SSm.mjs → useTeamPluginDialog-Dh-QOoiU.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamPluginDialog-DTs-7SSm.mjs.map → useTeamPluginDialog-Dh-QOoiU.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamsCatalog-CcpetYyW.mjs → useTeamsCatalog-HBSyKt5P.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamsCatalog-CcpetYyW.mjs.map → useTeamsCatalog-HBSyKt5P.mjs.map} +1 -1
- package/.output/server/chunks/build/{useWorkshopApi-CO3ophqt.mjs → useWorkshopApi-C9sTYu1F.mjs} +9 -1
- 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 +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +1 -1
- 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 +8 -3
- 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 +340 -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 +7 -0
- package/app/stores/workshop/notifications.ts +43 -17
- package/docs/cli.en.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/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 +152 -8
- package/i18n/locales/zh-CN.ts +152 -8
- package/package.json +1 -1
- package/public/robots.txt +3 -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/channel-templates/[id]/instantiate.post.ts +6 -0
- 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 +1 -1
- package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +4 -2
- 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/tool-classes.ts +2 -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 +19 -9
- 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 +5 -4
- package/server/services/workshop/runtime/manager/runtime-wiring.ts +17 -1
- package/shared/config/schema.json +2 -0
- package/.output/public/_nuxt/4wrEQ3np2.js +0 -21
- package/.output/public/_nuxt/CGQvF-Gg.js +0 -14
- package/.output/public/_nuxt/CcGuXiOa.js +0 -1
- 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/c64014ca-3595-4b7a-a5ca-055687c83ba2.json +0 -1
- package/.output/server/chunks/build/_id_-BUpQSlzo.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkshopApi-CO3ophqt.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
|
@@ -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
|
})
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { readValidatedBody } from 'h3'
|
|
2
2
|
import { userRegisterSchema, type UserRegister } from '../../schemas/user.schema'
|
|
3
3
|
import { userService } from '../../services/user.service'
|
|
4
|
+
import { userRepository } from '../../repositories/user.repository'
|
|
5
|
+
import { settingOf } from '../../services/workshop/settings'
|
|
6
|
+
import { AppError } from '../../utils/errors'
|
|
4
7
|
import { defineApiHandler } from '../../utils/response'
|
|
5
8
|
import { zValidator } from '../../utils/validate'
|
|
6
9
|
|
|
7
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* POST /api/users/register —— 公开注册(name + email + password),签发首个 token。
|
|
12
|
+
* 公网部署闸门:security.allowRegistration=false 且首管理员已就位时关闭自助注册
|
|
13
|
+
* (首 admin 引导不受此门限制;默认 true 保持"用户可自助注册"的产品语义)。
|
|
14
|
+
*/
|
|
8
15
|
export default defineApiHandler(async (event) => {
|
|
16
|
+
if (settingOf('security.allowRegistration') === false && userRepository.hasActiveAdmin()) {
|
|
17
|
+
throw new AppError(403, 'REGISTRATION_CLOSED', '自助注册已关闭(security.allowRegistration=false),请联系管理员开通账号')
|
|
18
|
+
}
|
|
9
19
|
const body = await readValidatedBody(event, zValidator(userRegisterSchema)) as UserRegister
|
|
10
20
|
return userService.register(body)
|
|
11
21
|
})
|
|
@@ -246,7 +246,7 @@ function bearerTokenOf(event: H3Event): string | undefined {
|
|
|
246
246
|
return match?.[1]?.trim()
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
/**
|
|
249
|
+
/** 取消任务:一律以 Bearer token 关联的 agent 身份(无 token 一律 401,不再以 lead 系统身份回退) */
|
|
250
250
|
async function cancelTaskWithCaller(
|
|
251
251
|
manager: AgentChannelManager,
|
|
252
252
|
event: H3Event,
|
|
@@ -254,13 +254,23 @@ async function cancelTaskWithCaller(
|
|
|
254
254
|
): Promise<WorkspaceTask> {
|
|
255
255
|
const token = bearerTokenOf(event)
|
|
256
256
|
const caller = token ? manager.findByToken(token) : undefined
|
|
257
|
-
if (caller)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
if (!caller) throw new AppError(401, 'UNAUTHORIZED', 'tasks/cancel 需要有效 Agent token(Authorization: Bearer)')
|
|
258
|
+
return manager.cancelTask(caller.channelId, caller.id, { taskId })
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* A2A 统一身份门:Bearer token 必须有效,且 URL agent 与 caller 同 channel
|
|
263
|
+
* (编排器以自己 token 调同 channel 其他 agent 的端点是合法流;跨 channel/匿名一律拒绝)。
|
|
264
|
+
* 返回 URL 指向的目标 agent(作用域身份)。
|
|
265
|
+
*/
|
|
266
|
+
function requireA2ACaller(manager: AgentChannelManager, event: H3Event, agentId: string): AgentInfo {
|
|
267
|
+
const token = bearerTokenOf(event)
|
|
268
|
+
const caller = token ? manager.findByToken(token) : undefined
|
|
269
|
+
if (!caller) throw new AppError(401, 'UNAUTHORIZED', 'A2A 调用需要有效 Agent token(Authorization: Bearer)')
|
|
270
|
+
const target = findAgent(manager, agentId)
|
|
271
|
+
if (!target) throw new AppError(404, 'NOT_FOUND', `Agent not found: ${agentId}`)
|
|
272
|
+
if (target.channelId !== caller.channelId) throw new AppError(403, 'FORBIDDEN', 'A2A 目标 agent 与 token 身份不在同一 channel')
|
|
273
|
+
return target
|
|
264
274
|
}
|
|
265
275
|
|
|
266
276
|
// ===== SSE(tasks/sendSubscribe) =====
|
|
@@ -342,35 +352,35 @@ async function dispatch(
|
|
|
342
352
|
): Promise<unknown> {
|
|
343
353
|
switch (method) {
|
|
344
354
|
case 'tasks/send': {
|
|
355
|
+
const agent = requireA2ACaller(manager, event, agentId)
|
|
345
356
|
const p = parseParams(sendParamsSchema, params)
|
|
346
|
-
const agent = findAgent(manager, agentId) ?? fail(-32001, `Agent not found: ${agentId}`)
|
|
347
357
|
const task = await submitTask(manager, agent, p)
|
|
348
358
|
const final = await waitTerminal(manager, task.id)
|
|
349
359
|
return ok(id, toA2ATask(final))
|
|
350
360
|
}
|
|
351
361
|
case 'tasks/sendSubscribe': {
|
|
362
|
+
const agent = requireA2ACaller(manager, event, agentId)
|
|
352
363
|
const p = parseParams(sendParamsSchema, params)
|
|
353
|
-
const agent = findAgent(manager, agentId) ?? fail(-32001, `Agent not found: ${agentId}`)
|
|
354
364
|
const stream = createEventStream(event)
|
|
355
365
|
void runSubscribe(stream, manager, agent, p)
|
|
356
366
|
// h3 EventStream 必须经 send() 激活(否则被当普通对象 JSON 序列化,SSE 从未生效)
|
|
357
367
|
return stream.send()
|
|
358
368
|
}
|
|
359
369
|
case 'tasks/get': {
|
|
370
|
+
const agent = requireA2ACaller(manager, event, agentId)
|
|
360
371
|
const p = parseParams(taskIdParamsSchema, params)
|
|
361
|
-
const agent = findAgent(manager, agentId) ?? fail(-32001, `Agent not found: ${agentId}`)
|
|
362
372
|
const task = await manager.getTask(agent.channelId, agent.id, p.taskId)
|
|
363
373
|
return ok(id, toA2ATask(task))
|
|
364
374
|
}
|
|
365
375
|
case 'tasks/list': {
|
|
376
|
+
const agent = requireA2ACaller(manager, event, agentId)
|
|
366
377
|
parseParams(noopParamsSchema, params)
|
|
367
|
-
const agent = findAgent(manager, agentId) ?? fail(-32001, `Agent not found: ${agentId}`)
|
|
368
378
|
const tasks = await manager.listTasks(agent.channelId, agent.id)
|
|
369
379
|
return ok(id, tasks.map(toA2ATask))
|
|
370
380
|
}
|
|
371
381
|
case 'tasks/cancel': {
|
|
372
382
|
const p = parseParams(taskIdParamsSchema, params)
|
|
373
|
-
|
|
383
|
+
requireA2ACaller(manager, event, agentId)
|
|
374
384
|
const canceled = await cancelTaskWithCaller(manager, event, p.taskId)
|
|
375
385
|
return ok(id, toA2ATask(canceled))
|
|
376
386
|
}
|
|
@@ -24,6 +24,8 @@ const instantiateSchema = z.object({
|
|
|
24
24
|
optimizationMode: z.enum(['exploration', 'aml']).optional(),
|
|
25
25
|
boundModelId: z.string().min(1).optional(),
|
|
26
26
|
enableKnowledgeBase: z.boolean().optional(),
|
|
27
|
+
/** v18:实例化即绑定产线(只读扩权:成员可读该线日志/配方/历史/状态;写仍走节点授权) */
|
|
28
|
+
bindLineId: z.string().min(1).optional(),
|
|
27
29
|
})
|
|
28
30
|
|
|
29
31
|
export default defineApiHandler(async (event) => {
|
|
@@ -36,6 +38,10 @@ export default defineApiHandler(async (event) => {
|
|
|
36
38
|
if (result.leadAgentId) {
|
|
37
39
|
ensureLeadSchedulerLoop(manager, result.channelId)
|
|
38
40
|
}
|
|
41
|
+
// v18:实例化即绑定产线(新频道 owner = 实例化者;产线存在性在 bindChannelLine 内校验)
|
|
42
|
+
if (body.bindLineId) {
|
|
43
|
+
await manager.bindChannelLine(result.channelId, body.bindLineId)
|
|
44
|
+
}
|
|
39
45
|
// 常驻事件录制器(与 channels.post 同口径):确保无人 WS 订阅前事件也已持久化
|
|
40
46
|
const { ensureStream } = await import('../../ws')
|
|
41
47
|
ensureStream(manager, result.channelId)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PUT /api/workshop/channels/:id/line —— 绑定/解绑产线(v18)。
|
|
3
|
+
* body: { "lineId": "<产线id>" | null } (null/缺省 = 解绑)
|
|
4
|
+
*
|
|
5
|
+
* 只读扩权语义:绑定后频道成员无需节点绑定即可读取该产线的运维日志(ops_log)、
|
|
6
|
+
* 配方变更史(recipe_log/recipe_versions)与实时全景(line_context:运行状态/活动
|
|
7
|
+
* 批次/当前配方);参数下发等写操作仍必须走节点授权,不受绑定影响。
|
|
8
|
+
* 权限:channel owner / admin(与 PATCH channel 同一守卫)。
|
|
9
|
+
* 绑定变更回收成员运行时,下次装配注入产线简报(与场景 prompt 变更同链路)。
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod'
|
|
12
|
+
import { getRouterParam, readValidatedBody } from 'h3'
|
|
13
|
+
import { resolveUser } from '../../caller'
|
|
14
|
+
import { zValidator } from '../../../../utils/validate'
|
|
15
|
+
import { defineApiHandler } from '../../../../utils/response'
|
|
16
|
+
import { getWorkshopManager } from '../../../../plugins/workshop'
|
|
17
|
+
|
|
18
|
+
const bindLineSchema = z.object({
|
|
19
|
+
lineId: z.string().trim().nullable().optional(),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export default defineApiHandler(async (event) => {
|
|
23
|
+
const channelId = getRouterParam(event, 'id')!
|
|
24
|
+
const user = resolveUser(event)
|
|
25
|
+
const body = await readValidatedBody(event, zValidator(bindLineSchema))
|
|
26
|
+
const manager = getWorkshopManager()
|
|
27
|
+
manager.requireChannelOwner(channelId, user, 'channel')
|
|
28
|
+
const channel = await manager.bindChannelLine(channelId, body.lineId ?? '')
|
|
29
|
+
return { ok: true, lineId: channel.lineId, channel }
|
|
30
|
+
})
|
|
@@ -23,6 +23,12 @@ export default defineApiHandler(async (event) => {
|
|
|
23
23
|
const n = Number(v)
|
|
24
24
|
return v != null && v !== '' && Number.isFinite(n) ? n : undefined
|
|
25
25
|
}
|
|
26
|
+
// 边界健壮性:超大有限数/负数会打穿下游(SQLite OFFSET/负 LIMIT 等)→ 500;在门口校验成 400
|
|
27
|
+
for (const [k, v] of [['from', num(q.from)], ['to', num(q.to)], ['bucketMs', num(q.bucketMs)], ['limit', num(q.limit)]] as const) {
|
|
28
|
+
if (v !== undefined && (!Number.isSafeInteger(v) || v < 0)) {
|
|
29
|
+
throw new AppError(400, 'VALIDATION_ERROR', `查询参数 ${k} 必须为非负安全整数`)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
26
32
|
const result = await getDcwController().lineQuery({
|
|
27
33
|
lineId: q.lineId ? String(q.lineId) : undefined,
|
|
28
34
|
productId: q.productId ? String(q.productId) : undefined,
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
* 生成新版本(非破坏;历史完整保留)。body: { version?: number, toLastGood?: boolean, reason: string }。
|
|
4
4
|
*/
|
|
5
5
|
import { getRouterParam, readBody } from 'h3'
|
|
6
|
-
import {
|
|
6
|
+
import { requireRole } from '@/server/api/workshop/caller'
|
|
7
7
|
import { defineApiHandler } from '@/server/utils/response'
|
|
8
8
|
import { getDcwController } from '@/server/services/workshop/dcw/dcw-controller'
|
|
9
9
|
import { AppError, ErrorCodes } from '@/server/utils/errors'
|
|
10
10
|
|
|
11
11
|
export default defineApiHandler(async (event) => {
|
|
12
|
-
|
|
12
|
+
// 与 apply/rollback-good 同一角色门:配方回退是产线写操作,admin/editor 专属
|
|
13
|
+
const user = requireRole(event)
|
|
13
14
|
const id = getRouterParam(event, 'id') ?? ''
|
|
14
15
|
const body = await readBody<{ version?: number, toLastGood?: boolean, reason?: string }> (event) ?? {}
|
|
15
16
|
if (!body.toLastGood && body.version == null) {
|
|
@@ -10,12 +10,25 @@ import { getQuery } from 'h3'
|
|
|
10
10
|
import { resolveUser } from '../caller'
|
|
11
11
|
import { AppError } from '../../../utils/errors'
|
|
12
12
|
import { defineApiHandler } from '../../../utils/response'
|
|
13
|
+
import { resolveRunMode } from '@/shared/config/home.mjs'
|
|
14
|
+
import { isPathInside } from '@/sdk/index.mjs'
|
|
15
|
+
|
|
16
|
+
/** 允许浏览的根:项目检出根 + 生效配置根 + 数据目录(文件选择器只服务这些工作区) */
|
|
17
|
+
function allowedRoots(): string[] {
|
|
18
|
+
const rm = resolveRunMode({ cwd: process.cwd(), env: process.env })
|
|
19
|
+
return [...new Set([process.cwd(), rm.configRoot, rm.dataDir].map(r => resolve(r)))]
|
|
20
|
+
}
|
|
13
21
|
|
|
14
22
|
export default defineApiHandler(async (event) => {
|
|
15
23
|
resolveUser(event)
|
|
16
24
|
const q = getQuery(event)
|
|
17
25
|
const raw = typeof q.path === 'string' ? q.path.trim() : ''
|
|
18
26
|
const cwd = raw ? resolve(raw) : process.cwd()
|
|
27
|
+
const roots = allowedRoots()
|
|
28
|
+
// 越权防护:任意绝对路径列举整盘目录是公网部署下的信息泄露面,锁定到工作区白名单根内
|
|
29
|
+
if (!roots.some(r => cwd === r || isPathInside(r, cwd))) {
|
|
30
|
+
throw new AppError(403, 'FS_OUT_OF_ROOT', 'path 必须位于项目根或配置根内')
|
|
31
|
+
}
|
|
19
32
|
let entries: import('node:fs').Dirent[]
|
|
20
33
|
try {
|
|
21
34
|
entries = readdirSync(cwd, { withFileTypes: true })
|
|
@@ -35,6 +48,11 @@ export default defineApiHandler(async (event) => {
|
|
|
35
48
|
return { name: e.name, path: full, hasChildren }
|
|
36
49
|
})
|
|
37
50
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
38
|
-
|
|
51
|
+
// parent 链同样不许逃出白名单根(到根即断,防止逐级上探)
|
|
52
|
+
const parent = (() => {
|
|
53
|
+
const up = dirname(cwd)
|
|
54
|
+
if (up === cwd) return null
|
|
55
|
+
return roots.some(r => up === r || isPathInside(r, up)) ? up : null
|
|
56
|
+
})()
|
|
39
57
|
return { cwd, parent, isAbsoluteRoot: !isAbsolute(cwd), dirs }
|
|
40
58
|
})
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* 返回 { logs: [...], count }。行结构 = audit_log 投影(id/actor/actorKind/kind/summary/detailJson…)。
|
|
5
5
|
*/
|
|
6
6
|
import { getQuery } from 'h3'
|
|
7
|
-
import {
|
|
7
|
+
import { requireRole } from '@/server/api/workshop/caller'
|
|
8
8
|
import { defineApiHandler } from '@/server/utils/response'
|
|
9
9
|
import { getOps } from '../../../services/workshop/ops/ops'
|
|
10
10
|
import { AppError } from '../../../utils/errors'
|
|
11
11
|
|
|
12
12
|
export default defineApiHandler(async (event) => {
|
|
13
|
-
|
|
13
|
+
// 全局审计台账含跨产线运维信息,收权到 admin/editor(普通用户走产线维度自己的记录)
|
|
14
|
+
requireRole(event)
|
|
14
15
|
const repo = getOps()?.audit
|
|
15
16
|
if (!repo)
|
|
16
17
|
throw new AppError(503, 'UNAVAILABLE', '运维日志仓储未就绪')
|
|
@@ -10,12 +10,19 @@ import { readValidatedBody } from 'h3'
|
|
|
10
10
|
import { zValidator } from '../../../utils/validate'
|
|
11
11
|
import { defineApiHandler } from '../../../utils/response'
|
|
12
12
|
import { userService } from '../../../services/user.service'
|
|
13
|
+
import { userRepository } from '../../../repositories/user.repository'
|
|
14
|
+
import { settingOf } from '../../../services/workshop/settings'
|
|
15
|
+
import { AppError } from '../../../utils/errors'
|
|
13
16
|
|
|
14
17
|
const schema = z.object({
|
|
15
18
|
name: z.string().trim().min(1, 'name 必填').max(64, 'name 过长'),
|
|
16
19
|
})
|
|
17
20
|
|
|
18
21
|
export default defineApiHandler(async (event) => {
|
|
22
|
+
// 公网部署闸门:与 /api/users/register 同一开关(首 admin 未就位时不受限)
|
|
23
|
+
if (settingOf('security.allowRegistration') === false && userRepository.hasActiveAdmin()) {
|
|
24
|
+
throw new AppError(403, 'REGISTRATION_CLOSED', '自助注册已关闭(security.allowRegistration=false),请联系管理员开通账号')
|
|
25
|
+
}
|
|
19
26
|
const body = await readValidatedBody(event, zValidator(schema))
|
|
20
27
|
const name = body.name.trim()
|
|
21
28
|
const email = `${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${Date.now()}@workshop.local`
|
|
@@ -112,7 +112,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
112
112
|
.optional(),
|
|
113
113
|
},
|
|
114
114
|
},
|
|
115
|
-
async (args) => {
|
|
115
|
+
async (args, extra) => {
|
|
116
|
+
requireCaller(manager, extra)
|
|
116
117
|
const result = await manager.createChannel({
|
|
117
118
|
name: args.name,
|
|
118
119
|
description: args.description,
|
|
@@ -128,8 +129,11 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
128
129
|
description: '全部 channel',
|
|
129
130
|
inputSchema: {},
|
|
130
131
|
},
|
|
131
|
-
async () => {
|
|
132
|
-
|
|
132
|
+
async (_args, extra) => {
|
|
133
|
+
const caller = requireCaller(manager, extra)
|
|
134
|
+
// 隔离:Agent 只能看到自己所在 channel(与 workshop.agent.list 同哲学)
|
|
135
|
+
const all = await manager.listChannels()
|
|
136
|
+
return jsonResult(all.filter(c => c.id === caller.channelId))
|
|
133
137
|
},
|
|
134
138
|
)
|
|
135
139
|
|
|
@@ -139,7 +143,9 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
139
143
|
description: '删除(级联)',
|
|
140
144
|
inputSchema: { channelId: z.string() },
|
|
141
145
|
},
|
|
142
|
-
async (args) => {
|
|
146
|
+
async (args, extra) => {
|
|
147
|
+
const caller = requireCaller(manager, extra)
|
|
148
|
+
if (args.channelId !== caller.channelId) throw new Error('FORBIDDEN: 只能删除自己所在 channel')
|
|
143
149
|
await manager.removeChannel(args.channelId)
|
|
144
150
|
return jsonResult({ ok: true })
|
|
145
151
|
},
|
|
@@ -157,7 +163,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
157
163
|
config: z.record(z.string(), z.unknown()).optional(),
|
|
158
164
|
},
|
|
159
165
|
},
|
|
160
|
-
async (args) => {
|
|
166
|
+
async (args, extra) => {
|
|
167
|
+
requireCaller(manager, extra)
|
|
161
168
|
const result = await manager.createAgent({
|
|
162
169
|
name: args.name,
|
|
163
170
|
harness: args.harness,
|
|
@@ -177,7 +184,9 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
177
184
|
role: z.enum(['lead', 'worker']),
|
|
178
185
|
},
|
|
179
186
|
},
|
|
180
|
-
async (args) => {
|
|
187
|
+
async (args, extra) => {
|
|
188
|
+
const caller = requireCaller(manager, extra)
|
|
189
|
+
if (args.channelId !== caller.channelId) throw new Error('FORBIDDEN: 只能向自己所在 channel 添加 Agent')
|
|
181
190
|
const result = await manager.addAgentToChannel({
|
|
182
191
|
channelId: args.channelId,
|
|
183
192
|
agentId: args.agentId,
|
|
@@ -193,7 +202,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
193
202
|
description: '列出全部 Agent 模板(全局可复用)',
|
|
194
203
|
inputSchema: {},
|
|
195
204
|
},
|
|
196
|
-
async () => {
|
|
205
|
+
async (_args, extra) => {
|
|
206
|
+
requireCaller(manager, extra)
|
|
197
207
|
return jsonResult(await manager.listAgents())
|
|
198
208
|
},
|
|
199
209
|
)
|
|
@@ -216,7 +226,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
216
226
|
description: '删除 Agent 模板(已克隆实例保留)',
|
|
217
227
|
inputSchema: { agentId: z.string() },
|
|
218
228
|
},
|
|
219
|
-
async (args) => {
|
|
229
|
+
async (args, extra) => {
|
|
230
|
+
requireCaller(manager, extra)
|
|
220
231
|
await manager.removeAgent(args.agentId)
|
|
221
232
|
return jsonResult({ ok: true })
|
|
222
233
|
},
|
|
@@ -235,7 +246,9 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
235
246
|
parts: z.array(partSchema).optional(),
|
|
236
247
|
},
|
|
237
248
|
},
|
|
238
|
-
async (args) => {
|
|
249
|
+
async (args, extra) => {
|
|
250
|
+
const caller = requireCaller(manager, extra)
|
|
251
|
+
if (args.channelId !== caller.channelId) throw new Error('FORBIDDEN: 只能向自己所在 channel 提交任务')
|
|
239
252
|
const result = await manager.submitChannelTask({
|
|
240
253
|
channelId: args.channelId,
|
|
241
254
|
title: args.title,
|
|
@@ -441,7 +454,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
441
454
|
description: '列出数字孪生设备(含 telemetry/state/desired)。Agent 据此判断哪些设备可控、当前状态如何。',
|
|
442
455
|
inputSchema: { workspaceId: z.string().optional() },
|
|
443
456
|
},
|
|
444
|
-
async (args) => {
|
|
457
|
+
async (args, extra) => {
|
|
458
|
+
requireCaller(manager, extra)
|
|
445
459
|
return jsonResult(getDeviceTwinRepo().listAll(args.workspaceId))
|
|
446
460
|
},
|
|
447
461
|
)
|
|
@@ -452,7 +466,8 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
452
466
|
description: '读取单个设备实时遥测 + 运行状态 + 可用指令集。数字人作业前先 read 感知设备当前情况。',
|
|
453
467
|
inputSchema: { deviceId: z.string() },
|
|
454
468
|
},
|
|
455
|
-
async (args) => {
|
|
469
|
+
async (args, extra) => {
|
|
470
|
+
requireCaller(manager, extra)
|
|
456
471
|
const twin = getDeviceTwinRepo().findById(args.deviceId)
|
|
457
472
|
if (!twin) throw new Error(`NOT_FOUND: 设备不存在 ${args.deviceId}`)
|
|
458
473
|
return jsonResult(twin)
|
|
@@ -469,7 +484,11 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
469
484
|
args: z.record(z.string(), z.unknown()).optional(),
|
|
470
485
|
},
|
|
471
486
|
},
|
|
472
|
-
async (args) => {
|
|
487
|
+
async (args, extra) => {
|
|
488
|
+
const caller = requireCaller(manager, extra)
|
|
489
|
+
const bound = getDeviceTwinRepo().findById(args.deviceId)
|
|
490
|
+
if (!bound) throw new Error(`NOT_FOUND: 设备不存在 ${args.deviceId}`)
|
|
491
|
+
if (bound.boundAgentId && bound.boundAgentId !== caller.id) throw new Error('FORBIDDEN: 设备已被其他 Agent 绑定')
|
|
473
492
|
const twin = getDeviceTwinRepo().applyControl(args.deviceId, args.command, args.args ?? {})
|
|
474
493
|
if (!twin) throw new Error(`NOT_FOUND: 设备不存在 ${args.deviceId}`)
|
|
475
494
|
return jsonResult(twin)
|
|
@@ -485,7 +504,11 @@ export function createWorkshopMcpServer(manager: AgentChannelManager): McpServer
|
|
|
485
504
|
telemetry: z.record(z.string(), z.union([z.number(), z.string(), z.boolean()])),
|
|
486
505
|
},
|
|
487
506
|
},
|
|
488
|
-
async (args) => {
|
|
507
|
+
async (args, extra) => {
|
|
508
|
+
const caller = requireCaller(manager, extra)
|
|
509
|
+
const bound = getDeviceTwinRepo().findById(args.deviceId)
|
|
510
|
+
if (!bound) throw new Error(`NOT_FOUND: 设备不存在 ${args.deviceId}`)
|
|
511
|
+
if (bound.boundAgentId && bound.boundAgentId !== caller.id) throw new Error('FORBIDDEN: 设备已被其他 Agent 绑定')
|
|
489
512
|
const twin = getDeviceTwinRepo().applyTelemetry(args.deviceId, args.telemetry)
|
|
490
513
|
if (!twin) throw new Error(`NOT_FOUND: 设备不存在 ${args.deviceId}`)
|
|
491
514
|
return jsonResult({ state: twin.state, telemetry: twin.telemetry })
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安全响应头(公网部署基线)—— 全站统一附加:
|
|
3
|
+
* - X-Content-Type-Options / X-Frame-Options / Referrer-Policy / Permissions-Policy
|
|
4
|
+
* - CSP:自托管 SPA 语义('self' + inline 样式/脚本;Nuxt 水合与 antd cssinjs 需要 inline)
|
|
5
|
+
* - HSTS:security.hstsEnabled 设置开启才下发(前提=已上 TLS,反代/隧道终结亦可)
|
|
6
|
+
* 纯 setHeader,不读 body、不阻塞;设置读取走 3s TTL 缓存(settingOf)。
|
|
7
|
+
*/
|
|
8
|
+
import { defineEventHandler, getRequestURL, setResponseHeader } from 'h3'
|
|
9
|
+
import { settingOf } from '../services/workshop/settings'
|
|
10
|
+
|
|
11
|
+
const CSP = [
|
|
12
|
+
'default-src \'self\'',
|
|
13
|
+
'script-src \'self\' \'unsafe-inline\' \'unsafe-eval\'',
|
|
14
|
+
'style-src \'self\' \'unsafe-inline\'',
|
|
15
|
+
'img-src \'self\' data: blob: https:',
|
|
16
|
+
'font-src \'self\' data:',
|
|
17
|
+
'connect-src \'self\' ws: wss:',
|
|
18
|
+
'media-src \'self\' blob:',
|
|
19
|
+
'object-src \'none\'',
|
|
20
|
+
'base-uri \'self\'',
|
|
21
|
+
'frame-ancestors \'none\'',
|
|
22
|
+
'form-action \'self\'',
|
|
23
|
+
].join('; ')
|
|
24
|
+
|
|
25
|
+
export default defineEventHandler((event) => {
|
|
26
|
+
if (!event.node?.res) return
|
|
27
|
+
setResponseHeader(event, 'X-Content-Type-Options', 'nosniff')
|
|
28
|
+
setResponseHeader(event, 'X-Frame-Options', 'DENY')
|
|
29
|
+
setResponseHeader(event, 'Referrer-Policy', 'strict-origin-when-cross-origin')
|
|
30
|
+
setResponseHeader(event, 'Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=()')
|
|
31
|
+
setResponseHeader(event, 'Content-Security-Policy', CSP)
|
|
32
|
+
const url = getRequestURL(event)
|
|
33
|
+
if (url.pathname.startsWith('/api/')) setResponseHeader(event, 'Cache-Control', 'no-store')
|
|
34
|
+
// HSTS 只在设置开启时下发(未上 TLS 时下发会锁死 http 访问)
|
|
35
|
+
if (settingOf('security.hstsEnabled') === true) {
|
|
36
|
+
setResponseHeader(event, 'Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
|
|
37
|
+
}
|
|
38
|
+
})
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP 防护门(公网部署基线)——单中间件四件事,内存滑窗,无外部依赖:
|
|
3
|
+
* 1. User-Agent 黑名单:默认拦常见扫描器(sqlmap/nikto/nuclei…),AW_UA_BLOCKLIST 可追加(正则段,| 分隔)
|
|
4
|
+
* 2. 请求体上限:Content-Length 超限 413(AW_BODY_LIMIT_MB,默认 64MB)
|
|
5
|
+
* 3. 频率限流:/api 认证面(login/register/mcp/a2a)严限,A其余 API 宽限(AW_RATE_LIMIT_API_PER_MIN,默认 600)
|
|
6
|
+
* 4. 404 扫描封锁:1 分钟内 /api/* 404 超过阈值(AW_SCAN_404_LIMIT,默认 60)→ 封 IP 10 分钟(反爬/反目录爆破)
|
|
7
|
+
* 旁路:AW_RATE_LIMIT_OFF=1 或 AW_BENCH_MODE=1(基准隔离实例)整体停用;
|
|
8
|
+
* 全部状态内存态(重启即清),多实例部署时反代层应另配限流。
|
|
9
|
+
*/
|
|
10
|
+
import { defineEventHandler, createError, getRequestIP, getRequestHeaders, getRequestURL } from 'h3'
|
|
11
|
+
|
|
12
|
+
const g = globalThis as typeof globalThis & {
|
|
13
|
+
__awRateBuckets?: Map<string, { count: number, reset: number }>
|
|
14
|
+
__awScanHits?: Map<string, { count: number, reset: number }>
|
|
15
|
+
__awScanBlocked?: Map<string, number>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const envNum = (v: string | undefined, dflt: number) => {
|
|
19
|
+
const n = Number(v)
|
|
20
|
+
return Number.isFinite(n) && n > 0 ? n : dflt
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const OFF = process.env.AW_RATE_LIMIT_OFF === '1' || process.env.AW_BENCH_MODE === '1'
|
|
24
|
+
const AUTH_LIMIT = envNum(process.env.AW_RATE_LIMIT_AUTH_PER_MIN, 20)
|
|
25
|
+
const API_LIMIT = envNum(process.env.AW_RATE_LIMIT_API_PER_MIN, 600)
|
|
26
|
+
const SCAN_LIMIT = envNum(process.env.AW_SCAN_404_LIMIT, 60)
|
|
27
|
+
const BODY_LIMIT_MB = envNum(process.env.AW_BODY_LIMIT_MB, 64)
|
|
28
|
+
const BLOCK_MS = 10 * 60_000
|
|
29
|
+
const WINDOW_MS = 60_000
|
|
30
|
+
// 默认 UA 黑名单:公认攻击工具,不含任何浏览器/爬虫正常名(正常搜索引擎爬虫由 robots.txt 约束)
|
|
31
|
+
const UA_RE = new RegExp(process.env.AW_UA_BLOCKLIST
|
|
32
|
+
|| 'sqlmap|nikto|nuclei|masscan|zgrab|dirbuster|gobuster|wfuzz|ffuf|hydra|acunetix|nessus|arachni', 'i')
|
|
33
|
+
|
|
34
|
+
/** 认证/敏感面(严限):登录、注册、MCP、A2A */
|
|
35
|
+
function isAuthFace(pathname: string): boolean {
|
|
36
|
+
return pathname.startsWith('/api/users/login')
|
|
37
|
+
|| pathname.startsWith('/api/users/register')
|
|
38
|
+
|| pathname.startsWith('/api/workshop/users/register')
|
|
39
|
+
|| pathname.startsWith('/api/mcp/')
|
|
40
|
+
|| pathname.includes('/a2a/')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function bucketOf(map: Map<string, { count: number, reset: number }>, key: string, limit: number, now: number): number {
|
|
44
|
+
const b = map.get(key)
|
|
45
|
+
if (!b || b.reset <= now) {
|
|
46
|
+
map.set(key, { count: 1, reset: now + WINDOW_MS })
|
|
47
|
+
return limit - 1
|
|
48
|
+
}
|
|
49
|
+
b.count += 1
|
|
50
|
+
// 可为负:第 N+1 发起 remaining < 0,由调用方判 429(勿钳 0,否则永不触发)
|
|
51
|
+
return limit - b.count
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default defineEventHandler((event) => {
|
|
55
|
+
if (OFF) return
|
|
56
|
+
const url = getRequestURL(event)
|
|
57
|
+
const path = url.pathname
|
|
58
|
+
const ip = getRequestIP(event, { xForwardedFor: true }) ?? 'local'
|
|
59
|
+
const now = Date.now()
|
|
60
|
+
|
|
61
|
+
// 已封锁 IP(404 扫描触发):直接 403,不看别的
|
|
62
|
+
const blockedUntil = g.__awScanBlocked?.get(ip)
|
|
63
|
+
if (blockedUntil && blockedUntil > now) {
|
|
64
|
+
throw createError({ statusCode: 403, statusMessage: `IP temporarily blocked (scanning): retry after ${Math.ceil((blockedUntil - now) / 1000)}s` })
|
|
65
|
+
}
|
|
66
|
+
if (blockedUntil && g.__awScanBlocked) g.__awScanBlocked.delete(ip)
|
|
67
|
+
|
|
68
|
+
// UA 黑名单(全路径,扫描器对静态面也探)
|
|
69
|
+
const ua = getRequestHeaders(event)['user-agent'] ?? ''
|
|
70
|
+
if (ua && UA_RE.test(ua)) {
|
|
71
|
+
throw createError({ statusCode: 403, statusMessage: 'User agent not allowed' })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 请求体上限(带 Content-Length 才拦;chunked 走 nitro 默认)
|
|
75
|
+
const len = Number(getRequestHeaders(event)['content-length'] ?? 0)
|
|
76
|
+
if (len > BODY_LIMIT_MB * 1024 * 1024) {
|
|
77
|
+
throw createError({ statusCode: 413, statusMessage: `Request body too large (limit ${BODY_LIMIT_MB}MB)` })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 只对 /api/* 限流(静态/页面不做)
|
|
81
|
+
if (path.startsWith('/api/')) {
|
|
82
|
+
if (!g.__awRateBuckets) g.__awRateBuckets = new Map()
|
|
83
|
+
const limit = isAuthFace(path) ? AUTH_LIMIT : API_LIMIT
|
|
84
|
+
const remaining = bucketOf(g.__awRateBuckets, `${ip}|${limit}`, limit, now)
|
|
85
|
+
if (remaining < 0) {
|
|
86
|
+
throw createError({ statusCode: 429, statusMessage: 'Too many requests: slow down' })
|
|
87
|
+
}
|
|
88
|
+
// 404 扫描计数(res finish 时回填;blocked 判定在下轮请求入口生效)
|
|
89
|
+
if (!g.__awScanHits) g.__awScanHits = new Map()
|
|
90
|
+
const res = event.node?.res
|
|
91
|
+
if (!res) return
|
|
92
|
+
res.once('finish', () => {
|
|
93
|
+
if (res.statusCode !== 404) return
|
|
94
|
+
const hits = bucketOf(g.__awScanHits!, `${ip}`, SCAN_LIMIT, Date.now())
|
|
95
|
+
if (hits <= 0) {
|
|
96
|
+
if (!g.__awScanBlocked) g.__awScanBlocked = new Map()
|
|
97
|
+
g.__awScanBlocked.set(ip, Date.now() + BLOCK_MS)
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
})
|