agentworkshop 0.7.54 → 0.7.59
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 +2418 -2184
- package/.env.example +1 -0
- package/.output/.AgentWorkShop/prompts/host-tools.json +2418 -2184
- package/.output/.AgentWorkShop/schema.json +140 -138
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/2pU5BiaQ2.js +1 -0
- package/.output/public/_nuxt/{BdF9OAZq2.js → 4RTUlYvj2.js} +1 -1
- package/.output/public/_nuxt/AuthGate.Cvsc4atp.css +1 -0
- package/.output/public/_nuxt/B-Y_rsfn.js +106 -0
- package/.output/public/_nuxt/{BhcbvVOa2.js → B02cxZz72.js} +1 -1
- package/.output/public/_nuxt/{DNZmwhSD.js → B03LfmKR.js} +1 -1
- package/.output/public/_nuxt/{BZtgVXC5.js → B4R5CHkk.js} +3 -3
- package/.output/public/_nuxt/{B3zB6K6m.js → BAqtRt0q.js} +1 -1
- package/.output/public/_nuxt/BDC8YDyc.js +1 -0
- package/.output/public/_nuxt/{uY58gQqR2.js → BG7XSX-S2.js} +1 -1
- package/.output/public/_nuxt/{DUribplv2.js → BH30ZaLl2.js} +1 -1
- package/.output/public/_nuxt/BKHd_sKD2.js +47 -0
- package/.output/public/_nuxt/{S9rLP7_v.js → BMUEVeOK.js} +1 -1
- package/.output/public/_nuxt/{D9TpiWjt.js → BMZ1d25O.js} +1 -1
- package/.output/public/_nuxt/{DFhyhDGa2.js → BNl_jGa12.js} +1 -1
- package/.output/public/_nuxt/{BxoaZc_U2.js → BSG-4Ecg2.js} +1 -1
- package/.output/public/_nuxt/{BPqXOlYX.js → BU7WuuKh.js} +1 -1
- package/.output/public/_nuxt/{BP8TgWo02.js → BVH9j8dQ2.js} +1 -1
- package/.output/public/_nuxt/{C7_F68I7.js → BXKCB3rS.js} +1 -1
- package/.output/public/_nuxt/{DioKmYyB2.js → Bd85nb9X2.js} +1 -1
- package/.output/public/_nuxt/BhrnGVGz.js +1 -0
- package/.output/public/_nuxt/BikIgp9R.js +1 -0
- package/.output/public/_nuxt/Bj7BcqHn.js +1 -0
- package/.output/public/_nuxt/BkGqyjWm.js +3 -0
- package/.output/public/_nuxt/{CP0Nep9S.js → BkO2MZZU.js} +1 -1
- package/.output/public/_nuxt/{KXjvpIk2.js → Bn1N3mJv.js} +1 -1
- package/.output/public/_nuxt/Br2LgfbH2.js +13 -0
- package/.output/public/_nuxt/BrFF_9742.js +1 -0
- package/.output/public/_nuxt/{tKxYgsf-.js → BtDBBofS.js} +1 -1
- package/.output/public/_nuxt/BtNT93vm2.js +1 -0
- package/.output/public/_nuxt/{BxWvUgMz2.js → BtYg4aGR2.js} +1 -1
- package/.output/public/_nuxt/BuVH9MB-.js +1 -0
- package/.output/public/_nuxt/BupBjt6B2.js +1 -0
- package/.output/public/_nuxt/{D2Sm-GTk2.js → ByvqxkcN.js} +1 -1
- package/.output/public/_nuxt/{CzlUIbK32.js → BzKT-ne_2.js} +3 -3
- package/.output/public/_nuxt/{vPfDYgvR.js → C4X_Z1lA.js} +1 -1
- package/.output/public/_nuxt/C5wBzGO7.js +1 -0
- package/.output/public/_nuxt/{BgnhB8r5.js → C8uaVABF.js} +1 -1
- package/.output/public/_nuxt/{BmTzcKJg2.js → C98jxVaK.js} +1 -1
- package/.output/public/_nuxt/CBATzTUf.js +13 -0
- package/.output/public/_nuxt/{B9rIcCX12.js → CCCq9H7D2.js} +1 -1
- package/.output/public/_nuxt/{CvGYm7w8.js → CEP4UrDv.js} +1 -1
- package/.output/public/_nuxt/CHyzK5m52.js +1 -0
- package/.output/public/_nuxt/CIPKYgrH2.js +1 -0
- package/.output/public/_nuxt/{Drq9iy6V.js → CIz7SM4H.js} +1 -1
- package/.output/public/_nuxt/{PY2GW_3N2.js → CKE_kTL92.js} +1 -1
- package/.output/public/_nuxt/CPSHP_EI.js +1 -0
- package/.output/public/_nuxt/{DCPhrNWR2.js → CSyIwYcJ2.js} +1 -1
- package/.output/public/_nuxt/{v55S8LnT.js → CW1HGp5X.js} +1 -1
- package/.output/public/_nuxt/{Yv9YItEX2.js → CYGkUj5M2.js} +1 -1
- package/.output/public/_nuxt/{DppqsiPC.js → CZ0Gt81h.js} +2 -2
- package/.output/public/_nuxt/{Cg8Pgbeu.js → CZkTlW93.js} +2 -2
- package/.output/public/_nuxt/{Dz2SLIde.js → CZwDnomB.js} +1 -1
- package/.output/public/_nuxt/{DnAn2LgG.js → CZyYdpqZ2.js} +1 -1
- package/.output/public/_nuxt/{BJhsCisg2.js → CaBVMdqG2.js} +1 -1
- package/.output/public/_nuxt/{CMWyj56j.js → CeDkXWCz.js} +1 -1
- package/.output/public/_nuxt/{C-y_g11k.js → Cl19UD7U.js} +1 -1
- package/.output/public/_nuxt/ClEbKcuS.js +1 -0
- package/.output/public/_nuxt/{B4ujjkUI.js → ClrkV0C4.js} +1 -1
- package/.output/public/_nuxt/{nT-bgxvf.js → CmTqFlYZ.js} +1 -1
- package/.output/public/_nuxt/{deBcbALe2.js → CnF6dXcZ2.js} +1 -1
- package/.output/public/_nuxt/CoGETbe-2.js +1 -0
- package/.output/public/_nuxt/{Dq0emNZi2.js → CuRtzvsa2.js} +1 -1
- package/.output/public/_nuxt/{CBUIODly2.js → Cv_H1gOM2.js} +1 -1
- package/.output/public/_nuxt/{Cmp8PMrA.js → CxLxiOGV.js} +1 -1
- package/.output/public/_nuxt/{MbT4wXb62.js → D1Xw30Dj2.js} +1 -1
- package/.output/public/_nuxt/{DJyNDnag.js → D5hI4Fhu.js} +1 -1
- package/.output/public/_nuxt/D5i2ofVw2.js +1 -0
- package/.output/public/_nuxt/D6XGn5vM.js +2 -0
- package/.output/public/_nuxt/{DjefmmJu.js → D6c5ppqB.js} +1 -1
- package/.output/public/_nuxt/D8VQGThE.js +28 -0
- package/.output/public/_nuxt/{DmzmgYHb2.js → DBwuADr82.js} +1 -1
- package/.output/public/_nuxt/{DO9xaI9a.js → DEhjFhZ2.js} +1 -1
- package/.output/public/_nuxt/{DuPM4HXw.js → DIDbAMv5.js} +1 -1
- package/.output/public/_nuxt/{CfLUvgr32.js → DJZzthKt2.js} +1 -1
- package/.output/public/_nuxt/{Bpkm4W5P.js → DKhRushG.js} +1 -1
- package/.output/public/_nuxt/DLAFNaPf.js +1 -0
- package/.output/public/_nuxt/{DffgG8vT.js → DMPpE41S2.js} +1 -1
- package/.output/public/_nuxt/{CPeZNE4S2.js → DTZO6WMs2.js} +1 -1
- package/.output/public/_nuxt/{Dk6Zf3-L.js → DTx_DtUo.js} +1 -1
- package/.output/public/_nuxt/DYtV50yi2.js +1 -0
- package/.output/public/_nuxt/{CV61ysvv.js → DctCtJq7.js} +1 -1
- package/.output/public/_nuxt/{xX7ccjDl2.js → DelESEcl2.js} +1 -1
- package/.output/public/_nuxt/DfqRQSFn.js +19 -0
- package/.output/public/_nuxt/{BFZIll912.js → DgldLfCZ2.js} +1 -1
- package/.output/public/_nuxt/Dmgqz2np.js +16 -0
- package/.output/public/_nuxt/Do0dCE8C2.js +1 -0
- package/.output/public/_nuxt/DraEWn4N2.js +1 -0
- package/.output/public/_nuxt/{Bwc6lt2X.js → Drhta6gr.js} +2 -2
- package/.output/public/_nuxt/{Cn6ihm8j.js → Du0zf-d3.js} +1 -1
- package/.output/public/_nuxt/{DqtnqNgL2.js → DvUt9uMt2.js} +1 -1
- package/.output/public/_nuxt/{C5cf3T4d.js → Dxo1GW5U.js} +1 -1
- package/.output/public/_nuxt/{Ca3iDJwu2.js → Dy-V8OEW2.js} +9 -9
- package/.output/public/_nuxt/{BWowAAJb.js → DyMgrV29.js} +1 -1
- package/.output/public/_nuxt/{Dm_iKz8k2.js → Eo2BYEIo2.js} +1 -1
- package/.output/public/_nuxt/{aV6YPjg02.js → H7Rbu32y2.js} +1 -1
- package/.output/public/_nuxt/{vXrNItas2.js → KS3KQF222.js} +1 -1
- package/.output/public/_nuxt/{BjWbbMHs.js → M58CVYnv.js} +1 -1
- package/.output/public/_nuxt/M6NcguDO.js +1 -0
- package/.output/public/_nuxt/{CtPNnATm2.js → MEwEMEMl2.js} +6 -6
- package/.output/public/_nuxt/MW-V7IIP2.js +1 -0
- package/.output/public/_nuxt/{tq3HbWr9.js → P0EcfD3j.js} +1 -1
- package/.output/public/_nuxt/{CHrErv1E.js → TjGWqrHo.js} +1 -1
- package/.output/public/_nuxt/{TownView.Xt1yygrh.css → TownView.BuMpDRkf.css} +1 -1
- package/.output/public/_nuxt/VVomhVqu2.js +1 -0
- package/.output/public/_nuxt/{QHo9mN-M2.js → WYqAa0r52.js} +1 -1
- package/.output/public/_nuxt/YDs3mbQu2.js +1 -0
- package/.output/public/_nuxt/{Dep0Hc9w2.js → Z3MSTcdu2.js} +1 -1
- package/.output/public/_nuxt/_id_.DOqX4gwB.css +1 -0
- package/.output/public/_nuxt/_vR_sc7t.js +24 -0
- package/.output/public/_nuxt/{aml.-czpKIs8.css → aml.BeFTP6_M.css} +1 -1
- package/.output/public/_nuxt/bTFhJlrI2.js +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/92fd7e2e-18f2-45c3-8588-d93004dda6e3.json +1 -0
- package/.output/public/_nuxt/daq.YQas76du.css +1 -0
- package/.output/public/_nuxt/dcw.UIcWRyIS.css +1 -0
- package/.output/public/_nuxt/{default.CyLpQD1C.css → default.8ac6QU28.css} +1 -1
- package/.output/public/_nuxt/{entry.JdEG3KJg.css → entry.BHNNQA9H.css} +1 -1
- package/.output/public/_nuxt/{D-Xyb3DA.js → gbaq2UOO.js} +1 -1
- package/.output/public/_nuxt/goF_oZHF.js +2 -0
- package/.output/public/_nuxt/h46i74oE.js +14 -0
- package/.output/public/_nuxt/{Cpm5JYv4.js → iZa330UY.js} +1 -1
- package/.output/public/_nuxt/logs.Bf65Kw17.css +1 -0
- package/.output/public/_nuxt/lyJsJl_G.js +1 -0
- package/.output/public/_nuxt/o-G6YtmK2.js +1 -0
- package/.output/public/_nuxt/{BkfA3BbD.js → pNy4V4kd.js} +1 -1
- package/.output/public/_nuxt/{C_sjV3Ee.js → pncSmP5n.js} +1 -1
- package/.output/public/_nuxt/{DVOR2pWg.js → qIQFsHtF.js} +1 -1
- package/.output/public/_nuxt/town.DFotRPod.css +1 -0
- package/.output/public/_nuxt/workshop.BX2YeO0g.css +1 -0
- package/.output/public/_nuxt/yPlLXpEw2.js +1 -0
- package/.output/public/_nuxt/ylowSquM2.js +1 -0
- package/.output/public/_nuxt/{Da0h_6VA.js → zGDAozGA.js} +4 -4
- package/.output/server/chunks/_/binding-authz.mjs +8 -4
- package/.output/server/chunks/_/binding-authz.mjs.map +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 +22 -2
- package/.output/server/chunks/_/host-bindings.mjs.map +1 -1
- package/.output/server/chunks/_/nitro.mjs +13085 -8339
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
- package/.output/server/chunks/_/user.schema.mjs +5 -1
- package/.output/server/chunks/_/user.schema.mjs.map +1 -1
- package/.output/server/chunks/build/{workshop-BDqWzJtr.mjs → AuthGate-DDPYswkA.mjs} +22 -327
- package/.output/server/chunks/build/AuthGate-DDPYswkA.mjs.map +1 -0
- package/.output/server/chunks/build/FormItemContext-4ORSzhWv.mjs +1 -1
- package/.output/server/chunks/build/{OmpTerminalPanel-mk31gVzA.mjs → OmpTerminalPanel-DZ2wHMS1.mjs} +4 -4
- package/.output/server/chunks/build/{OmpTerminalPanel-mk31gVzA.mjs.map → OmpTerminalPanel-DZ2wHMS1.mjs.map} +1 -1
- package/.output/server/chunks/build/{TownView-Bf5VFYFj.mjs → TownView-CZbFn6mO.mjs} +216 -107
- package/.output/server/chunks/build/TownView-CZbFn6mO.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-WF20tjqT.mjs → _id_-CCVhpJtj.mjs} +7 -6
- package/.output/server/chunks/build/_id_-CCVhpJtj.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-CuUmVPRg.mjs → _id_-Df2pgsAq.mjs} +521 -94
- package/.output/server/chunks/build/_id_-Df2pgsAq.mjs.map +1 -0
- package/.output/server/chunks/build/{_wsId_-BUIKB68b.mjs → _wsId_-CJqF-hmP.mjs} +19 -19
- package/.output/server/chunks/build/{_wsId_-BUIKB68b.mjs.map → _wsId_-CJqF-hmP.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-DqICy4AL.mjs → agents-BTsbna5H.mjs} +13 -13
- package/.output/server/chunks/build/{agents-DqICy4AL.mjs.map → agents-BTsbna5H.mjs.map} +1 -1
- package/.output/server/chunks/build/{aml-C55iuLn-.mjs → aml-BBKfWto1.mjs} +28 -27
- package/.output/server/chunks/build/aml-BBKfWto1.mjs.map +1 -0
- package/.output/server/chunks/build/api-B4Om0mEc.mjs +2 -1
- package/.output/server/chunks/build/api-B4Om0mEc.mjs.map +1 -1
- package/.output/server/chunks/build/{card-CUSocE9p.mjs → card-DJOYGuVH.mjs} +4 -4
- package/.output/server/chunks/build/{card-CUSocE9p.mjs.map → card-DJOYGuVH.mjs.map} +1 -1
- package/.output/server/chunks/build/{channel-templates-gdCLajKy.mjs → channel-templates-BPKJ8e4l.mjs} +9 -9
- package/.output/server/chunks/build/{channel-templates-gdCLajKy.mjs.map → channel-templates-BPKJ8e4l.mjs.map} +1 -1
- package/.output/server/chunks/build/constants-HPHJvjne.mjs +2 -1
- package/.output/server/chunks/build/constants-HPHJvjne.mjs.map +1 -1
- package/.output/server/chunks/build/{daq-D0kLscVr.mjs → daq-Cz7TaUAM.mjs} +38 -29
- package/.output/server/chunks/build/daq-Cz7TaUAM.mjs.map +1 -0
- package/.output/server/chunks/build/{dcw-DuhEyu7S.mjs → dcw-EhjJpVQM.mjs} +45 -20
- package/.output/server/chunks/build/dcw-EhjJpVQM.mjs.map +1 -0
- package/.output/server/chunks/build/{default-aFGiNebw.mjs → default-DweMY872.mjs} +260 -48
- package/.output/server/chunks/build/{default-aFGiNebw.mjs.map → default-DweMY872.mjs.map} +1 -1
- package/.output/server/chunks/build/{dropdown-Yev6knaj.mjs → dropdown-CIsqbX4P.mjs} +2 -2
- package/.output/server/chunks/build/{dropdown-Yev6knaj.mjs.map → dropdown-CIsqbX4P.mjs.map} +1 -1
- package/.output/server/chunks/build/{dropdown-KdKWCS5K.mjs → dropdown-CV9GW3z9.mjs} +5 -5
- package/.output/server/chunks/build/{dropdown-KdKWCS5K.mjs.map → dropdown-CV9GW3z9.mjs.map} +1 -1
- package/.output/server/chunks/build/{form-uSlNqIAV.mjs → form-cs_RcfGx.mjs} +4 -5
- package/.output/server/chunks/build/{form-uSlNqIAV.mjs.map → form-cs_RcfGx.mjs.map} +1 -1
- package/.output/server/chunks/{_/SearchOutlined.mjs → build/input-CobQ5LJ5.mjs} +1476 -103
- package/.output/server/chunks/build/input-CobQ5LJ5.mjs.map +1 -0
- package/.output/server/chunks/build/{input-number-BRVnxeiA.mjs → input-number-BpPYAWMk.mjs} +4 -4
- package/.output/server/chunks/build/{input-number-BRVnxeiA.mjs.map → input-number-BpPYAWMk.mjs.map} +1 -1
- package/.output/server/chunks/build/{logs-BlOalbsZ.mjs → logs-As9fZqU-.mjs} +49 -35
- package/.output/server/chunks/build/logs-As9fZqU-.mjs.map +1 -0
- package/.output/server/chunks/build/{menu-BgkRSSx7.mjs → menu-CVmvHyFT.mjs} +3 -3
- package/.output/server/chunks/build/{menu-BgkRSSx7.mjs.map → menu-CVmvHyFT.mjs.map} +1 -1
- package/.output/server/chunks/build/{monitor-DX_K0WMq.mjs → monitor-CdFQ2z4g.mjs} +17 -17
- package/.output/server/chunks/build/{monitor-DX_K0WMq.mjs.map → monitor-CdFQ2z4g.mjs.map} +1 -1
- package/.output/server/chunks/build/{operations-BD6LK-Yz.mjs → operations-B2gHCWgZ.mjs} +7 -6
- package/.output/server/chunks/build/operations-B2gHCWgZ.mjs.map +1 -0
- package/.output/server/chunks/build/{pages-DloBBvU5.mjs → pages-BItCt1ar.mjs} +5 -4
- package/.output/server/chunks/build/pages-BItCt1ar.mjs.map +1 -0
- package/.output/server/chunks/build/{permissions-BvmodvsO.mjs → permissions-D6mQw_9j.mjs} +12 -12
- package/.output/server/chunks/build/{permissions-BvmodvsO.mjs.map → permissions-D6mQw_9j.mjs.map} +1 -1
- package/.output/server/chunks/build/plugins-NAS9MQ5r.mjs +2 -1
- package/.output/server/chunks/build/plugins-NAS9MQ5r.mjs.map +1 -1
- package/.output/server/chunks/build/{popconfirm-Ox-_2V8A.mjs → popconfirm-DFfoFhmt.mjs} +2 -2
- package/.output/server/chunks/build/{popconfirm-Ox-_2V8A.mjs.map → popconfirm-DFfoFhmt.mjs.map} +1 -1
- package/.output/server/chunks/build/{schedules-D8vYHgQ5.mjs → schedules-BjWNDWL5.mjs} +16 -16
- package/.output/server/chunks/build/{schedules-D8vYHgQ5.mjs.map → schedules-BjWNDWL5.mjs.map} +1 -1
- package/.output/server/chunks/build/{segmented-C61yLHvo.mjs → segmented-D7FkCgg7.mjs} +2 -2
- package/.output/server/chunks/build/{segmented-C61yLHvo.mjs.map → segmented-D7FkCgg7.mjs.map} +1 -1
- package/.output/server/chunks/build/{select-rdBWytVK.mjs → select-FqBNxgxT.mjs} +3 -3
- package/.output/server/chunks/build/{select-rdBWytVK.mjs.map → select-FqBNxgxT.mjs.map} +1 -1
- package/.output/server/chunks/build/{settings-B7HA-sdb.mjs → settings-Cl_KRyEn.mjs} +9 -9
- package/.output/server/chunks/build/{settings-B7HA-sdb.mjs.map → settings-Cl_KRyEn.mjs.map} +1 -1
- package/.output/server/chunks/build/{table-DOFAvY-v.mjs → table-CeOYERqr.mjs} +8 -9
- package/.output/server/chunks/build/{table-DOFAvY-v.mjs.map → table-CeOYERqr.mjs.map} +1 -1
- package/.output/server/chunks/build/{tabs-DTeIuZeP.mjs → tabs-LLNSdLl2.mjs} +5 -6
- package/.output/server/chunks/build/{tabs-DTeIuZeP.mjs.map → tabs-LLNSdLl2.mjs.map} +1 -1
- package/.output/server/chunks/build/{tag-CHLGvNM6.mjs → tag-Dwvkh0Dj.mjs} +2 -3
- package/.output/server/chunks/build/{tag-CHLGvNM6.mjs.map → tag-Dwvkh0Dj.mjs.map} +1 -1
- package/.output/server/chunks/build/{teams-wM-MdLv9.mjs → teams-CGDZHaQl.mjs} +11 -11
- package/.output/server/chunks/build/{teams-wM-MdLv9.mjs.map → teams-CGDZHaQl.mjs.map} +1 -1
- package/.output/server/chunks/build/{tokens-CloWk4x_.mjs → tokens-BOYkZuoB.mjs} +13 -13
- package/.output/server/chunks/build/{tokens-CloWk4x_.mjs.map → tokens-BOYkZuoB.mjs.map} +1 -1
- package/.output/server/chunks/build/{town-BIn3be5v.mjs → town-BV-hbwb5.mjs} +41 -6
- package/.output/server/chunks/build/town-BV-hbwb5.mjs.map +1 -0
- package/.output/server/chunks/build/{town-B2gBu_ZE.mjs → town-P1rYoi0v.mjs} +7 -6
- package/.output/server/chunks/build/town-P1rYoi0v.mjs.map +1 -0
- package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
- package/.output/server/chunks/build/useAgentHarnessOptions-BnFCh23W.mjs +2 -1
- package/.output/server/chunks/build/useAgentHarnessOptions-BnFCh23W.mjs.map +1 -1
- package/.output/server/chunks/build/useAgentTemplateActions-DsBRUQni.mjs +2 -1
- package/.output/server/chunks/build/useAgentTemplateActions-DsBRUQni.mjs.map +1 -1
- package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs +2 -1
- package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs.map +1 -1
- package/.output/server/chunks/build/useAgentTemplateForm-DzQ_t2Ue.mjs +2 -1
- package/.output/server/chunks/build/useAgentTemplateForm-DzQ_t2Ue.mjs.map +1 -1
- package/.output/server/chunks/build/useAgentTemplatesCatalog-Q7LgG1Af.mjs +2 -1
- package/.output/server/chunks/build/useAgentTemplatesCatalog-Q7LgG1Af.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs +2 -1
- package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlEntities-BMLHU_39.mjs +3 -2
- package/.output/server/chunks/build/useAmlEntities-BMLHU_39.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlEnv-DdlyVzPu.mjs +2 -1
- package/.output/server/chunks/build/useAmlEnv-DdlyVzPu.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs +2 -1
- package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs +2 -1
- package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs.map +1 -1
- package/.output/server/chunks/build/{useAmlJobs--a_1ovew.mjs → useAmlJobs-BG_v21hJ.mjs} +4 -3
- package/.output/server/chunks/build/useAmlJobs-BG_v21hJ.mjs.map +1 -0
- package/.output/server/chunks/build/useAmlModels-D7MuOWOy.mjs +2 -1
- package/.output/server/chunks/build/useAmlModels-D7MuOWOy.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlNotes-CTZe-GI0.mjs +2 -1
- package/.output/server/chunks/build/useAmlNotes-CTZe-GI0.mjs.map +1 -1
- package/.output/server/chunks/build/useAmlPredict-BToRrVRV.mjs +2 -1
- package/.output/server/chunks/build/useAmlPredict-BToRrVRV.mjs.map +1 -1
- package/.output/server/chunks/build/useDaqAddNode-CaOCbe4-.mjs +3 -2
- package/.output/server/chunks/build/useDaqAddNode-CaOCbe4-.mjs.map +1 -1
- package/.output/server/chunks/build/useDaqDetailBinding-C7AbGIdP.mjs +2 -1
- package/.output/server/chunks/build/useDaqDetailBinding-C7AbGIdP.mjs.map +1 -1
- package/.output/server/chunks/build/useDaqDetailFrames-CmAEdbAL.mjs +2 -1
- package/.output/server/chunks/build/useDaqDetailFrames-CmAEdbAL.mjs.map +1 -1
- package/.output/server/chunks/build/{useDaqDetailHistory-pfi6zXWU.mjs → useDaqDetailHistory-C4LWayu1.mjs} +4 -3
- package/.output/server/chunks/build/useDaqDetailHistory-C4LWayu1.mjs.map +1 -0
- package/.output/server/chunks/build/{useDaqDetailNode-qT7MjqJ7.mjs → useDaqDetailNode-DXgwAu5u.mjs} +5 -4
- package/.output/server/chunks/build/useDaqDetailNode-DXgwAu5u.mjs.map +1 -0
- package/.output/server/chunks/build/useDaqDetailParams-CrTMDs-2.mjs +3 -2
- package/.output/server/chunks/build/useDaqDetailParams-CrTMDs-2.mjs.map +1 -1
- package/.output/server/chunks/build/{useDaqFilters-CMysN13f.mjs → useDaqFilters-Jx6EERfr.mjs} +5 -4
- package/.output/server/chunks/build/useDaqFilters-Jx6EERfr.mjs.map +1 -0
- package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs +2 -1
- package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs.map +1 -1
- package/.output/server/chunks/build/{useDaqOptimizations-Coq5lsfM.mjs → useDaqOptimizations-C5N4bcu4.mjs} +4 -3
- package/.output/server/chunks/build/useDaqOptimizations-C5N4bcu4.mjs.map +1 -0
- package/.output/server/chunks/build/useDaqStream-DhzdoyIR.mjs +1 -1
- package/.output/server/chunks/build/useDaqTemplates-C7GzQmdJ.mjs +3 -2
- package/.output/server/chunks/build/useDaqTemplates-C7GzQmdJ.mjs.map +1 -1
- package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs +2 -1
- package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs.map +1 -1
- package/.output/server/chunks/build/{useDashboardData-DgJcGJaF.mjs → useDashboardData-Ce-EU5DJ.mjs} +4 -3
- package/.output/server/chunks/build/useDashboardData-Ce-EU5DJ.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwAddNode-C9DbEKHi.mjs → useDcwAddNode-4mTPQ6T8.mjs} +38 -4
- package/.output/server/chunks/build/useDcwAddNode-4mTPQ6T8.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwCards-VDoMYG7l.mjs → useDcwCards-DvLGgUYr.mjs} +4 -3
- package/.output/server/chunks/build/useDcwCards-DvLGgUYr.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwDetailScope-CL97tJdJ.mjs → useDcwDetailScope-4j3B03Pi.mjs} +4 -3
- package/.output/server/chunks/build/useDcwDetailScope-4j3B03Pi.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwDetailTemplates-OLmjMSGD.mjs → useDcwDetailTemplates-yzNEAMK-.mjs} +4 -3
- package/.output/server/chunks/build/useDcwDetailTemplates-yzNEAMK-.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwFilter-Bs9C6-h_.mjs → useDcwFilter-BQDmQYY0.mjs} +4 -3
- package/.output/server/chunks/build/useDcwFilter-BQDmQYY0.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwLedger-Bbf_iFOY.mjs → useDcwLedger-DWGufEor.mjs} +4 -3
- package/.output/server/chunks/build/useDcwLedger-DWGufEor.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwLineMutations-Bhtuqw7J.mjs → useDcwLineMutations-DHF-Bemn.mjs} +4 -3
- package/.output/server/chunks/build/useDcwLineMutations-DHF-Bemn.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwLineRun-CGqZSnG4.mjs → useDcwLineRun-VFe35xou.mjs} +4 -3
- package/.output/server/chunks/build/useDcwLineRun-VFe35xou.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwParamApprovals-BBwdFsKv.mjs → useDcwParamApprovals-Bc0BGBds.mjs} +8 -7
- package/.output/server/chunks/build/useDcwParamApprovals-Bc0BGBds.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwProducts-BoBkJqpv.mjs → useDcwProducts-DXisXYMh.mjs} +4 -3
- package/.output/server/chunks/build/useDcwProducts-DXisXYMh.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwQuery-DP7b2qb6.mjs → useDcwQuery-Cmo3UtIQ.mjs} +4 -3
- package/.output/server/chunks/build/useDcwQuery-Cmo3UtIQ.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwQuickActions-DHRiA9KN.mjs → useDcwQuickActions-BkAcxVnj.mjs} +4 -3
- package/.output/server/chunks/build/useDcwQuickActions-BkAcxVnj.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwRecipes-CIMeH2oF.mjs → useDcwRecipes-BvtGPQJ9.mjs} +16 -5
- package/.output/server/chunks/build/useDcwRecipes-BvtGPQJ9.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwStream-B9ugUWRq.mjs → useDcwStream-BXJ2V8HM.mjs} +12 -2
- package/.output/server/chunks/build/{useDcwStream-B9ugUWRq.mjs.map → useDcwStream-BXJ2V8HM.mjs.map} +1 -1
- package/.output/server/chunks/build/{useDcwTemplates-M_-qjV8E.mjs → useDcwTemplates-Zxz2DPdu.mjs} +4 -3
- package/.output/server/chunks/build/useDcwTemplates-Zxz2DPdu.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwWrites-D94dAzqr.mjs → useDcwWrites-66CKxcos.mjs} +4 -3
- package/.output/server/chunks/build/useDcwWrites-66CKxcos.mjs.map +1 -0
- package/.output/server/chunks/build/useExpConfirmations-BbInIHsn.mjs +106 -0
- package/.output/server/chunks/build/useExpConfirmations-BbInIHsn.mjs.map +1 -0
- package/.output/server/chunks/build/{useLocalTime-DZ2RAtVs.mjs → useLocalTime-CUnDHV5V.mjs} +8 -2
- package/.output/server/chunks/build/useLocalTime-CUnDHV5V.mjs.map +1 -0
- package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs +2 -1
- package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs.map +1 -1
- package/.output/server/chunks/build/useLogsManual-CMjD62nt.mjs +2 -1
- package/.output/server/chunks/build/useLogsManual-CMjD62nt.mjs.map +1 -1
- package/.output/server/chunks/build/{useLogsQuery-2x1mKxT1.mjs → useLogsQuery-C5nadU1m.mjs} +15 -4
- package/.output/server/chunks/build/useLogsQuery-C5nadU1m.mjs.map +1 -0
- package/.output/server/chunks/build/{useLogsScope-04cUJCU-.mjs → useLogsScope-DgrB1ur3.mjs} +4 -3
- package/.output/server/chunks/build/useLogsScope-DgrB1ur3.mjs.map +1 -0
- package/.output/server/chunks/build/useMonitorColumns-DhYvkLDq.mjs +2 -1
- package/.output/server/chunks/build/useMonitorColumns-DhYvkLDq.mjs.map +1 -1
- package/.output/server/chunks/build/{useMonitorData-guVjMDtR.mjs → useMonitorData-D2gFSonG.mjs} +4 -3
- package/.output/server/chunks/build/useMonitorData-D2gFSonG.mjs.map +1 -0
- package/.output/server/chunks/build/{useMonitorFormat-C7lhZe4g.mjs → useMonitorFormat-DRCXsKwh.mjs} +4 -3
- package/.output/server/chunks/build/useMonitorFormat-DRCXsKwh.mjs.map +1 -0
- package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs +2 -1
- package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs.map +1 -1
- package/.output/server/chunks/build/useOperationsFeed-DsA2ym7M.mjs +2 -1
- package/.output/server/chunks/build/useOperationsFeed-DsA2ym7M.mjs.map +1 -1
- package/.output/server/chunks/build/useOpsLog-SnWPuRtK.mjs.map +1 -1
- package/.output/server/chunks/build/useRecipeDispatchApprovals-CbL2El3n.mjs +155 -0
- package/.output/server/chunks/build/useRecipeDispatchApprovals-CbL2El3n.mjs.map +1 -0
- package/.output/server/chunks/build/useTeamActions-BOLQkYxg.mjs +2 -1
- package/.output/server/chunks/build/useTeamActions-BOLQkYxg.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamAddMemberDialog-BCgrLPxI.mjs +2 -1
- package/.output/server/chunks/build/useTeamAddMemberDialog-BCgrLPxI.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamCreateDialog-CJk40LqS.mjs +2 -1
- package/.output/server/chunks/build/useTeamCreateDialog-CJk40LqS.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamDeployDialog-49hdUXQP.mjs +2 -1
- package/.output/server/chunks/build/useTeamDeployDialog-49hdUXQP.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs +2 -1
- package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamPluginDialog-Dh-QOoiU.mjs +2 -1
- package/.output/server/chunks/build/useTeamPluginDialog-Dh-QOoiU.mjs.map +1 -1
- package/.output/server/chunks/build/useTeamsCatalog-HBSyKt5P.mjs +2 -1
- package/.output/server/chunks/build/useTeamsCatalog-HBSyKt5P.mjs.map +1 -1
- package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs +2 -1
- package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs.map +1 -1
- package/.output/server/chunks/build/useTokenCreate-DkYvEQUD.mjs +2 -1
- package/.output/server/chunks/build/useTokenCreate-DkYvEQUD.mjs.map +1 -1
- package/.output/server/chunks/build/useTokenRename-DOCP4aeI.mjs +2 -1
- package/.output/server/chunks/build/useTokenRename-DOCP4aeI.mjs.map +1 -1
- package/.output/server/chunks/build/useTokenReveal-CybwwflV.mjs +2 -1
- package/.output/server/chunks/build/useTokenReveal-CybwwflV.mjs.map +1 -1
- package/.output/server/chunks/build/useTokensList-BLiMvrc4.mjs +2 -1
- package/.output/server/chunks/build/useTokensList-BLiMvrc4.mjs.map +1 -1
- package/.output/server/chunks/build/{useWorkbenchAuth-DqjBX-6w.mjs → useWorkbenchAuth-DAabQl7X.mjs} +6 -2
- package/.output/server/chunks/build/useWorkbenchAuth-DAabQl7X.mjs.map +1 -0
- package/.output/server/chunks/build/{useWorkbenchWorkspaces-GQVU9BLv.mjs → useWorkbenchWorkspaces-6-mpCGCR.mjs} +5 -4
- package/.output/server/chunks/build/useWorkbenchWorkspaces-6-mpCGCR.mjs.map +1 -0
- package/.output/server/chunks/build/{useWorkshopWs-CgeCsaYJ.mjs → useWorkshopWs-CM-Ywk4h.mjs} +2 -2
- package/.output/server/chunks/build/{useWorkshopWs-CgeCsaYJ.mjs.map → useWorkshopWs-CM-Ywk4h.mjs.map} +1 -1
- package/.output/server/chunks/build/useWorkspaceAuth-Dlvj9csD.mjs +2 -1
- package/.output/server/chunks/build/useWorkspaceAuth-Dlvj9csD.mjs.map +1 -1
- package/.output/server/chunks/build/{useWorkspaceChannels-B13vROC1.mjs → useWorkspaceChannels--65yU02b.mjs} +5 -4
- package/.output/server/chunks/build/useWorkspaceChannels--65yU02b.mjs.map +1 -0
- package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs +2 -1
- package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs.map +1 -1
- package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs +2 -1
- package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs.map +1 -1
- package/.output/server/chunks/build/{users-CCf5PgRs.mjs → users-B_pHStEa.mjs} +13 -13
- package/.output/server/chunks/build/{users-CCf5PgRs.mjs.map → users-B_pHStEa.mjs.map} +1 -1
- package/.output/server/chunks/build/workshop-C0DefygA.mjs +522 -0
- package/.output/server/chunks/build/workshop-C0DefygA.mjs.map +1 -0
- package/.output/server/chunks/routes/api/health.get.mjs +12 -2
- package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +4 -3
- package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/mcp/workshop.mjs +3 -2
- package/.output/server/chunks/routes/api/mcp/workshop.mjs.map +1 -1
- package/.output/server/chunks/routes/api/metrics.mjs +11 -1
- package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +2 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/i18n.get.mjs +2 -1
- package/.output/server/chunks/routes/api/plugins/i18n.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +2 -1
- package/.output/server/chunks/routes/api/plugins/manifest.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/backup/list.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/backup/list.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/backup/run.post.mjs +4 -3
- package/.output/server/chunks/routes/api/system/backup/run.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/config.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/config.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.post.mjs +2 -1
- package/.output/server/chunks/routes/api/system/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index2.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +2 -1
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +2 -1
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/monitor.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +2 -1
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/timezone.get.mjs +2 -1
- package/.output/server/chunks/routes/api/system/timezone.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/users/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.put.mjs +2 -1
- package/.output/server/chunks/routes/api/users/_id_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/change-password.post.mjs +35 -0
- package/.output/server/chunks/routes/api/users/change-password.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/users/index.get.mjs +3 -2
- package/.output/server/chunks/routes/api/users/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/index.post.mjs +4 -3
- package/.output/server/chunks/routes/api/users/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/login.post.mjs +4 -3
- package/.output/server/chunks/routes/api/users/login.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/logout.post.mjs +3 -2
- package/.output/server/chunks/routes/api/users/logout.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/me.get.mjs +3 -2
- package/.output/server/chunks/routes/api/users/me.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/register.post.mjs +3 -2
- package/.output/server/chunks/routes/api/users/register.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/setup-status.get.mjs +6 -3
- package/.output/server/chunks/routes/api/users/setup-status.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +3 -2
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +4 -3
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/_...path_.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/_...path_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +2 -1
- 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 +2 -1
- package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +15 -5
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +24 -3
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +48 -8
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/caller.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/caller.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +5 -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_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/messages/_messageId/read.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/messages/_messageId/read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/permissions.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/permissions.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index6.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index6.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs +9 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId/approve.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId/approve.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/join.post.mjs +5 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/join.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/leave.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/members/leave.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/channels.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +18 -5
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +15 -12
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +7 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +15 -14
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +12 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +16 -5
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +6 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index7.get.mjs +30 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index7.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +3 -2
- 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 +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/mes-artifacts/file.get.mjs +62 -0
- package/.output/server/chunks/routes/api/workshop/dcw/mes-artifacts/file.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/dcw/mes-hook-test.post.mjs +99 -0
- package/.output/server/chunks/routes/api/workshop/dcw/mes-hook-test.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/dcw/mes-test-read.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/mes-test-read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +7 -4
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +7 -4
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +7 -4
- 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 +7 -4
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/exp/confirmations/_id/decide.post.mjs +55 -0
- package/.output/server/chunks/routes/api/workshop/exp/confirmations/_id/decide.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/exp/index.get.mjs +38 -0
- package/.output/server/chunks/routes/api/workshop/exp/index.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +3 -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 +3 -2
- package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +8 -2
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +6 -3
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index.put.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index11.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index11.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index12.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index12.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index13.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index13.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index14.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index14.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs +8 -4
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs +8 -4
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs +3 -1
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/index9.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/runtime.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id/run.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id/run.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/reassign.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/reassign.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/reopen.post.mjs +48 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/reopen.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/update.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/update.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/tasks.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/users/me.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +2 -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 +4 -3
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +2 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/renderer.mjs +3 -3
- package/.output/server/chunks/virtual/entry.mjs +250 -57
- package/.output/server/chunks/virtual/entry.mjs.map +1 -1
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +2 -1
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/package.json +1 -1
- package/LICENSE +69 -91
- package/README-zh.md +928 -833
- package/README.md +949 -845
- package/app/components/AppSidebar.vue +1 -1
- package/app/components/aml/AmlEnvPanel.vue +230 -230
- package/app/components/app-header/LoginModal.vue +131 -0
- package/app/components/app-header/UserChip.vue +161 -150
- package/app/components/dcw/DcwAddNodeModal.vue +29 -1
- package/app/components/dcw/DcwEditLineModal.vue +216 -108
- package/app/components/dcw/DcwLineCard.vue +129 -117
- package/app/components/dcw/DcwMesArtifacts.vue +140 -0
- package/app/components/dcw/DcwNodesTable.vue +9 -0
- package/app/components/dcw/DcwParamApprovalCard.vue +116 -110
- package/app/components/dcw/DcwRecipeEditModal.vue +399 -306
- package/app/components/dcw/ExpConfirmCard.vue +103 -0
- package/app/components/dcw/RecipeDispatchApprovalCard.vue +330 -0
- package/app/components/dcw/RecipeGateApprovalCard.vue +159 -0
- package/app/components/logs/LogsEventTable.vue +321 -309
- package/app/components/logs/LogsFilterCard.vue +253 -234
- package/app/components/workshop/DaqNodeRow.vue +616 -592
- package/app/components/workshop/town/TownView.vue +6 -2
- package/app/components/workshop/town/components/AutoModeConfirmModal.vue +94 -0
- package/app/components/workshop/town/components/TownAgentBindings.vue +18 -2
- package/app/components/workshop/town/components/TownAgentInspector.vue +10 -2
- package/app/components/workshop/town/components/TownRightRail.vue +4 -1
- package/app/components/workshop/workbench/AuthGate.vue +182 -179
- package/app/components/workshop/workbench/ChangePasswordModal.vue +106 -0
- package/app/composables/workshop/town/town-relay-props.ts +6 -1
- package/app/composables/workshop/town/useTownAgentBindings.ts +73 -6
- package/app/composables/workshop/useDcwStream.ts +374 -362
- package/app/composables/workshop/useOpsLog.ts +3 -0
- package/app/layouts/default.vue +201 -161
- package/app/layouts/town.vue +40 -21
- package/app/pages/daq/composables/useDaqDetailHistory.ts +199 -199
- package/app/pages/dcw/[id].vue +380 -318
- package/app/pages/dcw/composables/useDcwAddNode.ts +29 -0
- package/app/pages/dcw/composables/useDcwParamApprovals.ts +123 -119
- package/app/pages/dcw/composables/useDcwRecipes.ts +256 -242
- package/app/pages/dcw/composables/useExpConfirmations.ts +108 -0
- package/app/pages/dcw/composables/useRecipeDispatchApprovals.ts +200 -0
- package/app/pages/dcw/dcw-page.css +360 -344
- package/app/pages/dcw/index.vue +11 -0
- package/app/pages/logs/composables/useLogsQuery.ts +57 -52
- package/app/pages/logs/index.vue +95 -94
- package/app/pages/workshop/composables/useWorkbenchAuth.ts +131 -125
- package/app/pages/workshop/index.vue +121 -116
- package/app/plugins/http.ts +6 -0
- package/app/stores/workshop/auth-ui.ts +26 -0
- package/app/stores/workshop/user.ts +19 -2
- package/cli/commands/mcp.mjs +6 -0
- package/config.yml +180 -180
- package/docker-compose.yml +4 -0
- package/docs/cli.en.md +447 -447
- package/docs/cli.md +412 -412
- package/docs/plugins.en.md +621 -621
- package/docs/plugins.md +610 -610
- package/docs/sdk.en.md +964 -964
- package/docs/sdk.md +900 -900
- package/i18n/locales/en.ts +2812 -2738
- package/i18n/locales/zh-CN.ts +2812 -2738
- package/mcp/aw-mcp-server.mjs +4 -1
- package/package.json +181 -181
- package/scripts/_audit/feature-audit-e2e.mjs +12 -9
- package/scripts/_audit/idd-scenarios-e2e.mjs +239 -0
- package/scripts/aw-start-smoke.mjs +7 -1
- package/scripts/check-docs-sync.mjs +417 -367
- package/scripts/dev-guard.mjs +2 -1
- package/scripts/dev-mes-simulator.mjs +456 -0
- package/scripts/feature-sweep-e2e.mjs +176 -0
- package/scripts/onboarding/forge-channel.mjs +157 -0
- package/scripts/onboarding/lib.mjs +78 -0
- package/scripts/onboarding/onboard.mjs +196 -0
- package/scripts/onboarding/provision-line.mjs +179 -0
- package/scripts/onboarding/test-connection.mjs +42 -0
- package/scripts/onboarding/verify-line.mjs +95 -0
- package/scripts/perm-isolation-e2e.mjs +188 -0
- package/scripts/render-opt-curve.mjs +97 -0
- package/scripts/render-pressure-curve.mjs +89 -0
- package/scripts/start.mjs +126 -2
- package/scripts/testing/aep-live.mjs +60 -0
- package/scripts/testing/aggregate-benchmarks.mjs +79 -0
- package/scripts/testing/api-full-loop.mjs +172 -0
- package/scripts/testing/benchmark.config.json +66 -0
- package/scripts/testing/game-host.mjs +63 -0
- package/scripts/testing/hitl-expert.mjs +143 -0
- package/scripts/testing/idd-kb-smoke.mjs +46 -0
- package/scripts/testing/run-benchmark.mjs +984 -0
- package/scripts/testing/sdk-live.mjs +55 -0
- package/scripts/ui/e2e-interactive.mjs +14 -14
- package/scripts/ui/lib.mjs +210 -210
- package/server/api/health.get.ts +12 -1
- package/server/api/metrics.ts +89 -78
- package/server/api/users/change-password.post.ts +18 -0
- package/server/api/users/setup-status.get.ts +13 -8
- package/server/api/workshop/agent-tools/approvals/[id]/decide.post.ts +21 -6
- package/server/api/workshop/agent-tools/bindings/[id].patch.ts +36 -3
- package/server/api/workshop/agent-tools/bindings/index.post.ts +60 -9
- package/server/api/workshop/caller.ts +3 -2
- package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +1 -1
- package/server/api/workshop/channels/[id]/line.put.ts +41 -30
- package/server/api/workshop/channels/[id]/members/join.post.ts +35 -30
- package/server/api/workshop/channels.post.ts +13 -0
- package/server/api/workshop/daq/index.post.ts +6 -1
- package/server/api/workshop/daq/test-driver.post.ts +3 -3
- package/server/api/workshop/dcw/index.post.ts +26 -20
- package/server/api/workshop/dcw/lines/[id].delete.ts +3 -2
- package/server/api/workshop/dcw/lines/[id].patch.ts +5 -3
- package/server/api/workshop/dcw/lines/index.post.ts +1 -1
- package/server/api/workshop/dcw/mes-artifacts/file.get.ts +50 -0
- package/server/api/workshop/dcw/mes-artifacts/index.get.ts +27 -0
- package/server/api/workshop/dcw/mes-hook-test.post.ts +105 -0
- package/server/api/workshop/dcw/products/index.post.ts +6 -2
- package/server/api/workshop/dcw/recipes/[id]/apply.post.ts +6 -2
- package/server/api/workshop/dcw/recipes/[id]/mark-good.post.ts +6 -2
- package/server/api/workshop/dcw/recipes/[id]/revert.post.ts +33 -29
- package/server/api/workshop/dcw/recipes/[id]/rollback-good.post.ts +7 -3
- package/server/api/workshop/dcw/recipes/index.post.ts +27 -15
- package/server/api/workshop/exp/confirmations/[id]/decide.post.ts +41 -0
- package/server/api/workshop/exp/confirmations/index.get.ts +25 -0
- package/server/api/workshop/hitl/pending.get.ts +57 -48
- package/server/api/workshop/hitl/respond.post.ts +10 -2
- package/server/api/workshop/ops-logs/index.get.ts +1 -0
- package/server/api/workshop/tasks/[id]/reopen.post.ts +35 -0
- package/server/api/workshop/ws/peer-sub.ts +135 -128
- package/server/api/workshop/ws/subscriptions.ts +15 -1
- package/server/plugins/backup.ts +94 -11
- package/server/plugins/daq.ts +3 -0
- package/server/plugins/memory-watch.ts +92 -0
- package/server/plugins/parent-watch.ts +22 -0
- package/server/plugins/workshop.ts +258 -230
- package/server/plugins-builtin/diag-bridge/client.mjs +49 -1
- package/server/plugins-builtin/diag-bridge/host/diagnosis.mjs +15 -6
- package/server/plugins-builtin/diag-bridge/host/exports.mjs +104 -0
- package/server/plugins-builtin/diag-bridge/host/plugin.mjs +120 -17
- package/server/plugins-builtin/diag-bridge/host/sweep.mjs +47 -0
- package/server/plugins-builtin/diag-bridge/i18n.json +82 -72
- package/server/repositories/user.repository.ts +36 -12
- package/server/schemas/user.schema.ts +7 -0
- package/server/services/user.service.ts +50 -8
- package/server/services/workshop/agents/agent-interface.ts +1 -1
- package/server/services/workshop/agents/base-agent.ts +8 -1
- package/server/services/workshop/agents/binding-authz.ts +8 -5
- package/server/services/workshop/agents/binding-mode.ts +51 -0
- package/server/services/workshop/agents/hitl-decision/dispatcher.ts +16 -3
- package/server/services/workshop/agents/hitl-decision/index.ts +24 -24
- package/server/services/workshop/agents/hitl-decision/line-of.ts +38 -0
- package/server/services/workshop/agents/hitl-decision/reconcile.ts +152 -70
- package/server/services/workshop/agents/hitl-decision/shared.ts +2 -0
- package/server/services/workshop/agents/hitl-registry.ts +582 -577
- package/server/services/workshop/agents/host-tool-bridge/catalog.ts +86 -2
- package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +25 -0
- package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +13 -1
- package/server/services/workshop/agents/host-tool-bridge/tools/memory.ts +4 -1
- package/server/services/workshop/agents/host-tool-bridge/tools/messaging.ts +45 -11
- package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +5 -1
- package/server/services/workshop/agents/industrial/aml-activity.ts +131 -0
- package/server/services/workshop/agents/industrial/aml-dataset-tools.ts +21 -0
- package/server/services/workshop/agents/industrial/aml-job-tools.ts +9 -3
- package/server/services/workshop/agents/industrial/daq-export.ts +510 -0
- package/server/services/workshop/agents/industrial/dcw-judge-tools.ts +160 -149
- package/server/services/workshop/agents/industrial/dcw-tools.ts +68 -21
- package/server/services/workshop/agents/industrial/exp-tools.ts +104 -0
- package/server/services/workshop/agents/industrial/grant-guard.ts +145 -0
- package/server/services/workshop/agents/industrial/index.ts +4 -0
- package/server/services/workshop/agents/industrial/line-tools.ts +151 -0
- package/server/services/workshop/agents/industrial/manual-approval.ts +3 -2
- package/server/services/workshop/agents/industrial/mes-tools.ts +143 -135
- package/server/services/workshop/agents/industrial/ops-tools.ts +267 -68
- package/server/services/workshop/agents/industrial/optimization-tools.ts +19 -9
- package/server/services/workshop/agents/industrial/param-tools.ts +192 -169
- package/server/services/workshop/agents/industrial/recipe-gate.ts +96 -0
- package/server/services/workshop/agents/industrial/recipe-propose-tools.ts +366 -0
- package/server/services/workshop/agents/industrial/twin-tools.ts +38 -4
- package/server/services/workshop/agents/industrial-context.ts +122 -24
- package/server/services/workshop/agents/mock-agent.ts +17 -0
- package/server/services/workshop/agents/node-bindings.repo.ts +207 -206
- package/server/services/workshop/agents/node-delegation.ts +4 -4
- package/server/services/workshop/agents/omp-agent/event-mapping.ts +178 -142
- package/server/services/workshop/agents/tool-approvals.ts +261 -13
- package/server/services/workshop/aml/dataset-builder.ts +8 -1
- package/server/services/workshop/aml/env-manager.ts +242 -242
- package/server/services/workshop/aml/job-orchestrator/failure.ts +19 -0
- package/server/services/workshop/aml/job-orchestrator/stages.ts +27 -0
- package/server/services/workshop/aml/python-runtime.ts +600 -552
- package/server/services/workshop/aml/twin/binding-snapshot.ts +637 -603
- package/server/services/workshop/aml/twin/channel-profile.ts +3 -2
- package/server/services/workshop/daq/bus/queue-port.ts +3 -0
- package/server/services/workshop/daq/daq-controller/crud.ts +206 -202
- package/server/services/workshop/daq/daq-controller/driver-probe.ts +64 -64
- package/server/services/workshop/daq/daq-controller/ingest.ts +189 -189
- package/server/services/workshop/daq/daq-controller/state.ts +204 -197
- package/server/services/workshop/daq/daq-controller/views.ts +85 -84
- package/server/services/workshop/daq/daq-node.repo.ts +27 -4
- package/server/services/workshop/daq/daq-node.ts +4 -2
- package/server/services/workshop/daq/daq-runtime.ts +2 -1
- package/server/services/workshop/daq/drivers/index.ts +29 -29
- package/server/services/workshop/daq/drivers/mqtt.ts +217 -182
- package/server/services/workshop/daq/drivers/registry.ts +35 -1
- package/server/services/workshop/daq/drivers/shared.ts +63 -60
- package/server/services/workshop/daq/objectstore/disk.adapter.ts +48 -2
- package/server/services/workshop/daq/objectstore/gc.ts +92 -0
- package/server/services/workshop/daq/objectstore/objectstore-port.ts +12 -0
- package/server/services/workshop/daq/storage/sqlite.adapter.ts +318 -318
- package/server/services/workshop/daq/storage/timescale.adapter.ts +37 -3
- package/server/services/workshop/db/database/migrations.ts +12 -1
- package/server/services/workshop/db/database/open.ts +5 -1
- package/server/services/workshop/db/database/rows.ts +4 -0
- package/server/services/workshop/db/database/schema.ts +7 -2
- package/server/services/workshop/db/database/seed.ts +71 -0
- package/server/services/workshop/db/memory.repo.ts +1 -1
- package/server/services/workshop/db/ops.repo.ts +24 -7
- package/server/services/workshop/dcw/dcw-controller/actuation.ts +140 -127
- package/server/services/workshop/dcw/dcw-controller/bindings.ts +97 -83
- package/server/services/workshop/dcw/dcw-controller/crud.ts +19 -4
- package/server/services/workshop/dcw/dcw-controller/gate-persist.ts +80 -0
- package/server/services/workshop/dcw/dcw-controller/lines.ts +229 -213
- package/server/services/workshop/dcw/dcw-controller/recipes.ts +286 -196
- package/server/services/workshop/dcw/dcw-controller/state.ts +71 -66
- package/server/services/workshop/dcw/dcw-controller/write-verify.ts +98 -0
- package/server/services/workshop/dcw/dcw-controller/write.ts +51 -9
- package/server/services/workshop/dcw/dcw-line.repo.ts +17 -1
- package/server/services/workshop/dcw/dcw-node.repo.ts +110 -87
- package/server/services/workshop/dcw/dcw-node.ts +8 -3
- package/server/services/workshop/dcw/dcw-recipe.repo.ts +32 -0
- package/server/services/workshop/dcw/dcw-runtime.ts +8 -1
- package/server/services/workshop/dcw/drivers/http.ts +68 -66
- package/server/services/workshop/dcw/drivers/index.ts +27 -27
- package/server/services/workshop/dcw/drivers/mes-rest.ts +707 -543
- package/server/services/workshop/dcw/drivers/mock.ts +47 -44
- package/server/services/workshop/dcw/drivers/modbus-rtu.ts +1 -1
- package/server/services/workshop/dcw/drivers/modbus.ts +1 -1
- package/server/services/workshop/dcw/drivers/mqtt.ts +109 -108
- package/server/services/workshop/dcw/drivers/opcua.ts +1 -1
- package/server/services/workshop/dcw/drivers/registry.ts +142 -100
- package/server/services/workshop/dcw/drivers/shared.ts +186 -161
- package/server/services/workshop/dcw/param-map.repo.ts +349 -321
- package/server/services/workshop/dcw/recipe-op-anchor.ts +117 -0
- package/server/services/workshop/dcw/recipe-rollback.repo.ts +26 -0
- package/server/services/workshop/exp/exp-collector.ts +275 -0
- package/server/services/workshop/exp/exp-state.repo.ts +339 -0
- package/server/services/workshop/json-store.mjs +137 -105
- package/server/services/workshop/mes/mes-controller.ts +274 -26
- package/server/services/workshop/mes/mes-datasets.ts +503 -441
- package/server/services/workshop/mes/mes-hook.ts +567 -0
- package/server/services/workshop/ops/ops.ts +3 -0
- package/server/services/workshop/permissions.ts +7 -7
- package/server/services/workshop/plugin-driver-registry.ts +123 -108
- package/server/services/workshop/plugins/host/services.mjs +10 -0
- package/server/services/workshop/prompts/loader.ts +11 -2
- package/server/services/workshop/runtime/agent-runtime/lifecycle.ts +18 -0
- package/server/services/workshop/runtime/agent-runtime/message.ts +10 -0
- package/server/services/workshop/runtime/line-notify.ts +76 -0
- package/server/services/workshop/runtime/manager/access.ts +488 -483
- package/server/services/workshop/runtime/manager/channel-templates.ts +21 -2
- package/server/services/workshop/runtime/manager/runtime-wiring.ts +96 -1
- package/server/services/workshop/runtime/manager/state.ts +106 -1
- package/server/services/workshop/runtime/manager/tasks.ts +67 -4
- package/server/services/workshop/runtime/manager/workspace.ts +8 -2
- package/server/services/workshop/runtime/memory/recall.ts +20 -1
- package/server/services/workshop/runtime/memory/write.ts +149 -93
- package/server/services/workshop/runtime/platform-notice.ts +113 -0
- package/server/services/workshop/runtime/scheduler-loop/execute.ts +44 -12
- package/server/services/workshop/runtime/scheduler-loop/rules.ts +24 -7
- package/server/services/workshop/runtime/scheduler-loop/tick.ts +44 -1
- package/server/services/workshop/runtime/task-engine/lifecycle.ts +11 -0
- package/server/services/workshop/runtime/task-engine/update.ts +11 -0
- package/server/services/workshop/settings.ts +17 -0
- package/server/types/user.ts +4 -0
- package/server/utils/errors.ts +1 -0
- package/server/utils/response.ts +6 -0
- package/shared/config/schema.json +140 -138
- package/shared/config/single-instance.mjs +28 -1
- package/shared/daq-protocol.ts +12 -2
- package/shared/dcw-protocol/catalog.ts +6 -1
- package/shared/dcw-protocol/index.ts +19 -19
- package/shared/dcw-protocol/line.ts +34 -0
- package/shared/dcw-protocol/recipe.ts +33 -3
- package/shared/local-time.mjs +37 -13
- package/shared/workshop-protocol.ts +4 -0
- package/.output/public/_nuxt/B2x8SKRO2.js +0 -1
- package/.output/public/_nuxt/BOhcoxIu.js +0 -2
- package/.output/public/_nuxt/BQy0Yy7S.js +0 -1
- package/.output/public/_nuxt/BTVyPFng2.js +0 -1
- package/.output/public/_nuxt/BXR3tgEk.js +0 -1
- package/.output/public/_nuxt/B_9_BM9G.js +0 -3
- package/.output/public/_nuxt/BcX4fktE.js +0 -1
- package/.output/public/_nuxt/Bfe2qOYs.js +0 -1
- package/.output/public/_nuxt/BnoyYd0Z2.js +0 -1
- package/.output/public/_nuxt/BqYO-UfR.js +0 -1
- package/.output/public/_nuxt/Btv3HXrq.js +0 -1
- package/.output/public/_nuxt/BuXaEtBG2.js +0 -1
- package/.output/public/_nuxt/Bub2P5me.js +0 -28
- package/.output/public/_nuxt/CAaSPBqk.js +0 -1
- package/.output/public/_nuxt/CD9lpEz22.js +0 -13
- package/.output/public/_nuxt/CFjveTJh.js +0 -1
- package/.output/public/_nuxt/CI2yXRr42.js +0 -1
- package/.output/public/_nuxt/COQM2L1M.js +0 -1
- package/.output/public/_nuxt/Ch9KdZWb2.js +0 -1
- package/.output/public/_nuxt/CtXOpljm2.js +0 -1
- package/.output/public/_nuxt/CwLQAKay2.js +0 -1
- package/.output/public/_nuxt/DB4ma-iU2.js +0 -1
- package/.output/public/_nuxt/DV5joWTn2.js +0 -47
- package/.output/public/_nuxt/DVKXGuMz2.js +0 -1
- package/.output/public/_nuxt/DZDi8inD.js +0 -1
- package/.output/public/_nuxt/DZuXfuXS.js +0 -14
- package/.output/public/_nuxt/Db4_F1T2.js +0 -1
- package/.output/public/_nuxt/DlX0nqUe.js +0 -1
- package/.output/public/_nuxt/Dqz5HiXa.js +0 -2
- package/.output/public/_nuxt/I1cI6sPJ2.js +0 -1
- package/.output/public/_nuxt/Sjjmp5OD2.js +0 -1
- package/.output/public/_nuxt/WVTVkqef.js +0 -1
- package/.output/public/_nuxt/_id_.DZbVLNnu.css +0 -1
- package/.output/public/_nuxt/a4X3ARNm2.js +0 -1
- package/.output/public/_nuxt/bt__BP-I.js +0 -13
- package/.output/public/_nuxt/builds/meta/af879435-fc74-4017-ade0-3b92c1ab35bb.json +0 -1
- package/.output/public/_nuxt/cY_5jwFz2.js +0 -1
- package/.output/public/_nuxt/daq.0uieKcZk.css +0 -1
- package/.output/public/_nuxt/dcw.pQRVkAi_.css +0 -1
- package/.output/public/_nuxt/eutnXI4F.js +0 -24
- package/.output/public/_nuxt/k5K6Jj6g.js +0 -19
- package/.output/public/_nuxt/logs.CD0Olr3c.css +0 -1
- package/.output/public/_nuxt/wDPc4SSR.js +0 -106
- package/.output/public/_nuxt/workshop.b4YRXEe0.css +0 -1
- package/.output/server/chunks/_/SearchOutlined.mjs.map +0 -1
- package/.output/server/chunks/build/TownView-Bf5VFYFj.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-CuUmVPRg.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-WF20tjqT.mjs.map +0 -1
- package/.output/server/chunks/build/aml-C55iuLn-.mjs.map +0 -1
- package/.output/server/chunks/build/daq-D0kLscVr.mjs.map +0 -1
- package/.output/server/chunks/build/dcw-DuhEyu7S.mjs.map +0 -1
- package/.output/server/chunks/build/input-Cr_KFj4T.mjs +0 -1381
- package/.output/server/chunks/build/input-Cr_KFj4T.mjs.map +0 -1
- package/.output/server/chunks/build/logs-BlOalbsZ.mjs.map +0 -1
- package/.output/server/chunks/build/operations-BD6LK-Yz.mjs.map +0 -1
- package/.output/server/chunks/build/pages-DloBBvU5.mjs.map +0 -1
- package/.output/server/chunks/build/town-B2gBu_ZE.mjs.map +0 -1
- package/.output/server/chunks/build/town-BIn3be5v.mjs.map +0 -1
- package/.output/server/chunks/build/useAmlJobs--a_1ovew.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqDetailHistory-pfi6zXWU.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqDetailNode-qT7MjqJ7.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqFilters-CMysN13f.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqOptimizations-Coq5lsfM.mjs.map +0 -1
- package/.output/server/chunks/build/useDashboardData-DgJcGJaF.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwAddNode-C9DbEKHi.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwCards-VDoMYG7l.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwDetailScope-CL97tJdJ.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwDetailTemplates-OLmjMSGD.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwFilter-Bs9C6-h_.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwLedger-Bbf_iFOY.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwLineMutations-Bhtuqw7J.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwLineRun-CGqZSnG4.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwParamApprovals-BBwdFsKv.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwProducts-BoBkJqpv.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwQuery-DP7b2qb6.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwQuickActions-DHRiA9KN.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwRecipes-CIMeH2oF.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwTemplates-M_-qjV8E.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwWrites-D94dAzqr.mjs.map +0 -1
- package/.output/server/chunks/build/useLocalTime-DZ2RAtVs.mjs.map +0 -1
- package/.output/server/chunks/build/useLogsQuery-2x1mKxT1.mjs.map +0 -1
- package/.output/server/chunks/build/useLogsScope-04cUJCU-.mjs.map +0 -1
- package/.output/server/chunks/build/useMonitorData-guVjMDtR.mjs.map +0 -1
- package/.output/server/chunks/build/useMonitorFormat-C7lhZe4g.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkbenchAuth-DqjBX-6w.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkbenchWorkspaces-GQVU9BLv.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkspaceChannels-B13vROC1.mjs.map +0 -1
- package/.output/server/chunks/build/workshop-BDqWzJtr.mjs.map +0 -1
- package/scripts/_aw0746-stage5.mjs +0 -159
- package/scripts/_aw0746-stage6-aml.mjs +0 -177
- package/scripts/_aw0746-train-strong.py +0 -142
- package/scripts/_aw0747-readme-rows.mjs +0 -32
- package/scripts/_aw0748-fresh-channel.mjs +0 -21
- package/scripts/_aw0748-mock-dispatch-diag.mjs +0 -66
- package/scripts/_aw0748-wake-channel.mjs +0 -46
- package/scripts/_aw0749-readme-rows.mjs +0 -23
- package/scripts/_dbg-comm-verify.mjs +0 -188
- package/scripts/_dbg-im-e2e.mjs +0 -169
- package/scripts/_dbg-opt2-run.mjs +0 -114
- package/scripts/_dbg-opt2-setup.mjs +0 -95
- package/scripts/_dbg-param-map-e2e.ts +0 -248
- package/scripts/_dbg-param-map-rest-smoke.mjs +0 -73
- package/scripts/_dbg-param-real-scenario.mjs +0 -153
- package/scripts/_dbg-real-scenario-e2e.mjs +0 -246
- package/scripts/_dbg-recipe-stale-e2e.mjs +0 -135
- package/scripts/_dbg-schedule-ui-verify.mjs +0 -115
- package/scripts/_dbg-team-matrix.mjs +0 -148
- package/scripts/_dbg-ui-fullcrawl.mjs +0 -91
- package/scripts/_dbg-ui-static-audit.mjs +0 -65
- package/scripts/_dbg-write-lock-e2e.mjs +0 -131
- /package/.output/public/_nuxt/{DdNujZN52.js → DdNujZN5.js} +0 -0
package/docs/sdk.en.md
CHANGED
|
@@ -1,964 +1,964 @@
|
|
|
1
|
-
# AgentWorkShop SDK Development and Usage Guide
|
|
2
|
-
|
|
3
|
-
> The SDK is AgentWorkShop's **programming client and extension base**: external projects
|
|
4
|
-
> consume the platform REST surface through it, and plugins receive the host-injected
|
|
5
|
-
> runtime context through it (hooks / config / storage / timers / platform API / event stream).
|
|
6
|
-
> Zero third-party runtime dependencies; works on Node ≥ 23.4 and modern browsers.
|
|
7
|
-
|
|
8
|
-
**SDK version constants**: server-side `SDK_VERSION = '0.3.0'`, browser-side `CLIENT_SDK_VERSION = '0.3.0'`.
|
|
9
|
-
These two constants are the **interface version of the SDK itself** and evolve **independently**
|
|
10
|
-
from the npm package version (the `version` field in `package.json`, currently 0.7.
|
|
11
|
-
them being out of sync is expected. Never use `SDK_VERSION` to infer the package version, or the reverse.
|
|
12
|
-
**Module format**: ESM only (only `import` / `export`; there is no CJS entry).
|
|
13
|
-
**Types**: `sdk/index.d.mts` and `sdk/client.d.mts` ship with the package, so TypeScript projects
|
|
14
|
-
get IntelliSense with zero configuration (coverage is described in §7).
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 1. Getting the SDK
|
|
19
|
-
|
|
20
|
-
### 1.1 Global install (includes the CLI and the platform itself)
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm install -g agentworkshop
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
The SDK lives inside the global package at `$(npm prefix -g)/node_modules/agentworkshop/sdk/`.
|
|
27
|
-
Plugins **need not and should not** import it directly (see the host-injection model in §2);
|
|
28
|
-
it serves two audiences:
|
|
29
|
-
|
|
30
|
-
- **External integration**: embed AgentWorkShop's line / DAQ / write-control / device-twin
|
|
31
|
-
capabilities into your own node service;
|
|
32
|
-
- **Plugin development** (TypeScript): import types only for full IntelliSense — the runtime
|
|
33
|
-
is injected by the host.
|
|
34
|
-
|
|
35
|
-
### 1.2 Project dependency (recommended for integrators)
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm install agentworkshop # as a dependency (full SDK and types)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 1.3 Import paths
|
|
42
|
-
|
|
43
|
-
`package.json` exposes exactly four `exports` entries:
|
|
44
|
-
|
|
45
|
-
| Import | Resolves to | Contents |
|
|
46
|
-
|---|---|---|
|
|
47
|
-
| `agentworkshop` | `sdk/index.mjs` | **Exactly the same facade** as `agentworkshop/sdk` (the root specifier was previously undocumented; it works) |
|
|
48
|
-
| `agentworkshop/sdk` | `sdk/index.mjs` | The whole facade (server + browser + platform REST client + types) |
|
|
49
|
-
| `agentworkshop/sdk/client` | `sdk/client.mjs` | Browser only (`createClientContext`) |
|
|
50
|
-
| `agentworkshop/package.json` | `package.json` | Package metadata |
|
|
51
|
-
|
|
52
|
-
**Deep paths are not importable**: paths such as `agentworkshop/sdk/api.mjs` or
|
|
53
|
-
`agentworkshop/sdk/hooks.mjs` do not appear in `exports`, and Node throws
|
|
54
|
-
`ERR_PACKAGE_PATH_NOT_EXPORTED`. Take every symbol from one of the three entry points above.
|
|
55
|
-
|
|
56
|
-
```js
|
|
57
|
-
import { createPlatformClient, definePlugin, HookBus } from 'agentworkshop/sdk'
|
|
58
|
-
import { createClientContext } from 'agentworkshop/sdk/client' // browser only
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 1.4 Named export list
|
|
62
|
-
|
|
63
|
-
| Entry | Named exports |
|
|
64
|
-
|---|---|
|
|
65
|
-
| `agentworkshop/sdk` (equivalent to `agentworkshop`) | `SDK_VERSION`, `definePlugin`, `createPluginContext`, `createRouteTable`, `validatePluginModule`, `validatePluginSettings`, `validatePluginGroups`, `resolvePluginGroupId`, `pluginKvExists`, `isPathInside`, `HookBus`, `createPlatformClient`, `CLIENT_SDK_VERSION`, `createClientContext`, `LIFECYCLE_EVENTS`, `CLIENT_EVENTS` |
|
|
66
|
-
| `agentworkshop/sdk/client` | `CLIENT_SDK_VERSION`, `createClientContext` |
|
|
67
|
-
|
|
68
|
-
### 1.5 The remaining named exports
|
|
69
|
-
|
|
70
|
-
Plugin authors normally work with the host-injected `ctx` (§4); the symbols below serve host
|
|
71
|
-
assembly, scaffolding and validation tooling.
|
|
72
|
-
|
|
73
|
-
| Symbol | Signature | Purpose |
|
|
74
|
-
|---|---|---|
|
|
75
|
-
| `createPluginContext(opts)` | `opts` is the host assembly object | Called by the host to build `ctx`; plugin authors never call it themselves |
|
|
76
|
-
| `createRouteTable()` | → `{ register, resolve, byPlugin, unregisterPlugin, size }` | Host route table: exact match, mounted at `/api/plugins/<name><path>` |
|
|
77
|
-
| `definePlugin(def)` | `def` → `def` | Type sugar plus shape validation; throws on an invalid definition. The host also accepts a bare object export |
|
|
78
|
-
| `validatePluginModule(mod, source)` | → `{ ok, def?, error? }` | Pre-load entry check (`name` required, `setup` must be a function, `client` must be a string, `settings` must be an array) |
|
|
79
|
-
| `validatePluginSettings(pluginName, defs)` | → `{ descriptors, errors }` | Validate and normalize setting declarations; rules in §4.9 |
|
|
80
|
-
| `validatePluginGroups(pluginName, defs)` | → `{ groups, errors }` | Validate and normalize config-group declarations |
|
|
81
|
-
| `resolvePluginGroupId(pluginName, declaredId)` | → `string` | Fold a declared group name into the `plugin-<name>[-<suffix>]` namespace |
|
|
82
|
-
| `pluginKvExists(dataDir, name)` | → `boolean` | Probe whether `<dataDir>/plugins/<name>/kv.json` exists |
|
|
83
|
-
| `isPathInside(dir, p)` | → `boolean` | Path containment test (uses `relative()`, so a sibling directory with the same prefix such as `…/foo-evil` cannot fool it) |
|
|
84
|
-
| `HookBus` | `class` | The hook bus implementation; the host owns one shared instance and plugins receive a scoped facade (§4.1) |
|
|
85
|
-
| `LIFECYCLE_EVENTS` | frozen array (11 items) | Authoritative server-side event list (§5) |
|
|
86
|
-
| `CLIENT_EVENTS` | frozen array (5 items) | Authoritative browser-side event list (§5) |
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## 2. Core model: two identities, one SDK
|
|
91
|
-
|
|
92
|
-
| Identity | Form | Role of the SDK |
|
|
93
|
-
|---|---|---|
|
|
94
|
-
| **External integrator** | regular dependency | call `createPlatformClient()` to consume the platform REST surface |
|
|
95
|
-
| **Plugin author** | exports `{ name, setup(ctx) }` | `ctx` is the host-injected SDK context — **zero imports**, the SDK runtime is provided by the host |
|
|
96
|
-
|
|
97
|
-
> Why don't plugins import the SDK directly? Globally installed plugin directories
|
|
98
|
-
> (`~/.AgentWorkShop/plugins/`) are outside the node_modules resolution chain, so host
|
|
99
|
-
> injection is the only zero-pitfall shape (the same paradigm as VSCode's `activate(context)`).
|
|
100
|
-
|
|
101
|
-
A plugin entry is an ordinary ESM module:
|
|
102
|
-
|
|
103
|
-
```js
|
|
104
|
-
export default {
|
|
105
|
-
name: 'my-plugin',
|
|
106
|
-
version: '1.0.0',
|
|
107
|
-
description: 'Example plugin',
|
|
108
|
-
auth: 'none', // declarative auth for plugin routes, see §4.4
|
|
109
|
-
client: './client.mjs', // browser entry (optional), see §6
|
|
110
|
-
async setup(ctx) {
|
|
111
|
-
ctx.logger.info('loaded, directory:', ctx.dir)
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## 3. Platform REST client `createPlatformClient`
|
|
119
|
-
|
|
120
|
-
The SDK fronts the platform as a "project service client": it attaches the Bearer token,
|
|
121
|
-
unwraps the unified envelope `{ code, message, data } → data`, and throws according to the
|
|
122
|
-
rules below.
|
|
123
|
-
|
|
124
|
-
### 3.1 Creating a client
|
|
125
|
-
|
|
126
|
-
```js
|
|
127
|
-
import { createPlatformClient } from 'agentworkshop/sdk'
|
|
128
|
-
|
|
129
|
-
const api = createPlatformClient({
|
|
130
|
-
baseUrl: 'http://127.0.0.1:3001', // defaults to '' (same-origin relative); integrators pass the platform address
|
|
131
|
-
token: '<bearer-token>', // optional; api.setToken() swaps it later
|
|
132
|
-
timeoutMs: 10_000, // optional; per-request timeout (AbortSignal), default 10 000
|
|
133
|
-
logger, // optional; warns when a request fails
|
|
134
|
-
})
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
- `baseUrl` defaults to `''`, i.e. same-origin relative paths; it **may also be a function**
|
|
138
|
-
evaluated lazily on every request (the host's listening port is only known once the server
|
|
139
|
-
actually listens, so the host passes `() => origin`).
|
|
140
|
-
- A trailing `/` is stripped: `'http://host:3001/'` and `'http://host:3001'` are equivalent.
|
|
141
|
-
|
|
142
|
-
### 3.2 Envelope and error semantics (three paths — do not mix them up)
|
|
143
|
-
|
|
144
|
-
| Case | Behaviour |
|
|
145
|
-
|---|---|
|
|
146
|
-
| HTTP non-2xx | throws an `Error` carrying **only `err.status` and `err.body`**; this path **does not set `err.code`** |
|
|
147
|
-
| HTTP 200 but envelope `code !== 0` | throws an `Error` carrying `err.status`, `err.code` **and** `err.body` |
|
|
148
|
-
| Success | returns the unwrapped `data`; a body with no `code`/`data` envelope is returned **as-is** (for example `GET /api/workshop/plugins`, `GET /api/plugins/manifest`) |
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
try {
|
|
152
|
-
await api.daqNodes.get('no-such-node')
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
err.status // 404
|
|
156
|
-
err.body // { code: 'NOT_FOUND', message: '…', data: null }
|
|
157
|
-
err.code // undefined —— this path does not set code
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
> On the platform side `defineApiHandler` sets a non-2xx status for business errors, so in
|
|
162
|
-
> practice you almost always hit the first path. The second path is a defensive check inside
|
|
163
|
-
> the SDK (`sdk/api.mjs` inspects `code` before unwrapping) aimed at endpoints that do not go
|
|
164
|
-
> through the unified wrapper yet still return an error envelope under HTTP 200 — without that
|
|
165
|
-
> check a plugin would unwrap the error envelope to `null` and treat it as success.
|
|
166
|
-
|
|
167
|
-
### 3.3 Generic calls (any platform path)
|
|
168
|
-
|
|
169
|
-
| Method | Signature | Notes |
|
|
170
|
-
|---|---|---|
|
|
171
|
-
| `api.call(method, path, body?, opt?)` | low level | `opt` may carry `{ timeoutMs, headers }`; returns the unwrapped `data` |
|
|
172
|
-
| `api.get(path, query?)` | query object serialized automatically | `api.get('/api/workshop/dcw', { page: 1 })` |
|
|
173
|
-
| `api.post(path, body?)` | JSON-serialized | |
|
|
174
|
-
| `api.patch(path, body?)` | | |
|
|
175
|
-
| `api.delete(path)` | | |
|
|
176
|
-
| `api.setToken(token)` | chainable, returns `api` | `api.setToken(res.token)` after login; pass `null` to clear |
|
|
177
|
-
| `api.ping()` | `GET /api/plugins/manifest` | liveness probe (unauthenticated) |
|
|
178
|
-
|
|
179
|
-
`toQuery` **drops `undefined`, `null` and empty-string** values, so
|
|
180
|
-
`api.get('/x', { lineId: undefined })` never produces `?lineId=undefined`.
|
|
181
|
-
|
|
182
|
-
### 3.4 Resource surfaces and their real base paths
|
|
183
|
-
|
|
184
|
-
Every resource is built by the internal `resource(root)` helper, so **all of them expose five
|
|
185
|
-
methods**: `list(query?)`, `get(id)`, `create(body)`, `update(id, patch)`, `remove(id)`.
|
|
186
|
-
"A method exists" does not mean "the server route exists" — real availability is in §3.5.
|
|
187
|
-
|
|
188
|
-
| Namespace | Base path | Extra methods |
|
|
189
|
-
|---|---|---|
|
|
190
|
-
| `api.users` | `/api/users` | `login(email, password)` → `{ user, token }`; `me()` |
|
|
191
|
-
| `api.lines` | `/api/workshop/dcw/lines` | `start(id, recipeId = '')`; `stop(id)` |
|
|
192
|
-
| `api.products` | `/api/workshop/dcw/products` | — |
|
|
193
|
-
| `api.recipes` | `/api/workshop/dcw/recipes` | — |
|
|
194
|
-
| `api.dcwNodes` | `/api/workshop/dcw` | — |
|
|
195
|
-
| `api.daqNodes` | `/api/workshop/daq` | `alarms()` → `GET /api/workshop/daq/alarms` |
|
|
196
|
-
| `api.templates` | — | `daq()` / `dcw()`: read `.templates` off the two list responses |
|
|
197
|
-
| `api.twins` | `/api/workshop/device-twins` | — |
|
|
198
|
-
| `api.teams` | `/api/workshop/teams` | — |
|
|
199
|
-
| `api.agents` | `/api/workshop/agents` | — |
|
|
200
|
-
| `api.channels` | `/api/workshop/channels` | — |
|
|
201
|
-
| `api.permissions` | — | `overview()` → `GET /api/workshop/permissions`; `set({ userId, grants })` → `PUT /api/workshop/permissions` (admin) |
|
|
202
|
-
| `api.plugins` | — | `manifest()` |
|
|
203
|
-
|
|
204
|
-
The payload shape for `api.permissions.set`:
|
|
205
|
-
|
|
206
|
-
```json
|
|
207
|
-
{ "userId": "<user id>", "grants": [{ "lineId": "<line id>", "mode": "readonly" }] }
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
`mode` is `'readonly'`, `'operate'` or `null` (passing `null` revokes that grant).
|
|
211
|
-
|
|
212
|
-
### 3.5 Real route support
|
|
213
|
-
|
|
214
|
-
`resource(root)` always generates five methods, but only some server route files exist.
|
|
215
|
-
**The table below is the result of checking every route file**: "no" means the call targets a
|
|
216
|
-
path that does not exist and therefore 404s.
|
|
217
|
-
|
|
218
|
-
| Namespace | `list` | `get(id)` | `create` | `update(id)` | `remove(id)` | Notes |
|
|
219
|
-
|---|---|---|---|---|---|---|
|
|
220
|
-
| `users` | yes | yes | yes | **no** | yes | The server only has `PUT /api/users/:id`, while `update()` sends `PATCH`; to update a user call `api.call('PUT', '/api/users/' + id, patch)` directly. `list`/`get`/`create` all require admin |
|
|
221
|
-
| `lines` | yes | no | yes | yes | yes | Plus `start` / `stop`. `create` requires the `admin` or `editor` role |
|
|
222
|
-
| `products` | **no** | no | yes | yes | yes | There is no `GET /api/workshop/dcw/products`; read the product list from `.products` of `GET /api/workshop/dcw` (see §3.6) |
|
|
223
|
-
| `recipes` | yes | no | yes | yes | yes | `list()` returns `{ recipes, runs }`; there is no route for `recipes.get(id)` |
|
|
224
|
-
| `dcwNodes` | yes | no | yes | yes | yes | No `[id].get.ts`; read the node list from `.nodes` of `GET /api/workshop/dcw` |
|
|
225
|
-
| `daqNodes` | yes | no | yes | yes | yes | No `[id].get.ts`; `alarms()` works |
|
|
226
|
-
| `twins` | yes | no | yes | yes | yes | No `[id].get.ts` |
|
|
227
|
-
| `teams` | yes | yes | yes | yes | yes | Full CRUD |
|
|
228
|
-
| `agents` | yes | yes | yes | yes | yes | Full CRUD |
|
|
229
|
-
| `channels` | yes | yes | yes | yes | yes | Full CRUD |
|
|
230
|
-
| `permissions` | `overview()` only | — | — | — | — | No five-method `resource()`; only `overview()` and `set()` |
|
|
231
|
-
| `plugins` | `manifest()` only | — | — | — | — | Unauthenticated |
|
|
232
|
-
|
|
233
|
-
Authentication and timeouts:
|
|
234
|
-
|
|
235
|
-
- Business read endpoints such as `api.lines.list()`, `api.daqNodes.list()` and
|
|
236
|
-
`api.dcwNodes.list()` go through platform auth and need a user token (`api.setToken(...)`,
|
|
237
|
-
or the cookie in a browser);
|
|
238
|
-
- `api.plugins.manifest()` and `api.ping()` are unauthenticated — the only two endpoints you
|
|
239
|
-
can call without a token.
|
|
240
|
-
|
|
241
|
-
### 3.6 Response shapes at a glance
|
|
242
|
-
|
|
243
|
-
**A list does not necessarily return an array** — this is the easiest trap in the whole SDK.
|
|
244
|
-
Every row below was checked against the server handler.
|
|
245
|
-
|
|
246
|
-
| Call | Real response |
|
|
247
|
-
|---|---|
|
|
248
|
-
| `api.lines.list()` | `{ lines, states }` (**not an array**) |
|
|
249
|
-
| `api.daqNodes.list()` | `{ controller, nodes, meta, driverAvailable, infra, templates }` |
|
|
250
|
-
| `api.dcwNodes.list()` | a multi-key object (`controller` / `nodes` / `templates` / `recipes` / `runs` / `history` / `products` / `lines` …), **not a node array** |
|
|
251
|
-
| `api.recipes.list()` | `{ recipes, runs }` |
|
|
252
|
-
| `api.twins.list()` | `{ twins }` |
|
|
253
|
-
| `api.daqNodes.alarms()` | `{ alarms }` |
|
|
254
|
-
| `api.permissions.overview()` | `{ lines, users }` |
|
|
255
|
-
| `api.templates.daq()` / `api.templates.dcw()` | an array (`.templates ?? []`) |
|
|
256
|
-
| `api.teams.list()` / `api.agents.list()` / `api.channels.list()` | an array |
|
|
257
|
-
| `api.users.list()` | `{ items, total, page, pageSize }` |
|
|
258
|
-
| `api.plugins.manifest()` | `{ plugins }` (no envelope, returned as-is) |
|
|
259
|
-
| `api.lines.create(body)` | `{ line }` |
|
|
260
|
-
| `api.recipes.create(body)` | `{ recipe }` |
|
|
261
|
-
| `api.products.create(body)` | `{ product }` |
|
|
262
|
-
| `api.dcwNodes.create(body)` / `api.daqNodes.create(body)` | `{ node }` |
|
|
263
|
-
| `api.twins.create(body)` | `{ twin }` |
|
|
264
|
-
| `api.lines.start(id, recipeId)` | `{ run, line }` |
|
|
265
|
-
| `api.users.login(email, password)` | `{ user, token }` |
|
|
266
|
-
|
|
267
|
-
About `api.daqNodes.list({ lineId })`: the `{ lineId }` query argument **is not read by that
|
|
268
|
-
handler**. Line filtering happens server-side from the caller's permissions (a regular user
|
|
269
|
-
only sees nodes of granted lines). Do not present it as a working client-side filter.
|
|
270
|
-
|
|
271
|
-
About `api.lines.start(id, recipeId)`: `recipeId` defaults to an empty string, but the server
|
|
272
|
-
**requires a recipe that actually exists** (an empty string or an unknown id yields
|
|
273
|
-
404 `Recipe 不存在`). When a line has recipes, `recipeId` is effectively mandatory.
|
|
274
|
-
|
|
275
|
-
### 3.7 Full example: external integration
|
|
276
|
-
|
|
277
|
-
```js
|
|
278
|
-
import { createPlatformClient } from 'agentworkshop/sdk'
|
|
279
|
-
|
|
280
|
-
const api = createPlatformClient({ baseUrl: 'http://plant.local:3001' })
|
|
281
|
-
|
|
282
|
-
const { token } = await api.users.login('you@example.com', 'secret')
|
|
283
|
-
api.setToken(token)
|
|
284
|
-
|
|
285
|
-
// 1) Line list: { lines, states } —— not an array
|
|
286
|
-
const { lines, states } = await api.lines.list()
|
|
287
|
-
console.log(`${lines.length} lines`)
|
|
288
|
-
for (const l of lines) {
|
|
289
|
-
console.log(` ${l.name} → ${states.find(s => s.lineId === l.id)?.state ?? 'unknown'}`)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// 2) DAQ surface: { controller, nodes, meta, driverAvailable, infra, templates }
|
|
293
|
-
const { nodes } = await api.daqNodes.list()
|
|
294
|
-
console.log(`${nodes.length} DAQ nodes, ${nodes.filter(n => n.state === 'offline').length} offline`)
|
|
295
|
-
|
|
296
|
-
// 3) Write-control surface: the node list is an object too; products come from .products
|
|
297
|
-
const dcw = await api.dcwNodes.list()
|
|
298
|
-
console.log(`${dcw.nodes.length} DCW nodes, ${dcw.products.length} products`)
|
|
299
|
-
|
|
300
|
-
// 4) Recipe surface: { recipes, runs }
|
|
301
|
-
const { recipes } = await api.recipes.list()
|
|
302
|
-
|
|
303
|
-
// 5) Starting a line: recipeId must be a real recipe of that line (an empty string is rejected)
|
|
304
|
-
const line = lines[0]
|
|
305
|
-
const recipe = recipes.find(r => r.lineId === line?.id)
|
|
306
|
-
if (line && recipe) {
|
|
307
|
-
await api.lines.start(line.id, recipe.id)
|
|
308
|
-
await api.lines.stop(line.id)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// 6) Line grants (admin): overview() reads everything, set() writes in bulk
|
|
312
|
-
const { users } = await api.permissions.overview()
|
|
313
|
-
const target = users[0]
|
|
314
|
-
if (target && line) {
|
|
315
|
-
await api.permissions.set({ userId: target.id, grants: [{ lineId: line.id, mode: 'readonly' }] })
|
|
316
|
-
}
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
---
|
|
320
|
-
|
|
321
|
-
## 4. Plugin context `ctx` (the complete member surface)
|
|
322
|
-
|
|
323
|
-
The `ctx` handed to `setup(ctx)` is the host-assembled SDK runtime. **The table below is the
|
|
324
|
-
complete surface**; the last three rows (`ctx.daq` / `ctx.omp` / `ctx.services`) are attached
|
|
325
|
-
directly by the plugin host before `setup` runs and are not part of `sdk/context.mjs`.
|
|
326
|
-
|
|
327
|
-
| Group | Member | Type | Notes |
|
|
328
|
-
|---|---|---|---|
|
|
329
|
-
| Identity | `ctx.name` | `string` | plugin name (= directory name / declared name) |
|
|
330
|
-
| | `ctx.scope` | `'builtin' \| 'project' \| 'user'` | load scope; on a name clash the priority is builtin > project > user |
|
|
331
|
-
| | `ctx.dir` | `string` | absolute path of the plugin directory |
|
|
332
|
-
| | `ctx.sdkVersion` | `string` | SDK interface version (= `SDK_VERSION`) |
|
|
333
|
-
| Hooks | `ctx.hooks` | `{ on, once, off, emit }` | per-plugin scoped hook facade (§4.1); **not a `HookBus` instance and has no `.size`** |
|
|
334
|
-
| Logging | `ctx.logger` | `{ debug, info, warn, error }` | output is prefixed `[aw-plugins] [<plugin name>]` |
|
|
335
|
-
| Config | `ctx.config.get(key)` | any | effective value (after the four-layer merge) |
|
|
336
|
-
| | `ctx.config.all()` | `Record<string, any>` | shallow copy of every effective setting |
|
|
337
|
-
| | `ctx.config.onChange(fn)` | unsubscribe function | subscribes to `config:changed` (§4.5) |
|
|
338
|
-
| | `ctx.config.defineGroup(def)` | group object \| `null` | declare a plugin-owned config group (§4.9) |
|
|
339
|
-
| | `ctx.config.defineField(decl)` | descriptor \| `null` | declare a setting field (key auto-addressed as `plugins.<name>.<key>`) |
|
|
340
|
-
| | `ctx.config.removeGroup(id)` | `boolean` | remove a group declaration |
|
|
341
|
-
| | `ctx.config.removeField(key)` | `boolean` | remove a field declaration |
|
|
342
|
-
| | `ctx.config.groups()` / `fields()` | arrays | the groups / fields this plugin currently has registered (read-only snapshot) |
|
|
343
|
-
| Paths | `ctx.paths` | `{ home, configRoot, dataDir }` | config-root information (home mode = `~/.AgentWorkShop`) |
|
|
344
|
-
| | `ctx.dataDir` | `string` | this plugin's private data directory = `<paths.dataDir>/plugins/<name>` |
|
|
345
|
-
| Storage | `ctx.kv` | `{ get, set, all, bump }` | plugin-private KV (§4.2); **there is no `reset()`** |
|
|
346
|
-
| Timers | `ctx.timer.setInterval(fn, ms)` / `setTimeout(fn, ms)` | timer id | auto `unref` + auto-collected on shutdown / hot reload (§4.3) |
|
|
347
|
-
| Cleanup | `ctx.onDispose(fn)` | the `fn` you passed | register a cleanup callback (§4.3) |
|
|
348
|
-
| | `ctx.subscriptions.add(d)` | the `d` you passed | register a `{ dispose() }` object or a function; same collection queue as `onDispose` |
|
|
349
|
-
| Routes | `ctx.route(method, path, handler)` | `boolean` | mounts at `/api/plugins/<name><path>`; auth is declared by the plugin's `auth` field (§4.4) |
|
|
350
|
-
| Platform | `ctx.api` | `PlatformClient` | loopback REST client (**no token by default**; §4.6) |
|
|
351
|
-
| Network | `ctx.http.get(url, opts)` / `post(url, body, opts)` | `Promise<Response>` | outbound requests; the guard is protocol-only; 8 s default timeout (§4.6) |
|
|
352
|
-
| Events | `ctx.events.on(type, fn)` / `off(type, fn)` | unsubscribe function | live scene event subscription; the `event:` prefix is added for you (§4.6) |
|
|
353
|
-
| Line permissions (host-injected) | `ctx.permissions` | see §4.7 | query and manage the per-user, per-line three-state grants |
|
|
354
|
-
| DAQ extension (host-injected) | `ctx.daq` | see §4.8 | driver / processor / template registration + frame subscription + time-series queries |
|
|
355
|
-
| Agent tools (host-injected) | `ctx.omp.registerTool(tool)` | see §4.8 | hot-inject a custom host tool at runtime |
|
|
356
|
-
| Runtime services (host-injected) | `ctx.services` | see §4.8 | lazy service access + cross-plugin service provision |
|
|
357
|
-
|
|
358
|
-
`ctx` has **no** `ctx.routes`, `ctx.dcw`, `ctx.scene` or `ctx.version`: route registration is
|
|
359
|
-
the singular `ctx.route()`; write-control traffic is observed through the `dcw:write` hook;
|
|
360
|
-
scene events go through `ctx.events`.
|
|
361
|
-
|
|
362
|
-
### 4.1 `ctx.hooks` — the hook facade
|
|
363
|
-
|
|
364
|
-
The host owns one shared `HookBus` named `aw-plugins`; a plugin receives a **scoped facade
|
|
365
|
-
exposing only `on` / `once` / `off` / `emit`**. Listeners registered through it are tracked and
|
|
366
|
-
auto-unbound when the plugin hot-reloads (the one cleanup path that always worked).
|
|
367
|
-
The facade exposes no diagnostic properties such as `count` / `size` / `listeners`.
|
|
368
|
-
|
|
369
|
-
```js
|
|
370
|
-
function onSample(sample) {
|
|
371
|
-
ctx.kv.bump('samples')
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const off = ctx.hooks.on('daq:sample', onSample) // returns an unsubscribe function
|
|
375
|
-
ctx.hooks.once('server:close', () => { /* teardown, fires once */ })
|
|
376
|
-
ctx.hooks.off('daq:sample', onSample) // manual unbind: pass the original handler
|
|
377
|
-
off() // or just call the function returned by on()
|
|
378
|
-
|
|
379
|
-
await ctx.hooks.emit('my-plugin:custom', { hello: 1 }) // inter-plugin messaging: other plugins can listen
|
|
380
|
-
ctx.hooks.on('*', ({ type, payload }) => { /* every event */ })
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
Semantics (matching `sdk/hooks.mjs`):
|
|
384
|
-
|
|
385
|
-
- **Async-serial**: listeners of one type run in registration order and are awaited; the next
|
|
386
|
-
one does not start until the previous returns;
|
|
387
|
-
- **Error isolation**: one throwing listener is only counted and warned about; siblings and the
|
|
388
|
-
main service are unaffected;
|
|
389
|
-
- **Circuit breaker**: a listener failing **8 times in a row** is removed automatically;
|
|
390
|
-
**any single success resets the counter**, so occasional failures never accumulate into an eviction;
|
|
391
|
-
- **Wildcard**: the only server-side wildcard spelling is the bare `'*'`; its callback receives
|
|
392
|
-
`{ type, payload }` and runs after the named listeners;
|
|
393
|
-
- **The return value is fan-out, not a waterfall**: every listener receives **the same unmodified
|
|
394
|
-
payload**; `emit()` merely returns "the last non-`undefined` return value" — values are never
|
|
395
|
-
threaded from one listener to the next;
|
|
396
|
-
- **v1 is observation-only**: there is no veto / interception / rewriting.
|
|
397
|
-
|
|
398
|
-
> `ctx.hooks.on('event:*')` never fires. `event:*` is the subscription entry name the list uses
|
|
399
|
-
> for scene events; the real wildcard is the bare `'*'`, and the ergonomic scene-event form is
|
|
400
|
-
> `ctx.events.on('<type>', fn)` (§4.6).
|
|
401
|
-
|
|
402
|
-
### 4.2 `ctx.kv` — plugin-private persistence
|
|
403
|
-
|
|
404
|
-
```js
|
|
405
|
-
ctx.kv.set('threshold', 100)
|
|
406
|
-
ctx.kv.bump('samples') // atomic increment, +1 by default; bump(key, by) sets the step
|
|
407
|
-
ctx.kv.bump('samples', 5)
|
|
408
|
-
ctx.kv.get('threshold') // 100
|
|
409
|
-
ctx.kv.all() // { samples: 19453, threshold: 100, ... }
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
- **These four methods only**: `get` / `set` / `all` / `bump`. **No `reset()`, no `delete()`,
|
|
413
|
-
no `keys()`**; to clear a key, `set` it explicitly or switch to a new key.
|
|
414
|
-
- On-disk location: `<ctx.dataDir>/kv.json`, i.e. `<paths.dataDir>/plugins/<name>/kv.json`.
|
|
415
|
-
- **In-memory state is authoritative + a 200 ms debounced atomic write** (temp file plus
|
|
416
|
-
`rename`), so a high-frequency hook (`daq:sample`) and a low-frequency hook (`line:stop`)
|
|
417
|
-
calling concurrently cannot race on read-modify-write.
|
|
418
|
-
- On shutdown / hot reload the pending debounce is **cancelled and flushed synchronously**, so a
|
|
419
|
-
`set` from the last 200 ms before exit is not lost.
|
|
420
|
-
- Typical uses: counters, alarm state, threshold config, heartbeat timestamps.
|
|
421
|
-
|
|
422
|
-
### 4.3 `ctx.timer` / `ctx.onDispose` / `ctx.subscriptions`
|
|
423
|
-
|
|
424
|
-
```js
|
|
425
|
-
ctx.timer.setInterval(() => ctx.kv.set('heartbeat', Date.now()), 5000)
|
|
426
|
-
ctx.timer.setTimeout(() => ctx.logger.info('one-shot task'), 1000)
|
|
427
|
-
|
|
428
|
-
ctx.onDispose(() => ctx.logger.info('plugin cleanup done'))
|
|
429
|
-
|
|
430
|
-
// subscriptions.add accepts a { dispose() } object or a function; same queue as onDispose
|
|
431
|
-
const controller = new AbortController()
|
|
432
|
-
ctx.subscriptions.add({ dispose() { controller.abort() } })
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
- Timers created by `ctx.timer.setInterval/setTimeout` are automatically `unref`ed (they never
|
|
436
|
-
hold the process open) and automatically registered with the collection queue, so **you never
|
|
437
|
-
have to clear them by hand**.
|
|
438
|
-
- `ctx.onDispose(fn)` and `ctx.subscriptions.add(d)` (`d` may be `{ dispose() }` or a function)
|
|
439
|
-
share **one host-owned collection queue** with the timers.
|
|
440
|
-
- That queue runs on **both server shutdown and plugin hot reload** — a guarantee this version of
|
|
441
|
-
the SDK can make after the fix (`createPluginContext` previously failed to forward the host's
|
|
442
|
-
`onDispose` injection point, leaking timers and losing the final kv write).
|
|
443
|
-
|
|
444
|
-
Server shutdown sequence:
|
|
445
|
-
|
|
446
|
-
```text
|
|
447
|
-
server shutdown (nitro close)
|
|
448
|
-
└─ per-plugin dispose queue (each entry try/catch): clear timers, flush kv synchronously, unbind subscriptions…
|
|
449
|
-
└─ broadcast server:close { at }
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
### 4.4 `ctx.route` — plugin API
|
|
453
|
-
|
|
454
|
-
```js
|
|
455
|
-
export default {
|
|
456
|
-
name: 'my-plugin',
|
|
457
|
-
auth: 'user', // declarative auth: 'none' (default) | 'user' | 'admin' | 'agent-or-user'
|
|
458
|
-
async setup(ctx) {
|
|
459
|
-
// returns boolean: true = registration succeeded, false = handler is not a function
|
|
460
|
-
const ok = ctx.route('GET', '/stats', () => ctx.kv.all())
|
|
461
|
-
if (!ok) ctx.logger.warn('route registration failed')
|
|
462
|
-
|
|
463
|
-
ctx.route('POST', '/threshold', (event) => {
|
|
464
|
-
const body = event.awBody // the JSON body the host already pre-read (may be undefined)
|
|
465
|
-
const threshold = Number(body?.threshold)
|
|
466
|
-
if (!Number.isFinite(threshold)) return { ok: false, error: 'threshold must be a number' }
|
|
467
|
-
ctx.kv.set('threshold', threshold)
|
|
468
|
-
return { ok: true, threshold } // the return value is serialized to JSON by nitro
|
|
469
|
-
})
|
|
470
|
-
},
|
|
471
|
-
}
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
→ mounted at `GET /api/plugins/<plugin name>/stats` and
|
|
475
|
-
`POST /api/plugins/<plugin name>/threshold`.
|
|
476
|
-
|
|
477
|
-
- **The return value is `boolean`**: `false` when `handler` is not a function.
|
|
478
|
-
- **Paths** start with `/` (a missing one is added for you); the base is always
|
|
479
|
-
`/api/plugins/<plugin name>`.
|
|
480
|
-
- **Auth is declarative — do not write your own**: give the plugin definition
|
|
481
|
-
`auth: 'none' | 'user' | 'admin' | 'agent-or-user'` and the platform catch-all
|
|
482
|
-
(`server/api/plugins/[name]/[...path].ts`) validates it **before** your handler runs,
|
|
483
|
-
returning 401 on failure.
|
|
484
|
-
- **The handler cannot obtain a user object**: `resolveUser(event)` is not on `ctx` and cannot be
|
|
485
|
-
imported from a plugin module. When you need an identity, combine the `auth` gate with
|
|
486
|
-
`ctx.api.setToken(...)` and go through the platform API.
|
|
487
|
-
- **The JSON body is already pre-read** and attached as `event.awBody` (not h3's `readBody`).
|
|
488
|
-
- Handler errors are isolated: the platform logs with the plugin name and returns a 500 envelope
|
|
489
|
-
(`插件路由处理失败(<plugin name>): <original message>`) without leaking a stack trace.
|
|
490
|
-
|
|
491
|
-
### 4.5 `ctx.config` — reading config and reacting to change
|
|
492
|
-
|
|
493
|
-
```js
|
|
494
|
-
ctx.config.get('plugins.my-plugin.threshold') // effective value (after the four-layer merge)
|
|
495
|
-
ctx.config.all() // every effective setting (shallow copy)
|
|
496
|
-
|
|
497
|
-
const off = ctx.config.onChange((payload) => { // payload: the config:changed payload, see §5
|
|
498
|
-
ctx.logger.info('config changed:', payload?.changed)
|
|
499
|
-
})
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
`config:changed` is bridged onto the plugin bus from the platform settings service, and
|
|
503
|
-
`ctx.config.onChange(fn)` is essentially `ctx.hooks.on('config:changed', fn)`, so it is likewise
|
|
504
|
-
auto-unbound on hot reload.
|
|
505
|
-
|
|
506
|
-
### 4.6 `ctx.api` / `ctx.http` / `ctx.events` — which one to use
|
|
507
|
-
|
|
508
|
-
| Need | Use | Why |
|
|
509
|
-
|---|---|---|
|
|
510
|
-
| Read / write **platform business data** (lines, nodes, twins…) | `ctx.api` | auth / envelope / resource semantics out of the box |
|
|
511
|
-
| Call an **external system** (MES, webhook, mail gateway) | `ctx.http` | generic requests plus a protocol guard |
|
|
512
|
-
| React to the **live stream** (samples, alarms, start/stop) | `ctx.events` / `ctx.hooks.on` | in-process, zero HTTP overhead |
|
|
513
|
-
|
|
514
|
-
```js
|
|
515
|
-
// ctx.api: the loopback PlatformClient. baseUrl is resolved lazily by the host; no token by default.
|
|
516
|
-
const { token } = await ctx.api.users.login('user@example.com', 'secret')
|
|
517
|
-
ctx.api.setToken(token) // later loopback calls carry that token
|
|
518
|
-
const { lines } = await ctx.api.lines.list()
|
|
519
|
-
|
|
520
|
-
// ctx.http: outbound requests, protocol guard only (http/https), 8 s default timeout
|
|
521
|
-
const res = await ctx.http.get('https://mes.example.com/health', { timeoutMs: 3000 })
|
|
522
|
-
const payload = await ctx.http.post('https://mes.example.com/events', { lineId: 'L1' })
|
|
523
|
-
|
|
524
|
-
// ctx.events: scene events — pass the scene event name itself; the `event:` prefix is added for you
|
|
525
|
-
ctx.events.on('daq.reading', r => ctx.logger.info('sample', r.nodeId))
|
|
526
|
-
ctx.events.on('permissions.changed', ({ userId }) => ctx.logger.info('grants changed', userId))
|
|
527
|
-
ctx.events.on('device.created', d => ctx.logger.info('new device', d.id))
|
|
528
|
-
const off = ctx.events.on('daq.alarm', a => ctx.logger.warn('alarm', a.id))
|
|
529
|
-
off()
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
- `ctx.api` has **no token by default**: unauthenticated endpoints (`plugins.manifest` / `ping`)
|
|
533
|
-
work immediately; anything else needs a login followed by `setToken`. If you only need
|
|
534
|
-
in-process data, prefer `ctx.events` and `ctx.hooks` (no auth, no overhead).
|
|
535
|
-
- The `ctx.http` guard **checks the protocol only** and does not restrict hosts — the target
|
|
536
|
-
address is the plugin's own responsibility.
|
|
537
|
-
- `ctx.events.on(type, fn)` / `off(type, fn)` install `event:<type>` underneath; to receive every
|
|
538
|
-
scene event use `ctx.hooks.on('*', ({ type, payload }) => …)`.
|
|
539
|
-
|
|
540
|
-
### 4.7 `ctx.permissions` — per-user, per-line grants
|
|
541
|
-
|
|
542
|
-
| Method | Returns | Notes |
|
|
543
|
-
|---|---|---|
|
|
544
|
-
| `lineMode(user, lineId)` | `'none' \| 'readonly' \| 'operate'` | `user` is `{ id, role }`; admin/editor is always `operate` |
|
|
545
|
-
| `visibleLineIds(user)` | `Set<string> \| null` | `null` means unrestricted (admin/editor) |
|
|
546
|
-
| `listGrants(userId)` | `Array<{ lineId, mode, grantedBy, grantedAt }>` | read every grant of one user |
|
|
547
|
-
| `setGrants(userId, grants, grantedBy?)` | the grants after the write | `grants` looks like `[{ lineId, mode }]` with `mode` = `'readonly'` / `'operate'` / `null` |
|
|
548
|
-
|
|
549
|
-
```js
|
|
550
|
-
const userId = ctx.kv.get('watchUserId') // a plugin gets userIds from event payloads or its own config
|
|
551
|
-
if (userId) {
|
|
552
|
-
const mode = ctx.permissions.lineMode({ id: userId, role: 'user' }, 'line-1')
|
|
553
|
-
const visible = ctx.permissions.visibleLineIds({ id: userId, role: 'user' })
|
|
554
|
-
const grants = ctx.permissions.listGrants(userId)
|
|
555
|
-
ctx.logger.info(`mode=${mode} visible=${visible ? visible.size : 'all'} grants=${grants.length}`)
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Change notification is the scene event permissions.changed, subscribed via ctx.events (prefix added for you)
|
|
559
|
-
ctx.events.on('permissions.changed', ({ userId }) => ctx.logger.info('grants changed:', userId))
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
### 4.8 Host-injected extensions `ctx.daq` / `ctx.omp` / `ctx.services`
|
|
563
|
-
|
|
564
|
-
**`ctx.daq`** — multi-modal DAQ extension (v0.6 frame pipeline):
|
|
565
|
-
|
|
566
|
-
| Method | Notes |
|
|
567
|
-
|---|---|
|
|
568
|
-
| `registerDriver({ kind, available, sample, test })` | register a custom driver |
|
|
569
|
-
| `registerProcessor(kind, name, fn)` | register a sink processor (after sampling, before storage) |
|
|
570
|
-
| `registerTemplate(def)` | register a DAQ node template (`key` / `signalKind` / `vector` / `sink` / `metrics`) |
|
|
571
|
-
| `onFrame(fn)` | frame subscription sugar (= `ctx.hooks.on('daq:frame', fn)`) |
|
|
572
|
-
| `onSample(fn)` | sample subscription sugar (= `ctx.hooks.on('daq:sample', fn)`) |
|
|
573
|
-
| `query({ nodeIds?, lineId?, from?, to?, bucketMs? })` | unauthenticated time-series query (straight to `queryTagged`) |
|
|
574
|
-
| `nodes()` | DAQ node metadata snapshot (including line ownership) |
|
|
575
|
-
|
|
576
|
-
```js
|
|
577
|
-
ctx.daq.registerProcessor('vector', 'my-derive', (frame) => {
|
|
578
|
-
// frame = { kind: 'vector'|'image', points? | blob? (image producer side only), metrics }
|
|
579
|
-
return { ...frame, metrics: { ...frame.metrics, myMetric: 1 } }
|
|
580
|
-
})
|
|
581
|
-
ctx.daq.onFrame(f => ctx.logger.debug('frame', f.nodeId, f.kind))
|
|
582
|
-
const rows = await ctx.daq.query({ nodeIds: ['n1'], from: Date.now() - 3600_000, to: Date.now(), bucketMs: 60_000 })
|
|
583
|
-
const all = await ctx.daq.nodes()
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
A template's `sink.processors` declares the sink pipeline; `metrics` declares derived-metric
|
|
587
|
-
thresholds whose breaches ride the platform's existing alarm chain. Vector / frame metadata lands
|
|
588
|
-
in Timescale `daq_frames`; image pixels land in object storage (the `daq:frame` payload
|
|
589
|
-
**carries no pixel blob**).
|
|
590
|
-
|
|
591
|
-
**`ctx.omp.registerTool({ name, label?, description, parameters, roles?, handler })`** —
|
|
592
|
-
register a custom host tool, hot-injected into every running agent session at runtime:
|
|
593
|
-
|
|
594
|
-
```js
|
|
595
|
-
ctx.omp.registerTool({
|
|
596
|
-
name: 'sensor_log',
|
|
597
|
-
label: 'Sensor calibration',
|
|
598
|
-
description: 'Query or record sensor calibration conclusions',
|
|
599
|
-
parameters: { type: 'object', properties: { sensor: { type: 'string' } }, required: ['sensor'] },
|
|
600
|
-
roles: ['lead', 'worker'], // the only valid literals are 'lead' and 'worker'; default is both
|
|
601
|
-
handler: async (args, agent) => ({ text: `recorded ${args.sensor}` }), // agent = { agentId, channelId, role, name }
|
|
602
|
-
})
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
Registry changes are hot-injected into running sessions immediately (re-sending `set_host_tools`,
|
|
606
|
-
no respawn); a tool sharing a name with a built-in host tool is ignored.
|
|
607
|
-
|
|
608
|
-
**`ctx.services`** — the backend runtime object surface (lazy getters, cached after first access):
|
|
609
|
-
|
|
610
|
-
| Call | Resolves to |
|
|
611
|
-
|---|---|
|
|
612
|
-
| `ctx.services.names()` | every service name (including plugin-provided `<plugin>.<name>`) |
|
|
613
|
-
| `await ctx.services.get('daq')` | `{ query(q), nodes() }` |
|
|
614
|
-
| `await ctx.services.get('lines')` | `{ list(), byId(id) }` |
|
|
615
|
-
| `await ctx.services.get('channels')` | `{ list(), agents(channelId) }` |
|
|
616
|
-
| `await ctx.services.get('plugins')` | the plugin manifest **array** (note: not an object and with no `pluginManifest()`) |
|
|
617
|
-
| `ctx.services.provide(name, getter)` | provide a service, auto-prefixed with `<plugin>.` |
|
|
618
|
-
|
|
619
|
-
```js
|
|
620
|
-
const daq = await ctx.services.get('daq')
|
|
621
|
-
const lines = await ctx.services.get('lines')
|
|
622
|
-
const channels = await ctx.services.get('channels')
|
|
623
|
-
const plugins = await ctx.services.get('plugins') // an array
|
|
624
|
-
ctx.services.provide('my-data', async () => ({ ready: true })) // → 'my-plugin.my-data'
|
|
625
|
-
ctx.logger.info(ctx.services.names().join(', '))
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
An unknown name throws (the caller is expected to handle it). `provide` forces the
|
|
629
|
-
`<plugin>.` prefix so cross-plugin name clashes cannot happen.
|
|
630
|
-
|
|
631
|
-
### 4.9 Plugin setting declarations (`settings` / `configGroups`)
|
|
632
|
-
|
|
633
|
-
Two equivalent routes: the top-level `settings` array in the entry (declarative), or
|
|
634
|
-
`ctx.config.defineField` inside `setup` (conditional).
|
|
635
|
-
|
|
636
|
-
```js
|
|
637
|
-
export default {
|
|
638
|
-
name: 'my-plugin',
|
|
639
|
-
configGroups: [{ id: 'conn', label: 'Connection', collapsed: true }],
|
|
640
|
-
settings: [
|
|
641
|
-
{ key: 'base_url', type: 'string', default: 'https://example.com', group: 'conn',
|
|
642
|
-
labelKey: 'plugin.my-plugin.base_url', label: 'Service URL' },
|
|
643
|
-
],
|
|
644
|
-
async setup(ctx) {
|
|
645
|
-
// equivalent form: add declarations conditionally at runtime
|
|
646
|
-
ctx.config.defineGroup({ id: 'sync', label: 'Sync' })
|
|
647
|
-
ctx.config.defineField({ key: 'interval', type: 'number', default: 30, min: 1, max: 3600, group: 'sync' })
|
|
648
|
-
},
|
|
649
|
-
}
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
Validation rules (an entry that fails **is skipped with a warning**; it never blocks loading):
|
|
653
|
-
|
|
654
|
-
| Rule | Detail |
|
|
655
|
-
|---|---|
|
|
656
|
-
| `key` | must match `[A-Za-z0-9_-]+`; addressed as `plugins.<plugin name>.<key>` |
|
|
657
|
-
| `type` | one of `'string'` / `'number'` / `'boolean'` / `'select'` |
|
|
658
|
-
| `default` | **required** — a declaration without `default` is skipped outright |
|
|
659
|
-
| `select` | must supply an `options` array, and `default` must appear among its stringified values |
|
|
660
|
-
| `min` / `max` | **apply to `number` only** |
|
|
661
|
-
| Group | an explicit `group` is folded into the `plugin-<name>[-<suffix>]` namespace; a field without `group` lands in the `plugin-<name>` group labelled with the plugin name |
|
|
662
|
-
|
|
663
|
-
Once declared, the settings are merged into the platform settings service: the "Plugins" section
|
|
664
|
-
of the settings page renders them automatically, PATCH validation uses the same source, and
|
|
665
|
-
saving takes effect immediately. Read values with the full key:
|
|
666
|
-
`ctx.config.get('plugins.my-plugin.base_url')`.
|
|
667
|
-
|
|
668
|
-
### 4.10 `ctx.twin` — hybrid-twin Provider Registry bridge
|
|
669
|
-
|
|
670
|
-
`ctx.twin` registers an industrial scene's **physics core / scene pack / objectives / training and solver
|
|
671
|
-
adapters** into the hybrid-twin Provider Registry. The agent's twin tools (`twin_scene_read` /
|
|
672
|
-
`twin_snapshot_create` / `twin_trial_run` / `mpc_optimize`) resolve your provider through
|
|
673
|
-
`SceneContract.physicsProfileId`, falling back to the bundled `twin-injection-default`.
|
|
674
|
-
**Swapping scenes needs no tool or channel change.**
|
|
675
|
-
|
|
676
|
-
| Member | Notes |
|
|
677
|
-
|---|---|
|
|
678
|
-
| `registerPhysicsProvider(provider)` | register a physics core: manifest (`providerId` / `version` / `apiVersion: 'twin-provider.v1'` / `sceneKinds` / `backend` / the four variable tables / `parameterPriors` / `capabilities` / `artifactContract`) plus `initialize` / `step` / `simulate` / `evaluateConstraints`, optional `validateScene` / `calibrate` / `designSafeExperiment` / `estimateUncertainty` / `exportArtifacts` / `health` |
|
|
679
|
-
| `registerScenePack(pack)` | `{ sceneKind, sceneSchemaVersion, compile?, discover?, constraints?, objectives?, datasetSchema? }` — compiles field nodes and recipe into a `SceneContract` |
|
|
680
|
-
| `registerObjectiveProfile(profile)` | MPC objectives and weights |
|
|
681
|
-
| `registerTrainingAdapter(adapter)` / `registerSolverAdapter(adapter)` | training / external-solver adapters (ONNX, ROM, third-party solvers) |
|
|
682
|
-
| `listProviders(filter?)` / `getProviderHealth(id, version?)` | listing and health checks; health feeds the "may be used" decision |
|
|
683
|
-
| `resolveProvider(id, version?)` / `validateProvider(id, version?)` | resolve the active generation / validate without registering (pre-flight self-check) |
|
|
684
|
-
| `retireProvider(id, version?)` | explicit retirement; only unloads after references reach zero |
|
|
685
|
-
| `isRegistryAvailable()` | whether the bridge is ready (while it is not, registration calls are queued, so startup order cannot lose registrations) |
|
|
686
|
-
|
|
687
|
-
**Lifecycle and generations**: `DISCOVERED → VALIDATED → REGISTERED → READY → DRAINING → RETIRED`
|
|
688
|
-
(`FAILED` when validation rejects). A hot reload stages the new **generation** and drains the old one:
|
|
689
|
-
in-flight trials / MPC hold a lease and are never invalidated during a drain, and `unregisterPlugin`
|
|
690
|
-
means "drain + retire", so a disabled plugin loses its provider.
|
|
691
|
-
|
|
692
|
-
```js
|
|
693
|
-
export default {
|
|
694
|
-
name: 'my-twin-provider',
|
|
695
|
-
version: '1.0.0',
|
|
696
|
-
auth: 'none',
|
|
697
|
-
async setup(ctx) {
|
|
698
|
-
if (!ctx.twin.isRegistryAvailable()) return // registrations queue while the bridge is down
|
|
699
|
-
ctx.twin.registerPhysicsProvider(myProvider) // see docs/plugins.md, "Hybrid-twin provider plugins"
|
|
700
|
-
ctx.twin.registerScenePack(myScenePack)
|
|
701
|
-
const ok = await ctx.twin.validateProvider('my-provider', '1.0.0')
|
|
702
|
-
ctx.logger.info(`provider check: ${JSON.stringify(ok)}`)
|
|
703
|
-
},
|
|
704
|
-
}
|
|
705
|
-
```
|
|
706
|
-
|
|
707
|
-
Full field tables, generational hot-swap semantics and a runnable example live in
|
|
708
|
-
`docs/plugins.md`, section "Hybrid-twin provider plugins".
|
|
709
|
-
|
|
710
|
-
---
|
|
711
|
-
|
|
712
|
-
## 5. Lifecycle events
|
|
713
|
-
|
|
714
|
-
The authoritative lists are the SDK-exported `LIFECYCLE_EVENTS` (11 items) and
|
|
715
|
-
`CLIENT_EVENTS` (5 items), both checked one by one against what the host actually emits.
|
|
716
|
-
**Every event is also part of the config-root event stream.**
|
|
717
|
-
|
|
718
|
-
### 5.1 Server-side events (`LIFECYCLE_EVENTS`, 11 items)
|
|
719
|
-
|
|
720
|
-
| Event name (bus type) | When it fires | Payload | Typical use |
|
|
721
|
-
|---|---|---|---|
|
|
722
|
-
| `plugin:host:init` | once, after the host has loaded every plugin (including disabled ones) | `{ plugins: string[], failures: number }` | readiness proof, deferred init |
|
|
723
|
-
| `plugins:reloaded` | end of a hot reload (plugin enabled/disabled, `plugins-state.json` changed) | `{ plugins: <manifest entry array> }` | rebuild caches, re-register external resources |
|
|
724
|
-
| `config:changed` | `runtime-settings.json` changed (`aw config set` / settings page, bridged from SystemConfigService) | `{ type: 'config:changed', changed: string[], effective: object, sources: object }` | hot-update thresholds, refresh caches |
|
|
725
|
-
| `event:permissions:changed` | after line grants were written successfully | `{ userId }` | refresh cached grant views |
|
|
726
|
-
| `event:*` | **a subscription entry, not an emitted event** | — | use the bare `'*'` to receive everything (§4.1) |
|
|
727
|
-
| `daq:sample` | DAQ **downlink-level** sampling (same point as WS `daq.reading`, on the node's `publishIntervalMs` cadence) | `{ nodeId, templateRef, value, state, at, lineId }` | limit alarms, statistics, interlocking |
|
|
728
|
-
| `daq:frame` | multi-modal frames (vector / image) at downlink level, on the same frame-ingest path as `daq:sample` | `{ nodeId, templateRef, kind, at, lineId, preview?, metrics, thumbUrl?, state }` | custom sinks, derived metrics |
|
|
729
|
-
| `dcw:write` | observation after a write-control ACK (never affects the write decision) | `{ nodeId, name, eng, prevValue, ok, source, lineId, at }` | write audit, trend recording |
|
|
730
|
-
| `line:start` | a line starts running (batch window opens) | `{ lineId, runId, recipeId, productName? }` | batch-start interlocking |
|
|
731
|
-
| `line:stop` | a line stops (batch window closes) | `{ lineId, runId }` | batch wrap-up, report generation |
|
|
732
|
-
| `server:close` | server shutdown, after the per-plugin dispose queues have run | `{ at }` | final flush, outbound notification |
|
|
733
|
-
|
|
734
|
-
`dcw:write`'s `source` is `'manual'` / `'recipe'` / `'agent'` / `'rollback'`; the payload
|
|
735
|
-
**has no `message` field** (look at platform logs or the ledger for a failure reason).
|
|
736
|
-
|
|
737
|
-
The `config:changed` payload **has no `at` field** — take the time yourself with `Date.now()`
|
|
738
|
-
when you receive it, and read the new values from `ctx.config.get/all()`.
|
|
739
|
-
|
|
740
|
-
### 5.2 Browser-side events (`CLIENT_EVENTS`, 5 items)
|
|
741
|
-
|
|
742
|
-
| Event | When it fires | Payload |
|
|
743
|
-
|---|---|---|
|
|
744
|
-
| `client:init` | after the client script's `setup(ctx)` has finished | `{ name }` |
|
|
745
|
-
| `event:*` | live scene events (same source as the browser WS, via the event bridge) | the event's own payload |
|
|
746
|
-
| `page:change` | route change finished (`page:finish`) | `{ path }` |
|
|
747
|
-
| `i18n:changed` | UI language switched | `{ locale }` |
|
|
748
|
-
| `client:destroy` | just before `ctx.dispose()` collects things | `{ name }` |
|
|
749
|
-
|
|
750
|
-
### 5.3 Subscription cheat sheet
|
|
751
|
-
|
|
752
|
-
| What you want | Server plugin | Browser plugin |
|
|
753
|
-
|---|---|---|
|
|
754
|
-
| A named lifecycle hook (`daq:sample` / `dcw:write` / `line:start` …) | `ctx.hooks.on('daq:sample', fn)` | not delivered (server hooks never reach the browser) |
|
|
755
|
-
| A scene event (e.g. `daq.reading`, `device.created`) | `ctx.events.on('daq.reading', fn)` | `ctx.on('daq.reading', fn)` |
|
|
756
|
-
| Every scene event | `ctx.hooks.on('*', ({ type, payload }) => …)` | `ctx.on('event:*', fn)` |
|
|
757
|
-
| A client-local hook (`client:init` / `page:change` / `i18n:changed` / `client:destroy`) | n/a | `ctx.hooks.on('page:change', fn)` |
|
|
758
|
-
|
|
759
|
-
The two easiest mistakes:
|
|
760
|
-
|
|
761
|
-
- The server wildcard is the bare `'*'` only: `ctx.hooks.on('event:*', fn)` **never fires**;
|
|
762
|
-
- The client wildcard is the literal `'event:*'` only: `ctx.on('*', fn)` **never fires**, and
|
|
763
|
-
`ctx.on('event:line.start', fn)` gets the prefix added twice (`event:event:line.start`) and
|
|
764
|
-
likewise never fires.
|
|
765
|
-
|
|
766
|
-
Scene events enter the bus as `event:<type>`, and `ctx.events.on('<type>', fn)` is the sugar that
|
|
767
|
-
adds the prefix. So the correct subscription for the scene event `permissions.changed` is
|
|
768
|
-
`ctx.events.on('permissions.changed', fn)`, while `ctx.hooks.on('permissions:changed', fn)`
|
|
769
|
-
never fires.
|
|
770
|
-
|
|
771
|
-
### 5.4 Shutdown and hot-reload sequences
|
|
772
|
-
|
|
773
|
-
```text
|
|
774
|
-
server shutdown (nitro close → shutdownPluginHost)
|
|
775
|
-
└─ per-plugin ctx.onDispose queue (each entry try/catch)
|
|
776
|
-
└─ broadcast server:close { at }
|
|
777
|
-
|
|
778
|
-
plugin hot reload (plugins-state.json changed / plugin enabled-disabled / 10 s poll fallback)
|
|
779
|
-
└─ per-plugin ctx.onDispose queue
|
|
780
|
-
└─ unbind every listener registered through ctx.hooks
|
|
781
|
-
└─ reload → broadcast plugins:reloaded
|
|
782
|
-
└─ broadcast the scene event plugins.reloaded (the browser loader hot-injects / unloads client plugins from it)
|
|
783
|
-
```
|
|
784
|
-
|
|
785
|
-
> v1 hooks are **observation-only** — they never change interlocking or write-control decisions;
|
|
786
|
-
> veto (interception / rewriting) hooks are on the roadmap.
|
|
787
|
-
|
|
788
|
-
---
|
|
789
|
-
|
|
790
|
-
## 6. Browser-side SDK (`agentworkshop/sdk/client`)
|
|
791
|
-
|
|
792
|
-
A plugin's `client.mjs` is a **self-contained ESM** module (no bare imports — the browser resolves
|
|
793
|
-
it natively) exporting `setup(ctx)`. The entry must be declared in the plugin definition as
|
|
794
|
-
`client: './client.mjs'`; the loader fetches the script from
|
|
795
|
-
`GET /api/plugins/client/<plugin name>` and imports it dynamically.
|
|
796
|
-
|
|
797
|
-
### 6.1 Creation (host-invoked; plugins only write `setup`)
|
|
798
|
-
|
|
799
|
-
```js
|
|
800
|
-
import { createClientContext } from 'agentworkshop/sdk/client'
|
|
801
|
-
|
|
802
|
-
// host-side assembly (illustrative); a plugin author only writes setup(ctx) in client.mjs
|
|
803
|
-
const listeners = new Set()
|
|
804
|
-
const townBus = {
|
|
805
|
-
subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn) },
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
const ctx = createClientContext({
|
|
809
|
-
name: 'my-plugin',
|
|
810
|
-
// event bridge: the host feeds every WS bus message into dispatch
|
|
811
|
-
eventBridge: dispatch => townBus.subscribe(e => dispatch(e.type, e.payload)),
|
|
812
|
-
baseUrl: '', // same-origin; fill in the platform address for cross-origin integration
|
|
813
|
-
ui: { slots: ['plugins.page'], registerPanel: () => () => {} },
|
|
814
|
-
t: key => `plugin.my-plugin.${key}`, // the host passes a real translation helper
|
|
815
|
-
getLocale: () => 'zh-CN',
|
|
816
|
-
})
|
|
817
|
-
```
|
|
818
|
-
|
|
819
|
-
### 6.2 `ctx` members
|
|
820
|
-
|
|
821
|
-
| Member | Notes |
|
|
822
|
-
|---|---|
|
|
823
|
-
| `ctx.name` | plugin name |
|
|
824
|
-
| `ctx.sdkVersion` | `CLIENT_SDK_VERSION` |
|
|
825
|
-
| `ctx.hooks` | the client-local `HookBus`; both local hooks and scene events ride this bus |
|
|
826
|
-
| `ctx.on(type, fn)` | subscribe to **live scene events**; `type` is the **scene event name itself** (e.g. `'daq.reading'` / `'daq.alarm'` / `'daq.alarm.changed'` / `'dcw.written'` / `'daq.node.changed'` / `'device.updated'`), installed as `event:<type>` internally; returns an unsubscribe function and is **auto-collected on pagehide**. The only wildcard spelling is the literal **`'event:*'`** |
|
|
827
|
-
| `ctx.fetch(path, opt?)` | same-origin platform API: automatic JSON, automatic `{data}` unwrapping, throws on non-2xx, and **automatically carries the platform token from the cookie** |
|
|
828
|
-
| `ctx.el(tag, attrs, children)` | DOM builder: `style` / `class` / `on*` event attributes get special handling |
|
|
829
|
-
| `ctx.mount(target, node)` | mount into any selector / element; falls back to `ctx.root()` when the target is missing |
|
|
830
|
-
| `ctx.root()` | the plugin's private mount point `#aw-plugin-<name>` (bottom-right, lazily created) |
|
|
831
|
-
| `ctx.ui` | UI injection surface: `slots` and `registerPanel(entry)` (§6.4) |
|
|
832
|
-
| `ctx.t(key, params?)` | plugin namespace translation: `ctx.t('panel.title')` → `plugin.<name>.panel.title` (messages come from `i18n.json` in the plugin root; a miss falls back to the original key). **`params` is currently ignored — there is no interpolation** |
|
|
833
|
-
| `ctx.locale` | the current UI language (read-only getter) |
|
|
834
|
-
| `ctx.log` | prefixed console: `info` / `warn` / `error` (**no `debug`**) |
|
|
835
|
-
| `ctx.dispose()` | unload: broadcast `client:destroy` → run local disposables → remove `root()`. **Idempotent**; it does not unregister panels (the loader does that on disable / hot reload) |
|
|
836
|
-
|
|
837
|
-
Two wrong spellings of `ctx.on`: `ctx.on('*')` and `ctx.on('event:line.start')` both
|
|
838
|
-
**never fire** — the former is not installed on the bare `'*'`, the latter gets a second prefix
|
|
839
|
-
and becomes `event:event:line.start`.
|
|
840
|
-
|
|
841
|
-
**Server hooks never reach the browser**: colon-named server hooks such as `daq:sample`,
|
|
842
|
-
`dcw:write`, `line:start` / `line:stop` are not delivered to the client. Their browser-side
|
|
843
|
-
counterparts are scene events (`daq.reading` / `daq.frame` / `dcw.written` and so on); subscribe
|
|
844
|
-
to those with `ctx.on('<scene-type>')`.
|
|
845
|
-
|
|
846
|
-
**Client lifecycle hooks cannot go through `ctx.on` either**: `client:init` / `page:change` /
|
|
847
|
-
`i18n:changed` / `client:destroy` must be subscribed directly with `ctx.hooks.on(...)` (they carry
|
|
848
|
-
no `event:` prefix).
|
|
849
|
-
|
|
850
|
-
### 6.3 Full example
|
|
851
|
-
|
|
852
|
-
```js
|
|
853
|
-
export function setup(ctx) {
|
|
854
|
-
const badge = ctx.el('div', {
|
|
855
|
-
style: 'padding:8px 12px;border:1px solid #35e0a0;border-radius:10px;color:#35e0a0',
|
|
856
|
-
}, ['samples: 0'])
|
|
857
|
-
ctx.root().append(badge)
|
|
858
|
-
|
|
859
|
-
let n = 0
|
|
860
|
-
ctx.on('daq.reading', () => { badge.textContent = `samples: ${++n}` }) // scene event
|
|
861
|
-
ctx.on('event:*', (payload) => ctx.log.info('scene event', payload)) // the only wildcard spelling
|
|
862
|
-
|
|
863
|
-
ctx.hooks.on('page:change', ({ path }) => ctx.log.info('page →', path)) // local hook: subscribe directly
|
|
864
|
-
|
|
865
|
-
// Consume the platform API (same-origin, cookie auth): the line list is { lines, states }, not an array
|
|
866
|
-
ctx.fetch('/api/workshop/dcw/lines').then(({ lines }) => ctx.log.info('lines', lines.length))
|
|
867
|
-
}
|
|
868
|
-
```
|
|
869
|
-
|
|
870
|
-
### 6.4 UI injection `ctx.ui.registerPanel`
|
|
871
|
-
|
|
872
|
-
```js
|
|
873
|
-
let samples = 0
|
|
874
|
-
ctx.on('daq.reading', () => { samples += 1 })
|
|
875
|
-
|
|
876
|
-
const off = ctx.ui.registerPanel({
|
|
877
|
-
slot: 'dashboard.widgets', // 'plugins.page' | 'settings.plugins' | 'dashboard.widgets'
|
|
878
|
-
name: 'my-widget',
|
|
879
|
-
title: 'Sample counter',
|
|
880
|
-
titleKey: 'plugin.my-plugin.widget.title', // titleKey wins when present
|
|
881
|
-
order: 100, // smaller comes first; default 100
|
|
882
|
-
mount(el) {
|
|
883
|
-
el.textContent = `samples: ${samples}`
|
|
884
|
-
const tick = setInterval(() => { el.textContent = `samples: ${samples}` }, 1000)
|
|
885
|
-
return () => clearInterval(tick) // called when the panel is unmounted
|
|
886
|
-
},
|
|
887
|
-
})
|
|
888
|
-
off() // the returned unregister function; ctx.dispose() does not call it, the loader collects it on disable
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
- `ctx.ui.slots` is exactly `['plugins.page', 'settings.plugins', 'dashboard.widgets']`.
|
|
892
|
-
- `registerPanel` returns an unregister function; if `mount(el)` returns a function it is called
|
|
893
|
-
when that panel is unmounted.
|
|
894
|
-
|
|
895
|
-
### 6.5 Constraints and trust
|
|
896
|
-
|
|
897
|
-
- **Self-contained**: no bare imports of `vue` or other third-party packages (the browser's native
|
|
898
|
-
import cannot resolve them) — build UI with native DOM (`ctx.el`);
|
|
899
|
-
- **Trust model**: client scripts are served by platform endpoints, trusted at the same level as
|
|
900
|
-
aw commands — only install plugins you trust;
|
|
901
|
-
- **Isolation**: a single plugin failing to load only logs a console warning; the app and other
|
|
902
|
-
plugins are unaffected.
|
|
903
|
-
|
|
904
|
-
---
|
|
905
|
-
|
|
906
|
-
## 7. Types and TypeScript
|
|
907
|
-
|
|
908
|
-
```ts
|
|
909
|
-
import type { PluginDef, PluginContext, PlatformClient } from 'agentworkshop/sdk'
|
|
910
|
-
|
|
911
|
-
export default {
|
|
912
|
-
name: 'typed-plugin',
|
|
913
|
-
auth: 'user',
|
|
914
|
-
async setup(ctx: PluginContext) {
|
|
915
|
-
const timeout: number = ctx.config.get('plugins.typed-plugin.timeout')
|
|
916
|
-
const client: PlatformClient = ctx.api
|
|
917
|
-
ctx.logger.info('api available:', typeof client.get === 'function', 'timeout:', timeout)
|
|
918
|
-
},
|
|
919
|
-
} satisfies PluginDef
|
|
920
|
-
```
|
|
921
|
-
|
|
922
|
-
The runtime **does not import** the SDK (keeping the zero-dependency shape); types are erased at
|
|
923
|
-
build time.
|
|
924
|
-
|
|
925
|
-
Current coverage of the type declarations (always defer to `sdk/index.d.mts` and
|
|
926
|
-
`sdk/client.d.mts`):
|
|
927
|
-
|
|
928
|
-
- Declared: `PluginDef`, `PluginContext`, `PluginHostExtensions`, `PluginSettingDecl`,
|
|
929
|
-
`PluginGroupDecl`, `PluginLogger`, `PluginKv`, `PluginHttp`, `CrudResource`, `PlatformClient`,
|
|
930
|
-
`ConfigChangedPayload`, `HookBus`, `ClientContext`, `ClientUi`, `ClientPanelEntry`,
|
|
931
|
-
`LIFECYCLE_EVENTS`, `CLIENT_EVENTS` and the factory functions.
|
|
932
|
-
- **Not yet declared**: `isPathInside`, `validatePluginSettings`, `validatePluginGroups` and
|
|
933
|
-
`resolvePluginGroupId` are runtime-only exports with no declaration in `.d.mts` — a TypeScript
|
|
934
|
-
project importing them gets TS2614 and needs a local declaration or `await import()`.
|
|
935
|
-
- In addition, `sdk/client.d.mts` declares an `el` named export that does not exist at runtime
|
|
936
|
-
(the runtime has only `CLIENT_SDK_VERSION` and `createClientContext`); importing it compiles
|
|
937
|
-
but yields `undefined` at runtime.
|
|
938
|
-
|
|
939
|
-
---
|
|
940
|
-
|
|
941
|
-
## 8. Versioning and compatibility policy
|
|
942
|
-
|
|
943
|
-
- The SDK interface follows semver: patch = fixes; minor = new hooks / `ctx` members
|
|
944
|
-
(backwards compatible); major = breaking contract changes. `SDK_VERSION` /
|
|
945
|
-
`CLIENT_SDK_VERSION` are the versions on that line and are **independent of the npm package
|
|
946
|
-
version** — never infer one from the other.
|
|
947
|
-
- The host exposes `ctx.sdkVersion` so a plugin can degrade gracefully by feature.
|
|
948
|
-
- Config-root hardening does not live in the single `aw start` command but in the **CLI context
|
|
949
|
-
builder** — every `aw` command calls it while resolving the run root (idempotently), so no
|
|
950
|
-
command fails just because a config-root directory is missing.
|
|
951
|
-
- There is **no version-based directory-layout migration**: the only migration copies data files
|
|
952
|
-
from the legacy locations into the config root, that is `cwd/data` (and the historical
|
|
953
|
-
`cwd/server/data`) → `<configRoot>/data`, only for `.sqlite` / `.sqlite-wal` / `.sqlite-shm` /
|
|
954
|
-
`.json`, with "newest wins" by `mtimeMs` on a name clash; when the config root falls back to
|
|
955
|
-
`~/.AgentWorkShop` that migration is skipped to avoid cross-project pollution.
|
|
956
|
-
|
|
957
|
-
---
|
|
958
|
-
|
|
959
|
-
## Appendix: scope of this page
|
|
960
|
-
|
|
961
|
-
This page is the single source of truth for the SDK; it follows the actual implementation in
|
|
962
|
-
`sdk/*.mjs`, `sdk/*.d.mts`, `server/services/workshop/plugins/host.mjs` and `server/api/**`.
|
|
963
|
-
CI copies this file to the site at `docs/site/en/sdk/guide.md`, and the Chinese original
|
|
964
|
-
`docs/sdk.md` to `docs/site/sdk/guide.md`.
|
|
1
|
+
# AgentWorkShop SDK Development and Usage Guide
|
|
2
|
+
|
|
3
|
+
> The SDK is AgentWorkShop's **programming client and extension base**: external projects
|
|
4
|
+
> consume the platform REST surface through it, and plugins receive the host-injected
|
|
5
|
+
> runtime context through it (hooks / config / storage / timers / platform API / event stream).
|
|
6
|
+
> Zero third-party runtime dependencies; works on Node ≥ 23.4 and modern browsers.
|
|
7
|
+
|
|
8
|
+
**SDK version constants**: server-side `SDK_VERSION = '0.3.0'`, browser-side `CLIENT_SDK_VERSION = '0.3.0'`.
|
|
9
|
+
These two constants are the **interface version of the SDK itself** and evolve **independently**
|
|
10
|
+
from the npm package version (the `version` field in `package.json`, currently 0.7.58) —
|
|
11
|
+
them being out of sync is expected. Never use `SDK_VERSION` to infer the package version, or the reverse.
|
|
12
|
+
**Module format**: ESM only (only `import` / `export`; there is no CJS entry).
|
|
13
|
+
**Types**: `sdk/index.d.mts` and `sdk/client.d.mts` ship with the package, so TypeScript projects
|
|
14
|
+
get IntelliSense with zero configuration (coverage is described in §7).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Getting the SDK
|
|
19
|
+
|
|
20
|
+
### 1.1 Global install (includes the CLI and the platform itself)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g agentworkshop
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The SDK lives inside the global package at `$(npm prefix -g)/node_modules/agentworkshop/sdk/`.
|
|
27
|
+
Plugins **need not and should not** import it directly (see the host-injection model in §2);
|
|
28
|
+
it serves two audiences:
|
|
29
|
+
|
|
30
|
+
- **External integration**: embed AgentWorkShop's line / DAQ / write-control / device-twin
|
|
31
|
+
capabilities into your own node service;
|
|
32
|
+
- **Plugin development** (TypeScript): import types only for full IntelliSense — the runtime
|
|
33
|
+
is injected by the host.
|
|
34
|
+
|
|
35
|
+
### 1.2 Project dependency (recommended for integrators)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install agentworkshop # as a dependency (full SDK and types)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 1.3 Import paths
|
|
42
|
+
|
|
43
|
+
`package.json` exposes exactly four `exports` entries:
|
|
44
|
+
|
|
45
|
+
| Import | Resolves to | Contents |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `agentworkshop` | `sdk/index.mjs` | **Exactly the same facade** as `agentworkshop/sdk` (the root specifier was previously undocumented; it works) |
|
|
48
|
+
| `agentworkshop/sdk` | `sdk/index.mjs` | The whole facade (server + browser + platform REST client + types) |
|
|
49
|
+
| `agentworkshop/sdk/client` | `sdk/client.mjs` | Browser only (`createClientContext`) |
|
|
50
|
+
| `agentworkshop/package.json` | `package.json` | Package metadata |
|
|
51
|
+
|
|
52
|
+
**Deep paths are not importable**: paths such as `agentworkshop/sdk/api.mjs` or
|
|
53
|
+
`agentworkshop/sdk/hooks.mjs` do not appear in `exports`, and Node throws
|
|
54
|
+
`ERR_PACKAGE_PATH_NOT_EXPORTED`. Take every symbol from one of the three entry points above.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { createPlatformClient, definePlugin, HookBus } from 'agentworkshop/sdk'
|
|
58
|
+
import { createClientContext } from 'agentworkshop/sdk/client' // browser only
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 1.4 Named export list
|
|
62
|
+
|
|
63
|
+
| Entry | Named exports |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `agentworkshop/sdk` (equivalent to `agentworkshop`) | `SDK_VERSION`, `definePlugin`, `createPluginContext`, `createRouteTable`, `validatePluginModule`, `validatePluginSettings`, `validatePluginGroups`, `resolvePluginGroupId`, `pluginKvExists`, `isPathInside`, `HookBus`, `createPlatformClient`, `CLIENT_SDK_VERSION`, `createClientContext`, `LIFECYCLE_EVENTS`, `CLIENT_EVENTS` |
|
|
66
|
+
| `agentworkshop/sdk/client` | `CLIENT_SDK_VERSION`, `createClientContext` |
|
|
67
|
+
|
|
68
|
+
### 1.5 The remaining named exports
|
|
69
|
+
|
|
70
|
+
Plugin authors normally work with the host-injected `ctx` (§4); the symbols below serve host
|
|
71
|
+
assembly, scaffolding and validation tooling.
|
|
72
|
+
|
|
73
|
+
| Symbol | Signature | Purpose |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `createPluginContext(opts)` | `opts` is the host assembly object | Called by the host to build `ctx`; plugin authors never call it themselves |
|
|
76
|
+
| `createRouteTable()` | → `{ register, resolve, byPlugin, unregisterPlugin, size }` | Host route table: exact match, mounted at `/api/plugins/<name><path>` |
|
|
77
|
+
| `definePlugin(def)` | `def` → `def` | Type sugar plus shape validation; throws on an invalid definition. The host also accepts a bare object export |
|
|
78
|
+
| `validatePluginModule(mod, source)` | → `{ ok, def?, error? }` | Pre-load entry check (`name` required, `setup` must be a function, `client` must be a string, `settings` must be an array) |
|
|
79
|
+
| `validatePluginSettings(pluginName, defs)` | → `{ descriptors, errors }` | Validate and normalize setting declarations; rules in §4.9 |
|
|
80
|
+
| `validatePluginGroups(pluginName, defs)` | → `{ groups, errors }` | Validate and normalize config-group declarations |
|
|
81
|
+
| `resolvePluginGroupId(pluginName, declaredId)` | → `string` | Fold a declared group name into the `plugin-<name>[-<suffix>]` namespace |
|
|
82
|
+
| `pluginKvExists(dataDir, name)` | → `boolean` | Probe whether `<dataDir>/plugins/<name>/kv.json` exists |
|
|
83
|
+
| `isPathInside(dir, p)` | → `boolean` | Path containment test (uses `relative()`, so a sibling directory with the same prefix such as `…/foo-evil` cannot fool it) |
|
|
84
|
+
| `HookBus` | `class` | The hook bus implementation; the host owns one shared instance and plugins receive a scoped facade (§4.1) |
|
|
85
|
+
| `LIFECYCLE_EVENTS` | frozen array (11 items) | Authoritative server-side event list (§5) |
|
|
86
|
+
| `CLIENT_EVENTS` | frozen array (5 items) | Authoritative browser-side event list (§5) |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 2. Core model: two identities, one SDK
|
|
91
|
+
|
|
92
|
+
| Identity | Form | Role of the SDK |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| **External integrator** | regular dependency | call `createPlatformClient()` to consume the platform REST surface |
|
|
95
|
+
| **Plugin author** | exports `{ name, setup(ctx) }` | `ctx` is the host-injected SDK context — **zero imports**, the SDK runtime is provided by the host |
|
|
96
|
+
|
|
97
|
+
> Why don't plugins import the SDK directly? Globally installed plugin directories
|
|
98
|
+
> (`~/.AgentWorkShop/plugins/`) are outside the node_modules resolution chain, so host
|
|
99
|
+
> injection is the only zero-pitfall shape (the same paradigm as VSCode's `activate(context)`).
|
|
100
|
+
|
|
101
|
+
A plugin entry is an ordinary ESM module:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
export default {
|
|
105
|
+
name: 'my-plugin',
|
|
106
|
+
version: '1.0.0',
|
|
107
|
+
description: 'Example plugin',
|
|
108
|
+
auth: 'none', // declarative auth for plugin routes, see §4.4
|
|
109
|
+
client: './client.mjs', // browser entry (optional), see §6
|
|
110
|
+
async setup(ctx) {
|
|
111
|
+
ctx.logger.info('loaded, directory:', ctx.dir)
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 3. Platform REST client `createPlatformClient`
|
|
119
|
+
|
|
120
|
+
The SDK fronts the platform as a "project service client": it attaches the Bearer token,
|
|
121
|
+
unwraps the unified envelope `{ code, message, data } → data`, and throws according to the
|
|
122
|
+
rules below.
|
|
123
|
+
|
|
124
|
+
### 3.1 Creating a client
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
import { createPlatformClient } from 'agentworkshop/sdk'
|
|
128
|
+
|
|
129
|
+
const api = createPlatformClient({
|
|
130
|
+
baseUrl: 'http://127.0.0.1:3001', // defaults to '' (same-origin relative); integrators pass the platform address
|
|
131
|
+
token: '<bearer-token>', // optional; api.setToken() swaps it later
|
|
132
|
+
timeoutMs: 10_000, // optional; per-request timeout (AbortSignal), default 10 000
|
|
133
|
+
logger, // optional; warns when a request fails
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- `baseUrl` defaults to `''`, i.e. same-origin relative paths; it **may also be a function**
|
|
138
|
+
evaluated lazily on every request (the host's listening port is only known once the server
|
|
139
|
+
actually listens, so the host passes `() => origin`).
|
|
140
|
+
- A trailing `/` is stripped: `'http://host:3001/'` and `'http://host:3001'` are equivalent.
|
|
141
|
+
|
|
142
|
+
### 3.2 Envelope and error semantics (three paths — do not mix them up)
|
|
143
|
+
|
|
144
|
+
| Case | Behaviour |
|
|
145
|
+
|---|---|
|
|
146
|
+
| HTTP non-2xx | throws an `Error` carrying **only `err.status` and `err.body`**; this path **does not set `err.code`** |
|
|
147
|
+
| HTTP 200 but envelope `code !== 0` | throws an `Error` carrying `err.status`, `err.code` **and** `err.body` |
|
|
148
|
+
| Success | returns the unwrapped `data`; a body with no `code`/`data` envelope is returned **as-is** (for example `GET /api/workshop/plugins`, `GET /api/plugins/manifest`) |
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
try {
|
|
152
|
+
await api.daqNodes.get('no-such-node')
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
err.status // 404
|
|
156
|
+
err.body // { code: 'NOT_FOUND', message: '…', data: null }
|
|
157
|
+
err.code // undefined —— this path does not set code
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
> On the platform side `defineApiHandler` sets a non-2xx status for business errors, so in
|
|
162
|
+
> practice you almost always hit the first path. The second path is a defensive check inside
|
|
163
|
+
> the SDK (`sdk/api.mjs` inspects `code` before unwrapping) aimed at endpoints that do not go
|
|
164
|
+
> through the unified wrapper yet still return an error envelope under HTTP 200 — without that
|
|
165
|
+
> check a plugin would unwrap the error envelope to `null` and treat it as success.
|
|
166
|
+
|
|
167
|
+
### 3.3 Generic calls (any platform path)
|
|
168
|
+
|
|
169
|
+
| Method | Signature | Notes |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `api.call(method, path, body?, opt?)` | low level | `opt` may carry `{ timeoutMs, headers }`; returns the unwrapped `data` |
|
|
172
|
+
| `api.get(path, query?)` | query object serialized automatically | `api.get('/api/workshop/dcw', { page: 1 })` |
|
|
173
|
+
| `api.post(path, body?)` | JSON-serialized | |
|
|
174
|
+
| `api.patch(path, body?)` | | |
|
|
175
|
+
| `api.delete(path)` | | |
|
|
176
|
+
| `api.setToken(token)` | chainable, returns `api` | `api.setToken(res.token)` after login; pass `null` to clear |
|
|
177
|
+
| `api.ping()` | `GET /api/plugins/manifest` | liveness probe (unauthenticated) |
|
|
178
|
+
|
|
179
|
+
`toQuery` **drops `undefined`, `null` and empty-string** values, so
|
|
180
|
+
`api.get('/x', { lineId: undefined })` never produces `?lineId=undefined`.
|
|
181
|
+
|
|
182
|
+
### 3.4 Resource surfaces and their real base paths
|
|
183
|
+
|
|
184
|
+
Every resource is built by the internal `resource(root)` helper, so **all of them expose five
|
|
185
|
+
methods**: `list(query?)`, `get(id)`, `create(body)`, `update(id, patch)`, `remove(id)`.
|
|
186
|
+
"A method exists" does not mean "the server route exists" — real availability is in §3.5.
|
|
187
|
+
|
|
188
|
+
| Namespace | Base path | Extra methods |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| `api.users` | `/api/users` | `login(email, password)` → `{ user, token }`; `me()` |
|
|
191
|
+
| `api.lines` | `/api/workshop/dcw/lines` | `start(id, recipeId = '')`; `stop(id)` |
|
|
192
|
+
| `api.products` | `/api/workshop/dcw/products` | — |
|
|
193
|
+
| `api.recipes` | `/api/workshop/dcw/recipes` | — |
|
|
194
|
+
| `api.dcwNodes` | `/api/workshop/dcw` | — |
|
|
195
|
+
| `api.daqNodes` | `/api/workshop/daq` | `alarms()` → `GET /api/workshop/daq/alarms` |
|
|
196
|
+
| `api.templates` | — | `daq()` / `dcw()`: read `.templates` off the two list responses |
|
|
197
|
+
| `api.twins` | `/api/workshop/device-twins` | — |
|
|
198
|
+
| `api.teams` | `/api/workshop/teams` | — |
|
|
199
|
+
| `api.agents` | `/api/workshop/agents` | — |
|
|
200
|
+
| `api.channels` | `/api/workshop/channels` | — |
|
|
201
|
+
| `api.permissions` | — | `overview()` → `GET /api/workshop/permissions`; `set({ userId, grants })` → `PUT /api/workshop/permissions` (admin) |
|
|
202
|
+
| `api.plugins` | — | `manifest()` |
|
|
203
|
+
|
|
204
|
+
The payload shape for `api.permissions.set`:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{ "userId": "<user id>", "grants": [{ "lineId": "<line id>", "mode": "readonly" }] }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`mode` is `'readonly'`, `'operate'` or `null` (passing `null` revokes that grant).
|
|
211
|
+
|
|
212
|
+
### 3.5 Real route support
|
|
213
|
+
|
|
214
|
+
`resource(root)` always generates five methods, but only some server route files exist.
|
|
215
|
+
**The table below is the result of checking every route file**: "no" means the call targets a
|
|
216
|
+
path that does not exist and therefore 404s.
|
|
217
|
+
|
|
218
|
+
| Namespace | `list` | `get(id)` | `create` | `update(id)` | `remove(id)` | Notes |
|
|
219
|
+
|---|---|---|---|---|---|---|
|
|
220
|
+
| `users` | yes | yes | yes | **no** | yes | The server only has `PUT /api/users/:id`, while `update()` sends `PATCH`; to update a user call `api.call('PUT', '/api/users/' + id, patch)` directly. `list`/`get`/`create` all require admin |
|
|
221
|
+
| `lines` | yes | no | yes | yes | yes | Plus `start` / `stop`. `create` requires the `admin` or `editor` role |
|
|
222
|
+
| `products` | **no** | no | yes | yes | yes | There is no `GET /api/workshop/dcw/products`; read the product list from `.products` of `GET /api/workshop/dcw` (see §3.6) |
|
|
223
|
+
| `recipes` | yes | no | yes | yes | yes | `list()` returns `{ recipes, runs }`; there is no route for `recipes.get(id)` |
|
|
224
|
+
| `dcwNodes` | yes | no | yes | yes | yes | No `[id].get.ts`; read the node list from `.nodes` of `GET /api/workshop/dcw` |
|
|
225
|
+
| `daqNodes` | yes | no | yes | yes | yes | No `[id].get.ts`; `alarms()` works |
|
|
226
|
+
| `twins` | yes | no | yes | yes | yes | No `[id].get.ts` |
|
|
227
|
+
| `teams` | yes | yes | yes | yes | yes | Full CRUD |
|
|
228
|
+
| `agents` | yes | yes | yes | yes | yes | Full CRUD |
|
|
229
|
+
| `channels` | yes | yes | yes | yes | yes | Full CRUD |
|
|
230
|
+
| `permissions` | `overview()` only | — | — | — | — | No five-method `resource()`; only `overview()` and `set()` |
|
|
231
|
+
| `plugins` | `manifest()` only | — | — | — | — | Unauthenticated |
|
|
232
|
+
|
|
233
|
+
Authentication and timeouts:
|
|
234
|
+
|
|
235
|
+
- Business read endpoints such as `api.lines.list()`, `api.daqNodes.list()` and
|
|
236
|
+
`api.dcwNodes.list()` go through platform auth and need a user token (`api.setToken(...)`,
|
|
237
|
+
or the cookie in a browser);
|
|
238
|
+
- `api.plugins.manifest()` and `api.ping()` are unauthenticated — the only two endpoints you
|
|
239
|
+
can call without a token.
|
|
240
|
+
|
|
241
|
+
### 3.6 Response shapes at a glance
|
|
242
|
+
|
|
243
|
+
**A list does not necessarily return an array** — this is the easiest trap in the whole SDK.
|
|
244
|
+
Every row below was checked against the server handler.
|
|
245
|
+
|
|
246
|
+
| Call | Real response |
|
|
247
|
+
|---|---|
|
|
248
|
+
| `api.lines.list()` | `{ lines, states }` (**not an array**) |
|
|
249
|
+
| `api.daqNodes.list()` | `{ controller, nodes, meta, driverAvailable, infra, templates }` |
|
|
250
|
+
| `api.dcwNodes.list()` | a multi-key object (`controller` / `nodes` / `templates` / `recipes` / `runs` / `history` / `products` / `lines` …), **not a node array** |
|
|
251
|
+
| `api.recipes.list()` | `{ recipes, runs }` |
|
|
252
|
+
| `api.twins.list()` | `{ twins }` |
|
|
253
|
+
| `api.daqNodes.alarms()` | `{ alarms }` |
|
|
254
|
+
| `api.permissions.overview()` | `{ lines, users }` |
|
|
255
|
+
| `api.templates.daq()` / `api.templates.dcw()` | an array (`.templates ?? []`) |
|
|
256
|
+
| `api.teams.list()` / `api.agents.list()` / `api.channels.list()` | an array |
|
|
257
|
+
| `api.users.list()` | `{ items, total, page, pageSize }` |
|
|
258
|
+
| `api.plugins.manifest()` | `{ plugins }` (no envelope, returned as-is) |
|
|
259
|
+
| `api.lines.create(body)` | `{ line }` |
|
|
260
|
+
| `api.recipes.create(body)` | `{ recipe }` |
|
|
261
|
+
| `api.products.create(body)` | `{ product }` |
|
|
262
|
+
| `api.dcwNodes.create(body)` / `api.daqNodes.create(body)` | `{ node }` |
|
|
263
|
+
| `api.twins.create(body)` | `{ twin }` |
|
|
264
|
+
| `api.lines.start(id, recipeId)` | `{ run, line }` |
|
|
265
|
+
| `api.users.login(email, password)` | `{ user, token }` |
|
|
266
|
+
|
|
267
|
+
About `api.daqNodes.list({ lineId })`: the `{ lineId }` query argument **is not read by that
|
|
268
|
+
handler**. Line filtering happens server-side from the caller's permissions (a regular user
|
|
269
|
+
only sees nodes of granted lines). Do not present it as a working client-side filter.
|
|
270
|
+
|
|
271
|
+
About `api.lines.start(id, recipeId)`: `recipeId` defaults to an empty string, but the server
|
|
272
|
+
**requires a recipe that actually exists** (an empty string or an unknown id yields
|
|
273
|
+
404 `Recipe 不存在`). When a line has recipes, `recipeId` is effectively mandatory.
|
|
274
|
+
|
|
275
|
+
### 3.7 Full example: external integration
|
|
276
|
+
|
|
277
|
+
```js
|
|
278
|
+
import { createPlatformClient } from 'agentworkshop/sdk'
|
|
279
|
+
|
|
280
|
+
const api = createPlatformClient({ baseUrl: 'http://plant.local:3001' })
|
|
281
|
+
|
|
282
|
+
const { token } = await api.users.login('you@example.com', 'secret')
|
|
283
|
+
api.setToken(token)
|
|
284
|
+
|
|
285
|
+
// 1) Line list: { lines, states } —— not an array
|
|
286
|
+
const { lines, states } = await api.lines.list()
|
|
287
|
+
console.log(`${lines.length} lines`)
|
|
288
|
+
for (const l of lines) {
|
|
289
|
+
console.log(` ${l.name} → ${states.find(s => s.lineId === l.id)?.state ?? 'unknown'}`)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 2) DAQ surface: { controller, nodes, meta, driverAvailable, infra, templates }
|
|
293
|
+
const { nodes } = await api.daqNodes.list()
|
|
294
|
+
console.log(`${nodes.length} DAQ nodes, ${nodes.filter(n => n.state === 'offline').length} offline`)
|
|
295
|
+
|
|
296
|
+
// 3) Write-control surface: the node list is an object too; products come from .products
|
|
297
|
+
const dcw = await api.dcwNodes.list()
|
|
298
|
+
console.log(`${dcw.nodes.length} DCW nodes, ${dcw.products.length} products`)
|
|
299
|
+
|
|
300
|
+
// 4) Recipe surface: { recipes, runs }
|
|
301
|
+
const { recipes } = await api.recipes.list()
|
|
302
|
+
|
|
303
|
+
// 5) Starting a line: recipeId must be a real recipe of that line (an empty string is rejected)
|
|
304
|
+
const line = lines[0]
|
|
305
|
+
const recipe = recipes.find(r => r.lineId === line?.id)
|
|
306
|
+
if (line && recipe) {
|
|
307
|
+
await api.lines.start(line.id, recipe.id)
|
|
308
|
+
await api.lines.stop(line.id)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 6) Line grants (admin): overview() reads everything, set() writes in bulk
|
|
312
|
+
const { users } = await api.permissions.overview()
|
|
313
|
+
const target = users[0]
|
|
314
|
+
if (target && line) {
|
|
315
|
+
await api.permissions.set({ userId: target.id, grants: [{ lineId: line.id, mode: 'readonly' }] })
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 4. Plugin context `ctx` (the complete member surface)
|
|
322
|
+
|
|
323
|
+
The `ctx` handed to `setup(ctx)` is the host-assembled SDK runtime. **The table below is the
|
|
324
|
+
complete surface**; the last three rows (`ctx.daq` / `ctx.omp` / `ctx.services`) are attached
|
|
325
|
+
directly by the plugin host before `setup` runs and are not part of `sdk/context.mjs`.
|
|
326
|
+
|
|
327
|
+
| Group | Member | Type | Notes |
|
|
328
|
+
|---|---|---|---|
|
|
329
|
+
| Identity | `ctx.name` | `string` | plugin name (= directory name / declared name) |
|
|
330
|
+
| | `ctx.scope` | `'builtin' \| 'project' \| 'user'` | load scope; on a name clash the priority is builtin > project > user |
|
|
331
|
+
| | `ctx.dir` | `string` | absolute path of the plugin directory |
|
|
332
|
+
| | `ctx.sdkVersion` | `string` | SDK interface version (= `SDK_VERSION`) |
|
|
333
|
+
| Hooks | `ctx.hooks` | `{ on, once, off, emit }` | per-plugin scoped hook facade (§4.1); **not a `HookBus` instance and has no `.size`** |
|
|
334
|
+
| Logging | `ctx.logger` | `{ debug, info, warn, error }` | output is prefixed `[aw-plugins] [<plugin name>]` |
|
|
335
|
+
| Config | `ctx.config.get(key)` | any | effective value (after the four-layer merge) |
|
|
336
|
+
| | `ctx.config.all()` | `Record<string, any>` | shallow copy of every effective setting |
|
|
337
|
+
| | `ctx.config.onChange(fn)` | unsubscribe function | subscribes to `config:changed` (§4.5) |
|
|
338
|
+
| | `ctx.config.defineGroup(def)` | group object \| `null` | declare a plugin-owned config group (§4.9) |
|
|
339
|
+
| | `ctx.config.defineField(decl)` | descriptor \| `null` | declare a setting field (key auto-addressed as `plugins.<name>.<key>`) |
|
|
340
|
+
| | `ctx.config.removeGroup(id)` | `boolean` | remove a group declaration |
|
|
341
|
+
| | `ctx.config.removeField(key)` | `boolean` | remove a field declaration |
|
|
342
|
+
| | `ctx.config.groups()` / `fields()` | arrays | the groups / fields this plugin currently has registered (read-only snapshot) |
|
|
343
|
+
| Paths | `ctx.paths` | `{ home, configRoot, dataDir }` | config-root information (home mode = `~/.AgentWorkShop`) |
|
|
344
|
+
| | `ctx.dataDir` | `string` | this plugin's private data directory = `<paths.dataDir>/plugins/<name>` |
|
|
345
|
+
| Storage | `ctx.kv` | `{ get, set, all, bump }` | plugin-private KV (§4.2); **there is no `reset()`** |
|
|
346
|
+
| Timers | `ctx.timer.setInterval(fn, ms)` / `setTimeout(fn, ms)` | timer id | auto `unref` + auto-collected on shutdown / hot reload (§4.3) |
|
|
347
|
+
| Cleanup | `ctx.onDispose(fn)` | the `fn` you passed | register a cleanup callback (§4.3) |
|
|
348
|
+
| | `ctx.subscriptions.add(d)` | the `d` you passed | register a `{ dispose() }` object or a function; same collection queue as `onDispose` |
|
|
349
|
+
| Routes | `ctx.route(method, path, handler)` | `boolean` | mounts at `/api/plugins/<name><path>`; auth is declared by the plugin's `auth` field (§4.4) |
|
|
350
|
+
| Platform | `ctx.api` | `PlatformClient` | loopback REST client (**no token by default**; §4.6) |
|
|
351
|
+
| Network | `ctx.http.get(url, opts)` / `post(url, body, opts)` | `Promise<Response>` | outbound requests; the guard is protocol-only; 8 s default timeout (§4.6) |
|
|
352
|
+
| Events | `ctx.events.on(type, fn)` / `off(type, fn)` | unsubscribe function | live scene event subscription; the `event:` prefix is added for you (§4.6) |
|
|
353
|
+
| Line permissions (host-injected) | `ctx.permissions` | see §4.7 | query and manage the per-user, per-line three-state grants |
|
|
354
|
+
| DAQ extension (host-injected) | `ctx.daq` | see §4.8 | driver / processor / template registration + frame subscription + time-series queries |
|
|
355
|
+
| Agent tools (host-injected) | `ctx.omp.registerTool(tool)` | see §4.8 | hot-inject a custom host tool at runtime |
|
|
356
|
+
| Runtime services (host-injected) | `ctx.services` | see §4.8 | lazy service access + cross-plugin service provision |
|
|
357
|
+
|
|
358
|
+
`ctx` has **no** `ctx.routes`, `ctx.dcw`, `ctx.scene` or `ctx.version`: route registration is
|
|
359
|
+
the singular `ctx.route()`; write-control traffic is observed through the `dcw:write` hook;
|
|
360
|
+
scene events go through `ctx.events`.
|
|
361
|
+
|
|
362
|
+
### 4.1 `ctx.hooks` — the hook facade
|
|
363
|
+
|
|
364
|
+
The host owns one shared `HookBus` named `aw-plugins`; a plugin receives a **scoped facade
|
|
365
|
+
exposing only `on` / `once` / `off` / `emit`**. Listeners registered through it are tracked and
|
|
366
|
+
auto-unbound when the plugin hot-reloads (the one cleanup path that always worked).
|
|
367
|
+
The facade exposes no diagnostic properties such as `count` / `size` / `listeners`.
|
|
368
|
+
|
|
369
|
+
```js
|
|
370
|
+
function onSample(sample) {
|
|
371
|
+
ctx.kv.bump('samples')
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const off = ctx.hooks.on('daq:sample', onSample) // returns an unsubscribe function
|
|
375
|
+
ctx.hooks.once('server:close', () => { /* teardown, fires once */ })
|
|
376
|
+
ctx.hooks.off('daq:sample', onSample) // manual unbind: pass the original handler
|
|
377
|
+
off() // or just call the function returned by on()
|
|
378
|
+
|
|
379
|
+
await ctx.hooks.emit('my-plugin:custom', { hello: 1 }) // inter-plugin messaging: other plugins can listen
|
|
380
|
+
ctx.hooks.on('*', ({ type, payload }) => { /* every event */ })
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Semantics (matching `sdk/hooks.mjs`):
|
|
384
|
+
|
|
385
|
+
- **Async-serial**: listeners of one type run in registration order and are awaited; the next
|
|
386
|
+
one does not start until the previous returns;
|
|
387
|
+
- **Error isolation**: one throwing listener is only counted and warned about; siblings and the
|
|
388
|
+
main service are unaffected;
|
|
389
|
+
- **Circuit breaker**: a listener failing **8 times in a row** is removed automatically;
|
|
390
|
+
**any single success resets the counter**, so occasional failures never accumulate into an eviction;
|
|
391
|
+
- **Wildcard**: the only server-side wildcard spelling is the bare `'*'`; its callback receives
|
|
392
|
+
`{ type, payload }` and runs after the named listeners;
|
|
393
|
+
- **The return value is fan-out, not a waterfall**: every listener receives **the same unmodified
|
|
394
|
+
payload**; `emit()` merely returns "the last non-`undefined` return value" — values are never
|
|
395
|
+
threaded from one listener to the next;
|
|
396
|
+
- **v1 is observation-only**: there is no veto / interception / rewriting.
|
|
397
|
+
|
|
398
|
+
> `ctx.hooks.on('event:*')` never fires. `event:*` is the subscription entry name the list uses
|
|
399
|
+
> for scene events; the real wildcard is the bare `'*'`, and the ergonomic scene-event form is
|
|
400
|
+
> `ctx.events.on('<type>', fn)` (§4.6).
|
|
401
|
+
|
|
402
|
+
### 4.2 `ctx.kv` — plugin-private persistence
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
ctx.kv.set('threshold', 100)
|
|
406
|
+
ctx.kv.bump('samples') // atomic increment, +1 by default; bump(key, by) sets the step
|
|
407
|
+
ctx.kv.bump('samples', 5)
|
|
408
|
+
ctx.kv.get('threshold') // 100
|
|
409
|
+
ctx.kv.all() // { samples: 19453, threshold: 100, ... }
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
- **These four methods only**: `get` / `set` / `all` / `bump`. **No `reset()`, no `delete()`,
|
|
413
|
+
no `keys()`**; to clear a key, `set` it explicitly or switch to a new key.
|
|
414
|
+
- On-disk location: `<ctx.dataDir>/kv.json`, i.e. `<paths.dataDir>/plugins/<name>/kv.json`.
|
|
415
|
+
- **In-memory state is authoritative + a 200 ms debounced atomic write** (temp file plus
|
|
416
|
+
`rename`), so a high-frequency hook (`daq:sample`) and a low-frequency hook (`line:stop`)
|
|
417
|
+
calling concurrently cannot race on read-modify-write.
|
|
418
|
+
- On shutdown / hot reload the pending debounce is **cancelled and flushed synchronously**, so a
|
|
419
|
+
`set` from the last 200 ms before exit is not lost.
|
|
420
|
+
- Typical uses: counters, alarm state, threshold config, heartbeat timestamps.
|
|
421
|
+
|
|
422
|
+
### 4.3 `ctx.timer` / `ctx.onDispose` / `ctx.subscriptions`
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
ctx.timer.setInterval(() => ctx.kv.set('heartbeat', Date.now()), 5000)
|
|
426
|
+
ctx.timer.setTimeout(() => ctx.logger.info('one-shot task'), 1000)
|
|
427
|
+
|
|
428
|
+
ctx.onDispose(() => ctx.logger.info('plugin cleanup done'))
|
|
429
|
+
|
|
430
|
+
// subscriptions.add accepts a { dispose() } object or a function; same queue as onDispose
|
|
431
|
+
const controller = new AbortController()
|
|
432
|
+
ctx.subscriptions.add({ dispose() { controller.abort() } })
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
- Timers created by `ctx.timer.setInterval/setTimeout` are automatically `unref`ed (they never
|
|
436
|
+
hold the process open) and automatically registered with the collection queue, so **you never
|
|
437
|
+
have to clear them by hand**.
|
|
438
|
+
- `ctx.onDispose(fn)` and `ctx.subscriptions.add(d)` (`d` may be `{ dispose() }` or a function)
|
|
439
|
+
share **one host-owned collection queue** with the timers.
|
|
440
|
+
- That queue runs on **both server shutdown and plugin hot reload** — a guarantee this version of
|
|
441
|
+
the SDK can make after the fix (`createPluginContext` previously failed to forward the host's
|
|
442
|
+
`onDispose` injection point, leaking timers and losing the final kv write).
|
|
443
|
+
|
|
444
|
+
Server shutdown sequence:
|
|
445
|
+
|
|
446
|
+
```text
|
|
447
|
+
server shutdown (nitro close)
|
|
448
|
+
└─ per-plugin dispose queue (each entry try/catch): clear timers, flush kv synchronously, unbind subscriptions…
|
|
449
|
+
└─ broadcast server:close { at }
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### 4.4 `ctx.route` — plugin API
|
|
453
|
+
|
|
454
|
+
```js
|
|
455
|
+
export default {
|
|
456
|
+
name: 'my-plugin',
|
|
457
|
+
auth: 'user', // declarative auth: 'none' (default) | 'user' | 'admin' | 'agent-or-user'
|
|
458
|
+
async setup(ctx) {
|
|
459
|
+
// returns boolean: true = registration succeeded, false = handler is not a function
|
|
460
|
+
const ok = ctx.route('GET', '/stats', () => ctx.kv.all())
|
|
461
|
+
if (!ok) ctx.logger.warn('route registration failed')
|
|
462
|
+
|
|
463
|
+
ctx.route('POST', '/threshold', (event) => {
|
|
464
|
+
const body = event.awBody // the JSON body the host already pre-read (may be undefined)
|
|
465
|
+
const threshold = Number(body?.threshold)
|
|
466
|
+
if (!Number.isFinite(threshold)) return { ok: false, error: 'threshold must be a number' }
|
|
467
|
+
ctx.kv.set('threshold', threshold)
|
|
468
|
+
return { ok: true, threshold } // the return value is serialized to JSON by nitro
|
|
469
|
+
})
|
|
470
|
+
},
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
→ mounted at `GET /api/plugins/<plugin name>/stats` and
|
|
475
|
+
`POST /api/plugins/<plugin name>/threshold`.
|
|
476
|
+
|
|
477
|
+
- **The return value is `boolean`**: `false` when `handler` is not a function.
|
|
478
|
+
- **Paths** start with `/` (a missing one is added for you); the base is always
|
|
479
|
+
`/api/plugins/<plugin name>`.
|
|
480
|
+
- **Auth is declarative — do not write your own**: give the plugin definition
|
|
481
|
+
`auth: 'none' | 'user' | 'admin' | 'agent-or-user'` and the platform catch-all
|
|
482
|
+
(`server/api/plugins/[name]/[...path].ts`) validates it **before** your handler runs,
|
|
483
|
+
returning 401 on failure.
|
|
484
|
+
- **The handler cannot obtain a user object**: `resolveUser(event)` is not on `ctx` and cannot be
|
|
485
|
+
imported from a plugin module. When you need an identity, combine the `auth` gate with
|
|
486
|
+
`ctx.api.setToken(...)` and go through the platform API.
|
|
487
|
+
- **The JSON body is already pre-read** and attached as `event.awBody` (not h3's `readBody`).
|
|
488
|
+
- Handler errors are isolated: the platform logs with the plugin name and returns a 500 envelope
|
|
489
|
+
(`插件路由处理失败(<plugin name>): <original message>`) without leaking a stack trace.
|
|
490
|
+
|
|
491
|
+
### 4.5 `ctx.config` — reading config and reacting to change
|
|
492
|
+
|
|
493
|
+
```js
|
|
494
|
+
ctx.config.get('plugins.my-plugin.threshold') // effective value (after the four-layer merge)
|
|
495
|
+
ctx.config.all() // every effective setting (shallow copy)
|
|
496
|
+
|
|
497
|
+
const off = ctx.config.onChange((payload) => { // payload: the config:changed payload, see §5
|
|
498
|
+
ctx.logger.info('config changed:', payload?.changed)
|
|
499
|
+
})
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
`config:changed` is bridged onto the plugin bus from the platform settings service, and
|
|
503
|
+
`ctx.config.onChange(fn)` is essentially `ctx.hooks.on('config:changed', fn)`, so it is likewise
|
|
504
|
+
auto-unbound on hot reload.
|
|
505
|
+
|
|
506
|
+
### 4.6 `ctx.api` / `ctx.http` / `ctx.events` — which one to use
|
|
507
|
+
|
|
508
|
+
| Need | Use | Why |
|
|
509
|
+
|---|---|---|
|
|
510
|
+
| Read / write **platform business data** (lines, nodes, twins…) | `ctx.api` | auth / envelope / resource semantics out of the box |
|
|
511
|
+
| Call an **external system** (MES, webhook, mail gateway) | `ctx.http` | generic requests plus a protocol guard |
|
|
512
|
+
| React to the **live stream** (samples, alarms, start/stop) | `ctx.events` / `ctx.hooks.on` | in-process, zero HTTP overhead |
|
|
513
|
+
|
|
514
|
+
```js
|
|
515
|
+
// ctx.api: the loopback PlatformClient. baseUrl is resolved lazily by the host; no token by default.
|
|
516
|
+
const { token } = await ctx.api.users.login('user@example.com', 'secret')
|
|
517
|
+
ctx.api.setToken(token) // later loopback calls carry that token
|
|
518
|
+
const { lines } = await ctx.api.lines.list()
|
|
519
|
+
|
|
520
|
+
// ctx.http: outbound requests, protocol guard only (http/https), 8 s default timeout
|
|
521
|
+
const res = await ctx.http.get('https://mes.example.com/health', { timeoutMs: 3000 })
|
|
522
|
+
const payload = await ctx.http.post('https://mes.example.com/events', { lineId: 'L1' })
|
|
523
|
+
|
|
524
|
+
// ctx.events: scene events — pass the scene event name itself; the `event:` prefix is added for you
|
|
525
|
+
ctx.events.on('daq.reading', r => ctx.logger.info('sample', r.nodeId))
|
|
526
|
+
ctx.events.on('permissions.changed', ({ userId }) => ctx.logger.info('grants changed', userId))
|
|
527
|
+
ctx.events.on('device.created', d => ctx.logger.info('new device', d.id))
|
|
528
|
+
const off = ctx.events.on('daq.alarm', a => ctx.logger.warn('alarm', a.id))
|
|
529
|
+
off()
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
- `ctx.api` has **no token by default**: unauthenticated endpoints (`plugins.manifest` / `ping`)
|
|
533
|
+
work immediately; anything else needs a login followed by `setToken`. If you only need
|
|
534
|
+
in-process data, prefer `ctx.events` and `ctx.hooks` (no auth, no overhead).
|
|
535
|
+
- The `ctx.http` guard **checks the protocol only** and does not restrict hosts — the target
|
|
536
|
+
address is the plugin's own responsibility.
|
|
537
|
+
- `ctx.events.on(type, fn)` / `off(type, fn)` install `event:<type>` underneath; to receive every
|
|
538
|
+
scene event use `ctx.hooks.on('*', ({ type, payload }) => …)`.
|
|
539
|
+
|
|
540
|
+
### 4.7 `ctx.permissions` — per-user, per-line grants
|
|
541
|
+
|
|
542
|
+
| Method | Returns | Notes |
|
|
543
|
+
|---|---|---|
|
|
544
|
+
| `lineMode(user, lineId)` | `'none' \| 'readonly' \| 'operate'` | `user` is `{ id, role }`; admin/editor is always `operate` |
|
|
545
|
+
| `visibleLineIds(user)` | `Set<string> \| null` | `null` means unrestricted (admin/editor) |
|
|
546
|
+
| `listGrants(userId)` | `Array<{ lineId, mode, grantedBy, grantedAt }>` | read every grant of one user |
|
|
547
|
+
| `setGrants(userId, grants, grantedBy?)` | the grants after the write | `grants` looks like `[{ lineId, mode }]` with `mode` = `'readonly'` / `'operate'` / `null` |
|
|
548
|
+
|
|
549
|
+
```js
|
|
550
|
+
const userId = ctx.kv.get('watchUserId') // a plugin gets userIds from event payloads or its own config
|
|
551
|
+
if (userId) {
|
|
552
|
+
const mode = ctx.permissions.lineMode({ id: userId, role: 'user' }, 'line-1')
|
|
553
|
+
const visible = ctx.permissions.visibleLineIds({ id: userId, role: 'user' })
|
|
554
|
+
const grants = ctx.permissions.listGrants(userId)
|
|
555
|
+
ctx.logger.info(`mode=${mode} visible=${visible ? visible.size : 'all'} grants=${grants.length}`)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Change notification is the scene event permissions.changed, subscribed via ctx.events (prefix added for you)
|
|
559
|
+
ctx.events.on('permissions.changed', ({ userId }) => ctx.logger.info('grants changed:', userId))
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### 4.8 Host-injected extensions `ctx.daq` / `ctx.omp` / `ctx.services`
|
|
563
|
+
|
|
564
|
+
**`ctx.daq`** — multi-modal DAQ extension (v0.6 frame pipeline):
|
|
565
|
+
|
|
566
|
+
| Method | Notes |
|
|
567
|
+
|---|---|
|
|
568
|
+
| `registerDriver({ kind, available, sample, test })` | register a custom driver |
|
|
569
|
+
| `registerProcessor(kind, name, fn)` | register a sink processor (after sampling, before storage) |
|
|
570
|
+
| `registerTemplate(def)` | register a DAQ node template (`key` / `signalKind` / `vector` / `sink` / `metrics`) |
|
|
571
|
+
| `onFrame(fn)` | frame subscription sugar (= `ctx.hooks.on('daq:frame', fn)`) |
|
|
572
|
+
| `onSample(fn)` | sample subscription sugar (= `ctx.hooks.on('daq:sample', fn)`) |
|
|
573
|
+
| `query({ nodeIds?, lineId?, from?, to?, bucketMs? })` | unauthenticated time-series query (straight to `queryTagged`) |
|
|
574
|
+
| `nodes()` | DAQ node metadata snapshot (including line ownership) |
|
|
575
|
+
|
|
576
|
+
```js
|
|
577
|
+
ctx.daq.registerProcessor('vector', 'my-derive', (frame) => {
|
|
578
|
+
// frame = { kind: 'vector'|'image', points? | blob? (image producer side only), metrics }
|
|
579
|
+
return { ...frame, metrics: { ...frame.metrics, myMetric: 1 } }
|
|
580
|
+
})
|
|
581
|
+
ctx.daq.onFrame(f => ctx.logger.debug('frame', f.nodeId, f.kind))
|
|
582
|
+
const rows = await ctx.daq.query({ nodeIds: ['n1'], from: Date.now() - 3600_000, to: Date.now(), bucketMs: 60_000 })
|
|
583
|
+
const all = await ctx.daq.nodes()
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
A template's `sink.processors` declares the sink pipeline; `metrics` declares derived-metric
|
|
587
|
+
thresholds whose breaches ride the platform's existing alarm chain. Vector / frame metadata lands
|
|
588
|
+
in Timescale `daq_frames`; image pixels land in object storage (the `daq:frame` payload
|
|
589
|
+
**carries no pixel blob**).
|
|
590
|
+
|
|
591
|
+
**`ctx.omp.registerTool({ name, label?, description, parameters, roles?, handler })`** —
|
|
592
|
+
register a custom host tool, hot-injected into every running agent session at runtime:
|
|
593
|
+
|
|
594
|
+
```js
|
|
595
|
+
ctx.omp.registerTool({
|
|
596
|
+
name: 'sensor_log',
|
|
597
|
+
label: 'Sensor calibration',
|
|
598
|
+
description: 'Query or record sensor calibration conclusions',
|
|
599
|
+
parameters: { type: 'object', properties: { sensor: { type: 'string' } }, required: ['sensor'] },
|
|
600
|
+
roles: ['lead', 'worker'], // the only valid literals are 'lead' and 'worker'; default is both
|
|
601
|
+
handler: async (args, agent) => ({ text: `recorded ${args.sensor}` }), // agent = { agentId, channelId, role, name }
|
|
602
|
+
})
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
Registry changes are hot-injected into running sessions immediately (re-sending `set_host_tools`,
|
|
606
|
+
no respawn); a tool sharing a name with a built-in host tool is ignored.
|
|
607
|
+
|
|
608
|
+
**`ctx.services`** — the backend runtime object surface (lazy getters, cached after first access):
|
|
609
|
+
|
|
610
|
+
| Call | Resolves to |
|
|
611
|
+
|---|---|
|
|
612
|
+
| `ctx.services.names()` | every service name (including plugin-provided `<plugin>.<name>`) |
|
|
613
|
+
| `await ctx.services.get('daq')` | `{ query(q), nodes() }` |
|
|
614
|
+
| `await ctx.services.get('lines')` | `{ list(), byId(id) }` |
|
|
615
|
+
| `await ctx.services.get('channels')` | `{ list(), agents(channelId) }` |
|
|
616
|
+
| `await ctx.services.get('plugins')` | the plugin manifest **array** (note: not an object and with no `pluginManifest()`) |
|
|
617
|
+
| `ctx.services.provide(name, getter)` | provide a service, auto-prefixed with `<plugin>.` |
|
|
618
|
+
|
|
619
|
+
```js
|
|
620
|
+
const daq = await ctx.services.get('daq')
|
|
621
|
+
const lines = await ctx.services.get('lines')
|
|
622
|
+
const channels = await ctx.services.get('channels')
|
|
623
|
+
const plugins = await ctx.services.get('plugins') // an array
|
|
624
|
+
ctx.services.provide('my-data', async () => ({ ready: true })) // → 'my-plugin.my-data'
|
|
625
|
+
ctx.logger.info(ctx.services.names().join(', '))
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
An unknown name throws (the caller is expected to handle it). `provide` forces the
|
|
629
|
+
`<plugin>.` prefix so cross-plugin name clashes cannot happen.
|
|
630
|
+
|
|
631
|
+
### 4.9 Plugin setting declarations (`settings` / `configGroups`)
|
|
632
|
+
|
|
633
|
+
Two equivalent routes: the top-level `settings` array in the entry (declarative), or
|
|
634
|
+
`ctx.config.defineField` inside `setup` (conditional).
|
|
635
|
+
|
|
636
|
+
```js
|
|
637
|
+
export default {
|
|
638
|
+
name: 'my-plugin',
|
|
639
|
+
configGroups: [{ id: 'conn', label: 'Connection', collapsed: true }],
|
|
640
|
+
settings: [
|
|
641
|
+
{ key: 'base_url', type: 'string', default: 'https://example.com', group: 'conn',
|
|
642
|
+
labelKey: 'plugin.my-plugin.base_url', label: 'Service URL' },
|
|
643
|
+
],
|
|
644
|
+
async setup(ctx) {
|
|
645
|
+
// equivalent form: add declarations conditionally at runtime
|
|
646
|
+
ctx.config.defineGroup({ id: 'sync', label: 'Sync' })
|
|
647
|
+
ctx.config.defineField({ key: 'interval', type: 'number', default: 30, min: 1, max: 3600, group: 'sync' })
|
|
648
|
+
},
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
Validation rules (an entry that fails **is skipped with a warning**; it never blocks loading):
|
|
653
|
+
|
|
654
|
+
| Rule | Detail |
|
|
655
|
+
|---|---|
|
|
656
|
+
| `key` | must match `[A-Za-z0-9_-]+`; addressed as `plugins.<plugin name>.<key>` |
|
|
657
|
+
| `type` | one of `'string'` / `'number'` / `'boolean'` / `'select'` |
|
|
658
|
+
| `default` | **required** — a declaration without `default` is skipped outright |
|
|
659
|
+
| `select` | must supply an `options` array, and `default` must appear among its stringified values |
|
|
660
|
+
| `min` / `max` | **apply to `number` only** |
|
|
661
|
+
| Group | an explicit `group` is folded into the `plugin-<name>[-<suffix>]` namespace; a field without `group` lands in the `plugin-<name>` group labelled with the plugin name |
|
|
662
|
+
|
|
663
|
+
Once declared, the settings are merged into the platform settings service: the "Plugins" section
|
|
664
|
+
of the settings page renders them automatically, PATCH validation uses the same source, and
|
|
665
|
+
saving takes effect immediately. Read values with the full key:
|
|
666
|
+
`ctx.config.get('plugins.my-plugin.base_url')`.
|
|
667
|
+
|
|
668
|
+
### 4.10 `ctx.twin` — hybrid-twin Provider Registry bridge
|
|
669
|
+
|
|
670
|
+
`ctx.twin` registers an industrial scene's **physics core / scene pack / objectives / training and solver
|
|
671
|
+
adapters** into the hybrid-twin Provider Registry. The agent's twin tools (`twin_scene_read` /
|
|
672
|
+
`twin_snapshot_create` / `twin_trial_run` / `mpc_optimize`) resolve your provider through
|
|
673
|
+
`SceneContract.physicsProfileId`, falling back to the bundled `twin-injection-default`.
|
|
674
|
+
**Swapping scenes needs no tool or channel change.**
|
|
675
|
+
|
|
676
|
+
| Member | Notes |
|
|
677
|
+
|---|---|
|
|
678
|
+
| `registerPhysicsProvider(provider)` | register a physics core: manifest (`providerId` / `version` / `apiVersion: 'twin-provider.v1'` / `sceneKinds` / `backend` / the four variable tables / `parameterPriors` / `capabilities` / `artifactContract`) plus `initialize` / `step` / `simulate` / `evaluateConstraints`, optional `validateScene` / `calibrate` / `designSafeExperiment` / `estimateUncertainty` / `exportArtifacts` / `health` |
|
|
679
|
+
| `registerScenePack(pack)` | `{ sceneKind, sceneSchemaVersion, compile?, discover?, constraints?, objectives?, datasetSchema? }` — compiles field nodes and recipe into a `SceneContract` |
|
|
680
|
+
| `registerObjectiveProfile(profile)` | MPC objectives and weights |
|
|
681
|
+
| `registerTrainingAdapter(adapter)` / `registerSolverAdapter(adapter)` | training / external-solver adapters (ONNX, ROM, third-party solvers) |
|
|
682
|
+
| `listProviders(filter?)` / `getProviderHealth(id, version?)` | listing and health checks; health feeds the "may be used" decision |
|
|
683
|
+
| `resolveProvider(id, version?)` / `validateProvider(id, version?)` | resolve the active generation / validate without registering (pre-flight self-check) |
|
|
684
|
+
| `retireProvider(id, version?)` | explicit retirement; only unloads after references reach zero |
|
|
685
|
+
| `isRegistryAvailable()` | whether the bridge is ready (while it is not, registration calls are queued, so startup order cannot lose registrations) |
|
|
686
|
+
|
|
687
|
+
**Lifecycle and generations**: `DISCOVERED → VALIDATED → REGISTERED → READY → DRAINING → RETIRED`
|
|
688
|
+
(`FAILED` when validation rejects). A hot reload stages the new **generation** and drains the old one:
|
|
689
|
+
in-flight trials / MPC hold a lease and are never invalidated during a drain, and `unregisterPlugin`
|
|
690
|
+
means "drain + retire", so a disabled plugin loses its provider.
|
|
691
|
+
|
|
692
|
+
```js
|
|
693
|
+
export default {
|
|
694
|
+
name: 'my-twin-provider',
|
|
695
|
+
version: '1.0.0',
|
|
696
|
+
auth: 'none',
|
|
697
|
+
async setup(ctx) {
|
|
698
|
+
if (!ctx.twin.isRegistryAvailable()) return // registrations queue while the bridge is down
|
|
699
|
+
ctx.twin.registerPhysicsProvider(myProvider) // see docs/plugins.md, "Hybrid-twin provider plugins"
|
|
700
|
+
ctx.twin.registerScenePack(myScenePack)
|
|
701
|
+
const ok = await ctx.twin.validateProvider('my-provider', '1.0.0')
|
|
702
|
+
ctx.logger.info(`provider check: ${JSON.stringify(ok)}`)
|
|
703
|
+
},
|
|
704
|
+
}
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
Full field tables, generational hot-swap semantics and a runnable example live in
|
|
708
|
+
`docs/plugins.md`, section "Hybrid-twin provider plugins".
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## 5. Lifecycle events
|
|
713
|
+
|
|
714
|
+
The authoritative lists are the SDK-exported `LIFECYCLE_EVENTS` (11 items) and
|
|
715
|
+
`CLIENT_EVENTS` (5 items), both checked one by one against what the host actually emits.
|
|
716
|
+
**Every event is also part of the config-root event stream.**
|
|
717
|
+
|
|
718
|
+
### 5.1 Server-side events (`LIFECYCLE_EVENTS`, 11 items)
|
|
719
|
+
|
|
720
|
+
| Event name (bus type) | When it fires | Payload | Typical use |
|
|
721
|
+
|---|---|---|---|
|
|
722
|
+
| `plugin:host:init` | once, after the host has loaded every plugin (including disabled ones) | `{ plugins: string[], failures: number }` | readiness proof, deferred init |
|
|
723
|
+
| `plugins:reloaded` | end of a hot reload (plugin enabled/disabled, `plugins-state.json` changed) | `{ plugins: <manifest entry array> }` | rebuild caches, re-register external resources |
|
|
724
|
+
| `config:changed` | `runtime-settings.json` changed (`aw config set` / settings page, bridged from SystemConfigService) | `{ type: 'config:changed', changed: string[], effective: object, sources: object }` | hot-update thresholds, refresh caches |
|
|
725
|
+
| `event:permissions:changed` | after line grants were written successfully | `{ userId }` | refresh cached grant views |
|
|
726
|
+
| `event:*` | **a subscription entry, not an emitted event** | — | use the bare `'*'` to receive everything (§4.1) |
|
|
727
|
+
| `daq:sample` | DAQ **downlink-level** sampling (same point as WS `daq.reading`, on the node's `publishIntervalMs` cadence) | `{ nodeId, templateRef, value, state, at, lineId }` | limit alarms, statistics, interlocking |
|
|
728
|
+
| `daq:frame` | multi-modal frames (vector / image) at downlink level, on the same frame-ingest path as `daq:sample` | `{ nodeId, templateRef, kind, at, lineId, preview?, metrics, thumbUrl?, state }` | custom sinks, derived metrics |
|
|
729
|
+
| `dcw:write` | observation after a write-control ACK (never affects the write decision) | `{ nodeId, name, eng, prevValue, ok, source, lineId, at }` | write audit, trend recording |
|
|
730
|
+
| `line:start` | a line starts running (batch window opens) | `{ lineId, runId, recipeId, productName? }` | batch-start interlocking |
|
|
731
|
+
| `line:stop` | a line stops (batch window closes) | `{ lineId, runId }` | batch wrap-up, report generation |
|
|
732
|
+
| `server:close` | server shutdown, after the per-plugin dispose queues have run | `{ at }` | final flush, outbound notification |
|
|
733
|
+
|
|
734
|
+
`dcw:write`'s `source` is `'manual'` / `'recipe'` / `'agent'` / `'rollback'`; the payload
|
|
735
|
+
**has no `message` field** (look at platform logs or the ledger for a failure reason).
|
|
736
|
+
|
|
737
|
+
The `config:changed` payload **has no `at` field** — take the time yourself with `Date.now()`
|
|
738
|
+
when you receive it, and read the new values from `ctx.config.get/all()`.
|
|
739
|
+
|
|
740
|
+
### 5.2 Browser-side events (`CLIENT_EVENTS`, 5 items)
|
|
741
|
+
|
|
742
|
+
| Event | When it fires | Payload |
|
|
743
|
+
|---|---|---|
|
|
744
|
+
| `client:init` | after the client script's `setup(ctx)` has finished | `{ name }` |
|
|
745
|
+
| `event:*` | live scene events (same source as the browser WS, via the event bridge) | the event's own payload |
|
|
746
|
+
| `page:change` | route change finished (`page:finish`) | `{ path }` |
|
|
747
|
+
| `i18n:changed` | UI language switched | `{ locale }` |
|
|
748
|
+
| `client:destroy` | just before `ctx.dispose()` collects things | `{ name }` |
|
|
749
|
+
|
|
750
|
+
### 5.3 Subscription cheat sheet
|
|
751
|
+
|
|
752
|
+
| What you want | Server plugin | Browser plugin |
|
|
753
|
+
|---|---|---|
|
|
754
|
+
| A named lifecycle hook (`daq:sample` / `dcw:write` / `line:start` …) | `ctx.hooks.on('daq:sample', fn)` | not delivered (server hooks never reach the browser) |
|
|
755
|
+
| A scene event (e.g. `daq.reading`, `device.created`) | `ctx.events.on('daq.reading', fn)` | `ctx.on('daq.reading', fn)` |
|
|
756
|
+
| Every scene event | `ctx.hooks.on('*', ({ type, payload }) => …)` | `ctx.on('event:*', fn)` |
|
|
757
|
+
| A client-local hook (`client:init` / `page:change` / `i18n:changed` / `client:destroy`) | n/a | `ctx.hooks.on('page:change', fn)` |
|
|
758
|
+
|
|
759
|
+
The two easiest mistakes:
|
|
760
|
+
|
|
761
|
+
- The server wildcard is the bare `'*'` only: `ctx.hooks.on('event:*', fn)` **never fires**;
|
|
762
|
+
- The client wildcard is the literal `'event:*'` only: `ctx.on('*', fn)` **never fires**, and
|
|
763
|
+
`ctx.on('event:line.start', fn)` gets the prefix added twice (`event:event:line.start`) and
|
|
764
|
+
likewise never fires.
|
|
765
|
+
|
|
766
|
+
Scene events enter the bus as `event:<type>`, and `ctx.events.on('<type>', fn)` is the sugar that
|
|
767
|
+
adds the prefix. So the correct subscription for the scene event `permissions.changed` is
|
|
768
|
+
`ctx.events.on('permissions.changed', fn)`, while `ctx.hooks.on('permissions:changed', fn)`
|
|
769
|
+
never fires.
|
|
770
|
+
|
|
771
|
+
### 5.4 Shutdown and hot-reload sequences
|
|
772
|
+
|
|
773
|
+
```text
|
|
774
|
+
server shutdown (nitro close → shutdownPluginHost)
|
|
775
|
+
└─ per-plugin ctx.onDispose queue (each entry try/catch)
|
|
776
|
+
└─ broadcast server:close { at }
|
|
777
|
+
|
|
778
|
+
plugin hot reload (plugins-state.json changed / plugin enabled-disabled / 10 s poll fallback)
|
|
779
|
+
└─ per-plugin ctx.onDispose queue
|
|
780
|
+
└─ unbind every listener registered through ctx.hooks
|
|
781
|
+
└─ reload → broadcast plugins:reloaded
|
|
782
|
+
└─ broadcast the scene event plugins.reloaded (the browser loader hot-injects / unloads client plugins from it)
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
> v1 hooks are **observation-only** — they never change interlocking or write-control decisions;
|
|
786
|
+
> veto (interception / rewriting) hooks are on the roadmap.
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
## 6. Browser-side SDK (`agentworkshop/sdk/client`)
|
|
791
|
+
|
|
792
|
+
A plugin's `client.mjs` is a **self-contained ESM** module (no bare imports — the browser resolves
|
|
793
|
+
it natively) exporting `setup(ctx)`. The entry must be declared in the plugin definition as
|
|
794
|
+
`client: './client.mjs'`; the loader fetches the script from
|
|
795
|
+
`GET /api/plugins/client/<plugin name>` and imports it dynamically.
|
|
796
|
+
|
|
797
|
+
### 6.1 Creation (host-invoked; plugins only write `setup`)
|
|
798
|
+
|
|
799
|
+
```js
|
|
800
|
+
import { createClientContext } from 'agentworkshop/sdk/client'
|
|
801
|
+
|
|
802
|
+
// host-side assembly (illustrative); a plugin author only writes setup(ctx) in client.mjs
|
|
803
|
+
const listeners = new Set()
|
|
804
|
+
const townBus = {
|
|
805
|
+
subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn) },
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
const ctx = createClientContext({
|
|
809
|
+
name: 'my-plugin',
|
|
810
|
+
// event bridge: the host feeds every WS bus message into dispatch
|
|
811
|
+
eventBridge: dispatch => townBus.subscribe(e => dispatch(e.type, e.payload)),
|
|
812
|
+
baseUrl: '', // same-origin; fill in the platform address for cross-origin integration
|
|
813
|
+
ui: { slots: ['plugins.page'], registerPanel: () => () => {} },
|
|
814
|
+
t: key => `plugin.my-plugin.${key}`, // the host passes a real translation helper
|
|
815
|
+
getLocale: () => 'zh-CN',
|
|
816
|
+
})
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### 6.2 `ctx` members
|
|
820
|
+
|
|
821
|
+
| Member | Notes |
|
|
822
|
+
|---|---|
|
|
823
|
+
| `ctx.name` | plugin name |
|
|
824
|
+
| `ctx.sdkVersion` | `CLIENT_SDK_VERSION` |
|
|
825
|
+
| `ctx.hooks` | the client-local `HookBus`; both local hooks and scene events ride this bus |
|
|
826
|
+
| `ctx.on(type, fn)` | subscribe to **live scene events**; `type` is the **scene event name itself** (e.g. `'daq.reading'` / `'daq.alarm'` / `'daq.alarm.changed'` / `'dcw.written'` / `'daq.node.changed'` / `'device.updated'`), installed as `event:<type>` internally; returns an unsubscribe function and is **auto-collected on pagehide**. The only wildcard spelling is the literal **`'event:*'`** |
|
|
827
|
+
| `ctx.fetch(path, opt?)` | same-origin platform API: automatic JSON, automatic `{data}` unwrapping, throws on non-2xx, and **automatically carries the platform token from the cookie** |
|
|
828
|
+
| `ctx.el(tag, attrs, children)` | DOM builder: `style` / `class` / `on*` event attributes get special handling |
|
|
829
|
+
| `ctx.mount(target, node)` | mount into any selector / element; falls back to `ctx.root()` when the target is missing |
|
|
830
|
+
| `ctx.root()` | the plugin's private mount point `#aw-plugin-<name>` (bottom-right, lazily created) |
|
|
831
|
+
| `ctx.ui` | UI injection surface: `slots` and `registerPanel(entry)` (§6.4) |
|
|
832
|
+
| `ctx.t(key, params?)` | plugin namespace translation: `ctx.t('panel.title')` → `plugin.<name>.panel.title` (messages come from `i18n.json` in the plugin root; a miss falls back to the original key). **`params` is currently ignored — there is no interpolation** |
|
|
833
|
+
| `ctx.locale` | the current UI language (read-only getter) |
|
|
834
|
+
| `ctx.log` | prefixed console: `info` / `warn` / `error` (**no `debug`**) |
|
|
835
|
+
| `ctx.dispose()` | unload: broadcast `client:destroy` → run local disposables → remove `root()`. **Idempotent**; it does not unregister panels (the loader does that on disable / hot reload) |
|
|
836
|
+
|
|
837
|
+
Two wrong spellings of `ctx.on`: `ctx.on('*')` and `ctx.on('event:line.start')` both
|
|
838
|
+
**never fire** — the former is not installed on the bare `'*'`, the latter gets a second prefix
|
|
839
|
+
and becomes `event:event:line.start`.
|
|
840
|
+
|
|
841
|
+
**Server hooks never reach the browser**: colon-named server hooks such as `daq:sample`,
|
|
842
|
+
`dcw:write`, `line:start` / `line:stop` are not delivered to the client. Their browser-side
|
|
843
|
+
counterparts are scene events (`daq.reading` / `daq.frame` / `dcw.written` and so on); subscribe
|
|
844
|
+
to those with `ctx.on('<scene-type>')`.
|
|
845
|
+
|
|
846
|
+
**Client lifecycle hooks cannot go through `ctx.on` either**: `client:init` / `page:change` /
|
|
847
|
+
`i18n:changed` / `client:destroy` must be subscribed directly with `ctx.hooks.on(...)` (they carry
|
|
848
|
+
no `event:` prefix).
|
|
849
|
+
|
|
850
|
+
### 6.3 Full example
|
|
851
|
+
|
|
852
|
+
```js
|
|
853
|
+
export function setup(ctx) {
|
|
854
|
+
const badge = ctx.el('div', {
|
|
855
|
+
style: 'padding:8px 12px;border:1px solid #35e0a0;border-radius:10px;color:#35e0a0',
|
|
856
|
+
}, ['samples: 0'])
|
|
857
|
+
ctx.root().append(badge)
|
|
858
|
+
|
|
859
|
+
let n = 0
|
|
860
|
+
ctx.on('daq.reading', () => { badge.textContent = `samples: ${++n}` }) // scene event
|
|
861
|
+
ctx.on('event:*', (payload) => ctx.log.info('scene event', payload)) // the only wildcard spelling
|
|
862
|
+
|
|
863
|
+
ctx.hooks.on('page:change', ({ path }) => ctx.log.info('page →', path)) // local hook: subscribe directly
|
|
864
|
+
|
|
865
|
+
// Consume the platform API (same-origin, cookie auth): the line list is { lines, states }, not an array
|
|
866
|
+
ctx.fetch('/api/workshop/dcw/lines').then(({ lines }) => ctx.log.info('lines', lines.length))
|
|
867
|
+
}
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
### 6.4 UI injection `ctx.ui.registerPanel`
|
|
871
|
+
|
|
872
|
+
```js
|
|
873
|
+
let samples = 0
|
|
874
|
+
ctx.on('daq.reading', () => { samples += 1 })
|
|
875
|
+
|
|
876
|
+
const off = ctx.ui.registerPanel({
|
|
877
|
+
slot: 'dashboard.widgets', // 'plugins.page' | 'settings.plugins' | 'dashboard.widgets'
|
|
878
|
+
name: 'my-widget',
|
|
879
|
+
title: 'Sample counter',
|
|
880
|
+
titleKey: 'plugin.my-plugin.widget.title', // titleKey wins when present
|
|
881
|
+
order: 100, // smaller comes first; default 100
|
|
882
|
+
mount(el) {
|
|
883
|
+
el.textContent = `samples: ${samples}`
|
|
884
|
+
const tick = setInterval(() => { el.textContent = `samples: ${samples}` }, 1000)
|
|
885
|
+
return () => clearInterval(tick) // called when the panel is unmounted
|
|
886
|
+
},
|
|
887
|
+
})
|
|
888
|
+
off() // the returned unregister function; ctx.dispose() does not call it, the loader collects it on disable
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
- `ctx.ui.slots` is exactly `['plugins.page', 'settings.plugins', 'dashboard.widgets']`.
|
|
892
|
+
- `registerPanel` returns an unregister function; if `mount(el)` returns a function it is called
|
|
893
|
+
when that panel is unmounted.
|
|
894
|
+
|
|
895
|
+
### 6.5 Constraints and trust
|
|
896
|
+
|
|
897
|
+
- **Self-contained**: no bare imports of `vue` or other third-party packages (the browser's native
|
|
898
|
+
import cannot resolve them) — build UI with native DOM (`ctx.el`);
|
|
899
|
+
- **Trust model**: client scripts are served by platform endpoints, trusted at the same level as
|
|
900
|
+
aw commands — only install plugins you trust;
|
|
901
|
+
- **Isolation**: a single plugin failing to load only logs a console warning; the app and other
|
|
902
|
+
plugins are unaffected.
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 7. Types and TypeScript
|
|
907
|
+
|
|
908
|
+
```ts
|
|
909
|
+
import type { PluginDef, PluginContext, PlatformClient } from 'agentworkshop/sdk'
|
|
910
|
+
|
|
911
|
+
export default {
|
|
912
|
+
name: 'typed-plugin',
|
|
913
|
+
auth: 'user',
|
|
914
|
+
async setup(ctx: PluginContext) {
|
|
915
|
+
const timeout: number = ctx.config.get('plugins.typed-plugin.timeout')
|
|
916
|
+
const client: PlatformClient = ctx.api
|
|
917
|
+
ctx.logger.info('api available:', typeof client.get === 'function', 'timeout:', timeout)
|
|
918
|
+
},
|
|
919
|
+
} satisfies PluginDef
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
The runtime **does not import** the SDK (keeping the zero-dependency shape); types are erased at
|
|
923
|
+
build time.
|
|
924
|
+
|
|
925
|
+
Current coverage of the type declarations (always defer to `sdk/index.d.mts` and
|
|
926
|
+
`sdk/client.d.mts`):
|
|
927
|
+
|
|
928
|
+
- Declared: `PluginDef`, `PluginContext`, `PluginHostExtensions`, `PluginSettingDecl`,
|
|
929
|
+
`PluginGroupDecl`, `PluginLogger`, `PluginKv`, `PluginHttp`, `CrudResource`, `PlatformClient`,
|
|
930
|
+
`ConfigChangedPayload`, `HookBus`, `ClientContext`, `ClientUi`, `ClientPanelEntry`,
|
|
931
|
+
`LIFECYCLE_EVENTS`, `CLIENT_EVENTS` and the factory functions.
|
|
932
|
+
- **Not yet declared**: `isPathInside`, `validatePluginSettings`, `validatePluginGroups` and
|
|
933
|
+
`resolvePluginGroupId` are runtime-only exports with no declaration in `.d.mts` — a TypeScript
|
|
934
|
+
project importing them gets TS2614 and needs a local declaration or `await import()`.
|
|
935
|
+
- In addition, `sdk/client.d.mts` declares an `el` named export that does not exist at runtime
|
|
936
|
+
(the runtime has only `CLIENT_SDK_VERSION` and `createClientContext`); importing it compiles
|
|
937
|
+
but yields `undefined` at runtime.
|
|
938
|
+
|
|
939
|
+
---
|
|
940
|
+
|
|
941
|
+
## 8. Versioning and compatibility policy
|
|
942
|
+
|
|
943
|
+
- The SDK interface follows semver: patch = fixes; minor = new hooks / `ctx` members
|
|
944
|
+
(backwards compatible); major = breaking contract changes. `SDK_VERSION` /
|
|
945
|
+
`CLIENT_SDK_VERSION` are the versions on that line and are **independent of the npm package
|
|
946
|
+
version** — never infer one from the other.
|
|
947
|
+
- The host exposes `ctx.sdkVersion` so a plugin can degrade gracefully by feature.
|
|
948
|
+
- Config-root hardening does not live in the single `aw start` command but in the **CLI context
|
|
949
|
+
builder** — every `aw` command calls it while resolving the run root (idempotently), so no
|
|
950
|
+
command fails just because a config-root directory is missing.
|
|
951
|
+
- There is **no version-based directory-layout migration**: the only migration copies data files
|
|
952
|
+
from the legacy locations into the config root, that is `cwd/data` (and the historical
|
|
953
|
+
`cwd/server/data`) → `<configRoot>/data`, only for `.sqlite` / `.sqlite-wal` / `.sqlite-shm` /
|
|
954
|
+
`.json`, with "newest wins" by `mtimeMs` on a name clash; when the config root falls back to
|
|
955
|
+
`~/.AgentWorkShop` that migration is skipped to avoid cross-project pollution.
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
959
|
+
## Appendix: scope of this page
|
|
960
|
+
|
|
961
|
+
This page is the single source of truth for the SDK; it follows the actual implementation in
|
|
962
|
+
`sdk/*.mjs`, `sdk/*.d.mts`, `server/services/workshop/plugins/host.mjs` and `server/api/**`.
|
|
963
|
+
CI copies this file to the site at `docs/site/en/sdk/guide.md`, and the Chinese original
|
|
964
|
+
`docs/sdk.md` to `docs/site/sdk/guide.md`.
|