agentworkshop 0.7.39 → 0.7.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +55 -0
  2. package/.output/.AgentWorkShop/prompts/host-tools.json +55 -0
  3. package/.output/nitro.json +1 -1
  4. package/.output/public/_nuxt/88GOowgO2.js +1 -0
  5. package/.output/public/_nuxt/{BNT8gYU92.js → BC9wjTJK2.js} +2 -2
  6. package/.output/public/_nuxt/BOt2SP4z.js +1 -0
  7. package/.output/public/_nuxt/BP-NyKVG.js +18 -0
  8. package/.output/public/_nuxt/{HBLJ-wei.js → BXxH0UQE.js} +1 -1
  9. package/.output/public/_nuxt/{zIGh7R49.js → BneN7fbu.js} +1 -1
  10. package/.output/public/_nuxt/BsROmY89.js +1 -0
  11. package/.output/public/_nuxt/{C_OLzD09.js → C4oW1HsE.js} +1 -1
  12. package/.output/public/_nuxt/CFxtLwjp.js +1 -0
  13. package/.output/public/_nuxt/{Cec0Ua3F.js → CS50LB_l.js} +1 -1
  14. package/.output/public/_nuxt/C_iYD-EB.js +1 -0
  15. package/.output/public/_nuxt/{DAe0h2MB.js → ClILjvWH.js} +1 -1
  16. package/.output/public/_nuxt/CssgYAAL2.js +1 -0
  17. package/.output/public/_nuxt/{CY9LbPCI.js → CzOCSGLe.js} +1 -1
  18. package/.output/public/_nuxt/D8qvkfyY.js +1 -0
  19. package/.output/public/_nuxt/DCn7QZ5N.js +2 -0
  20. package/.output/public/_nuxt/DGIuvyRN2.js +1 -0
  21. package/.output/public/_nuxt/{CojCTLKD.js → DGj-WEBg.js} +1 -1
  22. package/.output/public/_nuxt/{DDShH71m.js → DS8qj8EL.js} +1 -1
  23. package/.output/public/_nuxt/DTFCy6h-.js +1 -0
  24. package/.output/public/_nuxt/{DrYV5i68.js → DUjW5Yq5.js} +1 -1
  25. package/.output/public/_nuxt/DZshyNLa.js +1 -0
  26. package/.output/public/_nuxt/{45zuyAso.js → D_OTvQza.js} +1 -1
  27. package/.output/public/_nuxt/DcsCcxp4.js +1 -0
  28. package/.output/public/_nuxt/{DUrecWPx.js → Dihnimlk.js} +2 -2
  29. package/.output/public/_nuxt/Dqw1lpr-.js +1 -0
  30. package/.output/public/_nuxt/{CUDwzgLV.js → Dr9v6C0f.js} +9 -9
  31. package/.output/public/_nuxt/{8NMOXZOV.js → Du9ZJtnj.js} +1 -1
  32. package/.output/public/_nuxt/TownView.f-YOdXRs.css +1 -0
  33. package/.output/public/_nuxt/_id_.CM4bIgKY.css +1 -0
  34. package/.output/public/_nuxt/_id_.bNV69Dtf.css +1 -0
  35. package/.output/public/_nuxt/_wsId_.B4WiqkIS.css +1 -0
  36. package/.output/public/_nuxt/agents.ZD0rVdHE.css +1 -0
  37. package/.output/public/_nuxt/aml.BN8ZEW4h.css +1 -0
  38. package/.output/public/_nuxt/builds/latest.json +1 -1
  39. package/.output/public/_nuxt/builds/meta/f4707884-7cf4-4a31-80d2-e3d72b73745f.json +1 -0
  40. package/.output/public/_nuxt/channel-templates.BOtahzPi.css +1 -0
  41. package/.output/public/_nuxt/daq.B0D3dPAc.css +1 -0
  42. package/.output/public/_nuxt/dcw.8Y7FqCVN.css +1 -0
  43. package/.output/public/_nuxt/default.J32SgqFY.css +1 -0
  44. package/.output/public/_nuxt/entry.bdm0tv6M.css +1 -0
  45. package/.output/public/_nuxt/logs.BpKzmKsh.css +1 -0
  46. package/.output/public/_nuxt/monitor.D9pe7qN6.css +1 -0
  47. package/.output/public/_nuxt/pages.D7aSDlUI.css +1 -0
  48. package/.output/public/_nuxt/permissions.DwTVlFe6.css +1 -0
  49. package/.output/public/_nuxt/plugins.sb4nDGqr.css +1 -0
  50. package/.output/public/_nuxt/{Cbq-mryP.js → qr6R6Ha1.js} +1 -1
  51. package/.output/public/_nuxt/settings.BTgR-NiE.css +1 -0
  52. package/.output/public/_nuxt/teams.CxnxKVVs.css +1 -0
  53. package/.output/public/_nuxt/tokens.BFY7qv4f.css +1 -0
  54. package/.output/public/_nuxt/{town.DKIAhKnx.css → town.BBXZmeoP.css} +1 -1
  55. package/.output/public/_nuxt/users.DLgZ1D0h.css +1 -0
  56. package/.output/public/_nuxt/workshop.CR_QzeAN.css +1 -0
  57. package/.output/public/_nuxt/{BzHEilTt.js → xh3_vYcu.js} +1 -1
  58. package/.output/public/_nuxt/yF0aYMF1.js +4 -0
  59. package/.output/server/chunks/_/entity.mjs.map +1 -1
  60. package/.output/server/chunks/_/nitro.mjs +2225 -1445
  61. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  62. package/.output/server/chunks/build/{TownView-jVazYOjN.mjs → TownView-BuLAsmpR.mjs} +288 -206
  63. package/.output/server/chunks/build/TownView-BuLAsmpR.mjs.map +1 -0
  64. package/.output/server/chunks/build/{_id_-CfVosNg3.mjs → _id_-BU1wfOID.mjs} +138 -138
  65. package/.output/server/chunks/build/{_id_-CfVosNg3.mjs.map → _id_-BU1wfOID.mjs.map} +1 -1
  66. package/.output/server/chunks/build/{_id_-Hwr4rZpr.mjs → _id_-BYsEua57.mjs} +33 -32
  67. package/.output/server/chunks/build/_id_-BYsEua57.mjs.map +1 -0
  68. package/.output/server/chunks/build/{_wsId_-BVg3bB77.mjs → _wsId_-BxlDcJHg.mjs} +293 -259
  69. package/.output/server/chunks/build/{_wsId_-BVg3bB77.mjs.map → _wsId_-BxlDcJHg.mjs.map} +1 -1
  70. package/.output/server/chunks/build/{agents-Bvin73QY.mjs → agents-CLQqJF2y.mjs} +21 -27
  71. package/.output/server/chunks/build/agents-CLQqJF2y.mjs.map +1 -0
  72. package/.output/server/chunks/build/{aml-BCSJCdX7.mjs → aml-_7FdFL2p.mjs} +109 -109
  73. package/.output/server/chunks/build/{aml-BCSJCdX7.mjs.map → aml-_7FdFL2p.mjs.map} +1 -1
  74. package/.output/server/chunks/build/api-error-dul30BYQ.mjs.map +1 -1
  75. package/.output/server/chunks/build/{channel-templates-BTq8570n.mjs → channel-templates-p6SZNjlM.mjs} +19 -19
  76. package/.output/server/chunks/build/{channel-templates-BTq8570n.mjs.map → channel-templates-p6SZNjlM.mjs.map} +1 -1
  77. package/.output/server/chunks/build/{daq-C03Uu5UE.mjs → daq-cgyjKmJu.mjs} +188 -122
  78. package/.output/server/chunks/build/daq-cgyjKmJu.mjs.map +1 -0
  79. package/.output/server/chunks/build/{dcw-6vEYVeje.mjs → dcw-CoTxBlAZ.mjs} +45 -45
  80. package/.output/server/chunks/build/{dcw-6vEYVeje.mjs.map → dcw-CoTxBlAZ.mjs.map} +1 -1
  81. package/.output/server/chunks/build/{default-CZmZFpqH.mjs → default-BE4r0FZN.mjs} +152 -58
  82. package/.output/server/chunks/build/{default-CZmZFpqH.mjs.map → default-BE4r0FZN.mjs.map} +1 -1
  83. package/.output/server/chunks/build/{logs-B-xhuqln.mjs → logs-BSOeZwwI.mjs} +34 -34
  84. package/.output/server/chunks/build/{logs-B-xhuqln.mjs.map → logs-BSOeZwwI.mjs.map} +1 -1
  85. package/.output/server/chunks/build/{monitor-CyfDt4nR.mjs → monitor-C0okQaXz.mjs} +33 -33
  86. package/.output/server/chunks/build/{monitor-CyfDt4nR.mjs.map → monitor-C0okQaXz.mjs.map} +1 -1
  87. package/.output/server/chunks/build/{pages-BO7yZsXA.mjs → pages-DFxjn9Xa.mjs} +33 -17
  88. package/.output/server/chunks/build/pages-DFxjn9Xa.mjs.map +1 -0
  89. package/.output/server/chunks/build/{permissions-B52oOmaO.mjs → permissions-68SsNjex.mjs} +12 -12
  90. package/.output/server/chunks/build/{permissions-B52oOmaO.mjs.map → permissions-68SsNjex.mjs.map} +1 -1
  91. package/.output/server/chunks/build/{plugins-CUWmMdyt.mjs → plugins-lGlUr1lj.mjs} +17 -17
  92. package/.output/server/chunks/build/{plugins-CUWmMdyt.mjs.map → plugins-lGlUr1lj.mjs.map} +1 -1
  93. package/.output/server/chunks/build/{settings-DoQ2Oq3P.mjs → settings-Ddd1qx2Z.mjs} +50 -47
  94. package/.output/server/chunks/build/settings-Ddd1qx2Z.mjs.map +1 -0
  95. package/.output/server/chunks/build/{teams-2kz3CusY.mjs → teams-MEDLZdMn.mjs} +38 -34
  96. package/.output/server/chunks/build/teams-MEDLZdMn.mjs.map +1 -0
  97. package/.output/server/chunks/build/{tokens-BbWLqtVz.mjs → tokens-C7fTM5C2.mjs} +14 -14
  98. package/.output/server/chunks/build/{tokens-BbWLqtVz.mjs.map → tokens-C7fTM5C2.mjs.map} +1 -1
  99. package/.output/server/chunks/build/{town-BOl6hs9B.mjs → town-qMPql9Se.mjs} +36 -10
  100. package/.output/server/chunks/build/town-qMPql9Se.mjs.map +1 -0
  101. package/.output/server/chunks/build/useDaqStream-CIBaiGAl.mjs +1 -1
  102. package/.output/server/chunks/build/useDcwStream-CBbiYnWe.mjs +1 -1
  103. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs +49 -0
  104. package/.output/server/chunks/build/useResponsive-BKDMGTHs.mjs.map +1 -0
  105. package/.output/server/chunks/build/{users-fohSmF-J.mjs → users-Cfd5-l2-.mjs} +6 -6
  106. package/.output/server/chunks/build/{users-fohSmF-J.mjs.map → users-Cfd5-l2-.mjs.map} +1 -1
  107. package/.output/server/chunks/build/{workshop-DX5-ldc4.mjs → workshop-BL5bhfs0.mjs} +15 -15
  108. package/.output/server/chunks/build/{workshop-DX5-ldc4.mjs.map → workshop-BL5bhfs0.mjs.map} +1 -1
  109. package/.output/server/chunks/build/{workspaces-BuydxM-3.mjs → workspaces-Bgz5Ekwp.mjs} +18 -3
  110. package/.output/server/chunks/build/workspaces-Bgz5Ekwp.mjs.map +1 -0
  111. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs.map +1 -1
  112. package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
  113. package/.output/server/chunks/routes/api/system/index.post.mjs.map +1 -1
  114. package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
  115. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +6 -2
  116. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
  117. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +2 -1
  118. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs.map +1 -1
  119. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  120. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +3 -3
  121. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
  122. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
  123. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
  124. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +3 -2
  125. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
  126. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -1
  127. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
  128. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +8 -6
  129. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
  130. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +5 -5
  131. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
  132. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +14 -4
  133. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
  134. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +4 -4
  135. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
  136. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +4 -3
  137. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
  138. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +31 -0
  139. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs.map +1 -0
  140. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +28 -0
  141. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs.map +1 -0
  142. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
  143. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +32 -0
  144. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs.map +1 -0
  145. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +34 -0
  146. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs.map +1 -0
  147. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +33 -0
  148. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs.map +1 -0
  149. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +34 -0
  150. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs.map +1 -0
  151. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  152. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  153. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  154. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  155. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  156. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  157. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  158. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +2 -0
  159. package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
  160. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +3 -1
  161. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  162. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  163. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  164. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  165. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  166. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  167. package/.output/server/chunks/routes/renderer.mjs +3 -3
  168. package/.output/server/chunks/virtual/entry.mjs +51 -25
  169. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  170. package/.output/server/package.json +1 -1
  171. package/README-zh.md +199 -35
  172. package/README.md +739 -591
  173. package/app/app.vue +9 -3
  174. package/app/assets/css/main.css +517 -7
  175. package/app/components/AppHeader.vue +98 -7
  176. package/app/components/AppSidebar.vue +117 -11
  177. package/app/components/AwChart.vue +2 -1
  178. package/app/components/workshop/AgentInspectorDrawer.vue +6 -6
  179. package/app/components/workshop/AgentLanesView.vue +52 -1
  180. package/app/components/workshop/AssetLibrary.vue +4 -2
  181. package/app/components/workshop/ChannelSessionList.vue +4 -2
  182. package/app/components/workshop/Composer.vue +96 -0
  183. package/app/components/workshop/DaqNodeRow.vue +19 -0
  184. package/app/components/workshop/DaqTemplateIcon.vue +33 -0
  185. package/app/components/workshop/DeviceTwinPanel.vue +37 -35
  186. package/app/components/workshop/EventBlock.vue +3 -3
  187. package/app/components/workshop/InspectorPanel.vue +47 -11
  188. package/app/components/workshop/LiveAgentBar.vue +34 -0
  189. package/app/components/workshop/TaskBoardView.vue +83 -33
  190. package/app/components/workshop/TranscriptTimeline.vue +56 -0
  191. package/app/components/workshop/blocks/ClusterError.vue +1 -1
  192. package/app/components/workshop/blocks/ClusterRoute.vue +3 -1
  193. package/app/components/workshop/blocks/ClusterStatus.vue +2 -2
  194. package/app/components/workshop/blocks/ClusterStream.vue +8 -2
  195. package/app/components/workshop/town/ModelPreview3D.vue +1 -1
  196. package/app/components/workshop/town/TownView.vue +507 -82
  197. package/app/composables/useResponsive.ts +88 -0
  198. package/app/composables/useRouteMeta.ts +3 -0
  199. package/app/composables/workshop/useDcwStream.ts +1 -1
  200. package/app/composables/workshop/useVisibleInterval.ts +2 -2
  201. package/app/composables/workshop/useWorkshopApi.ts +1 -1
  202. package/app/layouts/default.vue +46 -2
  203. package/app/pages/aml/index.vue +712 -616
  204. package/app/pages/daq/[id].vue +3 -2
  205. package/app/pages/daq/index.vue +209 -9
  206. package/app/pages/dcw/[id].vue +109 -28
  207. package/app/pages/dcw/index.vue +83 -23
  208. package/app/pages/index.vue +35 -1
  209. package/app/pages/logs/index.vue +147 -13
  210. package/app/pages/monitor.vue +56 -12
  211. package/app/pages/permissions/index.vue +34 -0
  212. package/app/pages/plugins/index.vue +35 -4
  213. package/app/pages/settings.vue +90 -21
  214. package/app/pages/tokens.vue +23 -0
  215. package/app/pages/town.vue +50 -5
  216. package/app/pages/users.vue +23 -0
  217. package/app/pages/workshop/agents.vue +92 -2
  218. package/app/pages/workshop/channel-templates.vue +53 -0
  219. package/app/pages/workshop/index.vue +14 -0
  220. package/app/pages/workshop/teams.vue +66 -6
  221. package/app/pages/workshop/w/[wsId].vue +202 -14
  222. package/app/plugins/aw-plugins.client.ts +13 -8
  223. package/app/stores/app.ts +33 -1
  224. package/app/stores/workshop/user.ts +1 -1
  225. package/app/stores/workshop/workspaces.ts +18 -2
  226. package/app/utils/api-error.ts +1 -1
  227. package/cli/commands/build.mjs +8 -1
  228. package/docker-compose.yml +6 -0
  229. package/i18n/locales/en.ts +2 -0
  230. package/i18n/locales/zh-CN.ts +2 -0
  231. package/nuxt.config.ts +31 -0
  232. package/package.json +9 -1
  233. package/scripts/_dbg-param-map-e2e.ts +242 -0
  234. package/scripts/_dbg-param-map-rest-smoke.mjs +73 -0
  235. package/scripts/_dbg-param-real-scenario.mjs +153 -0
  236. package/scripts/api-live-e2e.mjs +40 -8
  237. package/scripts/capture-walkthrough.mjs +232 -0
  238. package/scripts/render-walkthrough-figure.mjs +46 -0
  239. package/scripts/seed-walkthrough-fixture.mjs +143 -0
  240. package/scripts/test-plugin-hardening.mjs +8 -0
  241. package/scripts/ui/admin-shots.mjs +46 -0
  242. package/scripts/ui/audit-layout.mjs +301 -0
  243. package/scripts/ui/bump-microfont.mjs +39 -0
  244. package/scripts/ui/lib.mjs +198 -0
  245. package/scripts/ui/linkcheck2.mjs +37 -0
  246. package/scripts/ui/live-render-check.mjs +72 -0
  247. package/scripts/ui/md-lint.mjs +80 -0
  248. package/scripts/ui/perf-audit.mjs +132 -0
  249. package/scripts/ui/readme-assets.mjs +30 -0
  250. package/scripts/ui/readme-shots.mjs +42 -0
  251. package/scripts/ui/record.mjs +225 -0
  252. package/scripts/ui/seed-admin.mjs +68 -0
  253. package/scripts/ui/seed-demo.mjs +83 -0
  254. package/scripts/ui/shot-hero.mjs +25 -0
  255. package/scripts/ui/shots.mjs +75 -0
  256. package/scripts/ui/sim-ui-shot.mjs +16 -0
  257. package/scripts/ui/verify-nav.mjs +51 -0
  258. package/scripts/ui/verify-responsive.mjs +285 -0
  259. package/server/api/system/config-groups/[id].patch.ts +1 -1
  260. package/server/api/system/config-groups/index.post.ts +1 -1
  261. package/server/api/system/settings/events.get.ts +1 -1
  262. package/server/api/system/settings/index.patch.ts +1 -1
  263. package/server/api/workshop/agent-tools/invoke.post.ts +16 -2
  264. package/server/api/workshop/aml/datasets/[id].get.ts +8 -1
  265. package/server/api/workshop/daq/infra/reconnect.post.ts +1 -1
  266. package/server/api/workshop/daq/templates/[key].delete.ts +1 -0
  267. package/server/api/workshop/daq/templates/[key].patch.ts +1 -0
  268. package/server/api/workshop/daq/templates/index.post.ts +1 -0
  269. package/server/api/workshop/dcw/[id]/write.post.ts +10 -2
  270. package/server/api/workshop/dcw/[id].delete.ts +5 -2
  271. package/server/api/workshop/dcw/index.get.ts +2 -0
  272. package/server/api/workshop/dcw/lines/[id].patch.ts +1 -1
  273. package/server/api/workshop/dcw/params/[id]/read.post.ts +17 -0
  274. package/server/api/workshop/dcw/params/[id]/write.post.ts +21 -0
  275. package/server/api/workshop/dcw/params/[id].delete.ts +19 -0
  276. package/server/api/workshop/dcw/params/[id].patch.ts +23 -0
  277. package/server/api/workshop/dcw/params/index.get.ts +27 -0
  278. package/server/api/workshop/dcw/params/index.post.ts +25 -0
  279. package/server/api/workshop/permissions/index.get.ts +3 -1
  280. package/server/plugins/aw-plugins.ts +14 -3
  281. package/server/plugins/dev-stability-guard.ts +3 -1
  282. package/server/plugins/system-config.ts +6 -1
  283. package/server/services/system-config.ts +28 -9
  284. package/server/services/workshop/agents/adapters/one-shot-cli-agent.ts +2 -1
  285. package/server/services/workshop/agents/agent-interface.ts +8 -6
  286. package/server/services/workshop/agents/base-agent.ts +18 -4
  287. package/server/services/workshop/agents/claude-agent.ts +7 -3
  288. package/server/services/workshop/agents/codex-agent.ts +3 -3
  289. package/server/services/workshop/agents/dsh-agent.ts +3 -3
  290. package/server/services/workshop/agents/goose-agent.ts +0 -1
  291. package/server/services/workshop/agents/harness-terminal.ts +14 -1
  292. package/server/services/workshop/agents/hermes-agent.ts +4 -2
  293. package/server/services/workshop/agents/host-tool-bridge.ts +5 -1
  294. package/server/services/workshop/agents/industrial-context.ts +4 -1
  295. package/server/services/workshop/agents/industrial-tools.ts +164 -6
  296. package/server/services/workshop/agents/omp-agent.ts +15 -9
  297. package/server/services/workshop/agents/opencode-agent.ts +47 -21
  298. package/server/services/workshop/agents/qwen-agent.ts +10 -5
  299. package/server/services/workshop/aml/entity.ts +3 -1
  300. package/server/services/workshop/aml/python-runtime.ts +3 -2
  301. package/server/services/workshop/daq/bus/mqtt.adapter.ts +8 -4
  302. package/server/services/workshop/daq/daq-controller.ts +18 -3
  303. package/server/services/workshop/daq/daq-runtime.ts +5 -3
  304. package/server/services/workshop/daq/drivers.ts +63 -8
  305. package/server/services/workshop/daq/host-ports.ts +3 -2
  306. package/server/services/workshop/daq/storage/timescale.adapter.ts +3 -1
  307. package/server/services/workshop/db/channel.repo.ts +4 -0
  308. package/server/services/workshop/db/ops.repo.ts +5 -2
  309. package/server/services/workshop/db/retention.ts +8 -3
  310. package/server/services/workshop/dcw/dcw-controller.ts +143 -16
  311. package/server/services/workshop/dcw/dcw-product.repo.ts +38 -1
  312. package/server/services/workshop/dcw/dcw-runtime.ts +3 -2
  313. package/server/services/workshop/dcw/drivers.ts +5 -2
  314. package/server/services/workshop/dcw/param-conversion.ts +78 -0
  315. package/server/services/workshop/dcw/param-limits.ts +142 -0
  316. package/server/services/workshop/dcw/param-map.repo.ts +305 -0
  317. package/server/services/workshop/dcw/recipe-rollback-manager.ts +13 -7
  318. package/server/services/workshop/runtime/agent-runtime.ts +4 -0
  319. package/server/services/workshop/runtime/manager.ts +9 -2
  320. package/server/services/workshop/settings.ts +4 -2
  321. package/server/types/pg.d.ts +49 -0
  322. package/server/utils/stability-severity.ts +13 -2
  323. package/shared/config/groups.mjs +22 -1
  324. package/shared/config/home.d.mts +28 -0
  325. package/shared/dcw-protocol.ts +136 -0
  326. package/uno.config.ts +12 -1
  327. package/.output/public/_nuxt/BFkgkW8u.js +0 -4
  328. package/.output/public/_nuxt/C5gUkRwn.js +0 -1
  329. package/.output/public/_nuxt/CM12FuB42.js +0 -1
  330. package/.output/public/_nuxt/CZiw7sEV.js +0 -1
  331. package/.output/public/_nuxt/Cc_9VzD42.js +0 -1
  332. package/.output/public/_nuxt/CdPzkOMV.js +0 -1
  333. package/.output/public/_nuxt/CmsOtOAA2.js +0 -1
  334. package/.output/public/_nuxt/D1YDxZpZ.js +0 -1
  335. package/.output/public/_nuxt/D20Yamr4.js +0 -1
  336. package/.output/public/_nuxt/DmqknNvV.js +0 -18
  337. package/.output/public/_nuxt/DnUuIR83.js +0 -1
  338. package/.output/public/_nuxt/S_fVQwJK.js +0 -1
  339. package/.output/public/_nuxt/TownView.0oLiQgTC.css +0 -1
  340. package/.output/public/_nuxt/_id_.D-SYuyZb.css +0 -1
  341. package/.output/public/_nuxt/_id_.hma_BU6T.css +0 -1
  342. package/.output/public/_nuxt/_wsId_.B12v3PhY.css +0 -1
  343. package/.output/public/_nuxt/agents.BV70ioCv.css +0 -1
  344. package/.output/public/_nuxt/ahgEJu2R.js +0 -1
  345. package/.output/public/_nuxt/aml.COEKNNqK.css +0 -1
  346. package/.output/public/_nuxt/builds/meta/4457d63f-0866-4cea-b320-04a321f24795.json +0 -1
  347. package/.output/public/_nuxt/channel-templates.C-M5nKcC.css +0 -1
  348. package/.output/public/_nuxt/daq.B3265ZDn.css +0 -1
  349. package/.output/public/_nuxt/dcw.DLYZqEhT.css +0 -1
  350. package/.output/public/_nuxt/default.BXI_fZUi.css +0 -1
  351. package/.output/public/_nuxt/entry.BB-Eeh-J.css +0 -1
  352. package/.output/public/_nuxt/logs.CqFyMrJw.css +0 -1
  353. package/.output/public/_nuxt/monitor.B--1dPzs.css +0 -1
  354. package/.output/public/_nuxt/pages.ooEzrMm9.css +0 -1
  355. package/.output/public/_nuxt/permissions.B1pjGChZ.css +0 -1
  356. package/.output/public/_nuxt/plugins.5e5chZ67.css +0 -1
  357. package/.output/public/_nuxt/pz2JDAM7.js +0 -2
  358. package/.output/public/_nuxt/settings.Dm3M0RLy.css +0 -1
  359. package/.output/public/_nuxt/teams.BC75EGnR.css +0 -1
  360. package/.output/public/_nuxt/tokens.xRb1fSPU.css +0 -1
  361. package/.output/public/_nuxt/users.CXnP2E08.css +0 -1
  362. package/.output/public/_nuxt/workshop.Jk5HxWPE.css +0 -1
  363. package/.output/server/chunks/build/TownView-jVazYOjN.mjs.map +0 -1
  364. package/.output/server/chunks/build/_id_-Hwr4rZpr.mjs.map +0 -1
  365. package/.output/server/chunks/build/agents-Bvin73QY.mjs.map +0 -1
  366. package/.output/server/chunks/build/daq-C03Uu5UE.mjs.map +0 -1
  367. package/.output/server/chunks/build/pages-BO7yZsXA.mjs.map +0 -1
  368. package/.output/server/chunks/build/settings-DoQ2Oq3P.mjs.map +0 -1
  369. package/.output/server/chunks/build/teams-2kz3CusY.mjs.map +0 -1
  370. package/.output/server/chunks/build/town-BOl6hs9B.mjs.map +0 -1
  371. package/.output/server/chunks/build/workspaces-BuydxM-3.mjs.map +0 -1
  372. /package/.output/public/_nuxt/{36oeS8_R2.js → 36oeS8_R.js} +0 -0
  373. /package/.output/public/_nuxt/{CYWVXZTS.js → CYWVXZTS2.js} +0 -0
@@ -60,9 +60,13 @@ const hitlAnswer = async (item: AepHitlItem, confirmed: boolean): Promise<void>
60
60
  }
61
61
  }
62
62
 
63
+ /* 语言选择器在窄屏显示"短名":完整语言名(简体中文=56px @14px)配上
64
+ * antd 给箭头预留的 24px 内距,92px 的选择器只剩 46px 文本位 ——
65
+ * 实测被截成「简 体…」,这是每页都出现的破相。
66
+ * 窄屏用 2 字标签,桌面保留完整语言名。 */
63
67
  const localeOptions = computed(() =>
64
68
  (locales.value as Array<{ code: string, name: string }>).map(l => ({
65
- label: l.name,
69
+ label: isMobile.value ? l.code.split('-')[0]!.toUpperCase() : l.name,
66
70
  value: l.code,
67
71
  })),
68
72
  )
@@ -76,6 +80,26 @@ const switchLocale: SelectProps['onChange'] = (value) => {
76
80
  }
77
81
  }
78
82
 
83
+ /* ── 响应式:窄屏顶栏不是"缩小版顶栏",而是换一套信息优先级 ─────────────
84
+ * 桌面:航迹页签是主角(多页并行来回切)。
85
+ * 窄屏:页签轨与右侧功能簇争抢横向空间 —— 实测 390px 下页签被右侧图标
86
+ * 逐个压过去,最后连用户铭牌都被推出视口(顶栏 overflow:hidden 直接裁掉)。
87
+ * 所以窄屏撤掉页签轨,用**当前页标题**替代:窄屏用户要的是"我在哪",
88
+ * 不是"我刚才还开过哪 5 个页面"。 */
89
+ const { isDrawer, isMobile } = useResponsive()
90
+
91
+ const navToggleLabel = computed(() =>
92
+ isDrawer.value
93
+ ? (store.mobileNavOpen ? t('header.closeNav') : t('header.openNav'))
94
+ : (store.sidebarCollapsed ? t('header.expand') : t('header.collapse')))
95
+
96
+ const toggleNav = () => {
97
+ if (isDrawer.value) store.toggleMobileNav()
98
+ else store.toggleSidebar()
99
+ }
100
+
101
+ const currentTitle = computed(() => metaFor(route.path).title)
102
+
79
103
  // ── 航迹导航:路由变化 → 记录航点;切换时进度线扫过 ──
80
104
  const hydrated = ref(false)
81
105
  const plotting = ref(false)
@@ -196,12 +220,16 @@ const onAvatarMenu: MenuProps['onClick'] = async ({ key }) => {
196
220
  <div class="header-left">
197
221
  <button
198
222
  class="collapse-btn"
199
- :aria-label="store.sidebarCollapsed ? t('header.expand') : t('header.collapse')"
200
- @click="store.toggleSidebar()"
223
+ :aria-label="navToggleLabel"
224
+ :aria-expanded="isDrawer ? store.mobileNavOpen : !store.sidebarCollapsed"
225
+ @click="toggleNav()"
201
226
  >
202
227
  <span class="i-tabler-menu-2" />
203
228
  </button>
204
229
 
230
+ <!-- 窄屏:当前页标题(替代被撤掉的页签轨) -->
231
+ <span class="mobile-title">{{ currentTitle }}</span>
232
+
205
233
  <span class="rail-mark i-tabler-route" />
206
234
 
207
235
  <nav
@@ -313,14 +341,14 @@ const onAvatarMenu: MenuProps['onClick'] = async ({ key }) => {
313
341
  </ClientOnly>
314
342
  <!-- 实时连接状态点(WS 会话全局单例;未用过 WS 的会话不显示) -->
315
343
  <span
316
- v-if="wsVisible"
344
+ v-if="hydrated && wsVisible"
317
345
  class="ws-dot"
318
346
  :class="wsClass"
319
347
  :title="wsLabel"
320
348
  />
321
349
  <a-tooltip :title="t('header.fullscreen')">
322
350
  <button
323
- class="icon-btn"
351
+ class="icon-btn hdr-fullscreen"
324
352
  @click="toggleFullscreen"
325
353
  >
326
354
  <span
@@ -734,12 +762,75 @@ const onAvatarMenu: MenuProps['onClick'] = async ({ key }) => {
734
762
 
735
763
  .user-role {
736
764
  font-family: var(--font-mono);
737
- font-size: 8.5px;
738
- letter-spacing: 0.18em;
765
+ /* 8.5px 是"看得见读不了"的下限之外(实测常驻被审计标红);
766
+ 角色是身份信息,不是装饰刻度,抬到 9.5px 仍保持铭牌声部 */
767
+ font-size: 9.5px;
768
+ letter-spacing: 0.14em;
739
769
  text-transform: uppercase;
740
770
  color: var(--app-text-secondary, var(--ink-faint));
741
771
  }
742
772
 
773
+ /* 移动端当前页标题:桌面不存在(那里有页签轨) */
774
+ .mobile-title {
775
+ display: none;
776
+ min-width: 0;
777
+ overflow: hidden;
778
+ font-size: 14px;
779
+ font-weight: 600;
780
+ color: var(--app-text, var(--ink));
781
+ text-overflow: ellipsis;
782
+ white-space: nowrap;
783
+ }
784
+
785
+ /* ══ 顶栏响应式:按信息优先级逐级卸载,而不是让它们互相挤压 ═══════════════
786
+ * 卸载顺序(从最可省到最不可省):页签轨 → 全屏钮 → 用户双行铭牌 → 语言文字。
787
+ * 留下的核心是:HITL 铃标(有待办必须看得见)、连接状态点、主题、语言、身份。 */
788
+ @media (max-width: 899px) {
789
+ .rail-mark,
790
+ .trail {
791
+ display: none;
792
+ }
793
+
794
+ .mobile-title {
795
+ display: block;
796
+ margin-left: 2px;
797
+ }
798
+
799
+ .app-header {
800
+ padding: 0 12px 0 8px;
801
+ }
802
+ }
803
+
804
+ @media (max-width: 639px) {
805
+ .hdr-fullscreen {
806
+ display: none;
807
+ }
808
+
809
+ .user-chip {
810
+ height: 38px;
811
+ padding: 0 6px;
812
+ }
813
+
814
+ .user-meta {
815
+ display: none;
816
+ }
817
+
818
+ /* 窄屏标签已换成 2 字符(ZH / EN),选择器只需容纳标签 + 箭头 + 内距 */
819
+ .lang-select {
820
+ width: 76px;
821
+ }
822
+
823
+ .lang-select :deep(.ant-select-selection-item) {
824
+ padding-inline-end: 16px;
825
+ font-size: 12.5px;
826
+ }
827
+
828
+ .header-left,
829
+ .header-right {
830
+ gap: 4px;
831
+ }
832
+ }
833
+
743
834
  .hidden {
744
835
  display: none;
745
836
  }
@@ -23,6 +23,13 @@ interface MenuGroup {
23
23
  items: MenuItem[]
24
24
  }
25
25
 
26
+ /**
27
+ * 是否已完成客户端水合。
28
+ * 服务端拿不到会话(cookie 里的 workshop.user 只在浏览器可读),
29
+ * 任何"按身份增删 DOM"的渲染都必须由它门控,否则 SSR 与客户端首帧结构不一致。
30
+ */
31
+ const navHydrated = ref(false)
32
+
26
33
  /**
27
34
  * 导航信息架构:12 个平铺条目 → 三组语义分区(控制台 / 运维 / 系统)。
28
35
  * 分组的价值不在多一层容器,而在"扫视成本":同组内的入口是同一件事的不同面,
@@ -61,26 +68,96 @@ const menuGroups = computed<MenuGroup[]>(() => [
61
68
  ],
62
69
  },
63
70
  ]
64
- .map(g => ({ ...g, items: g.items.filter(m => !m.adminOnly || userStore.isAdmin) }))
71
+ /* ⚠️ admin-only 条目必须等挂载后再放行:服务端没有会话(读不到 cookie 里的
72
+ * workshop.user),SSR 会少渲染「权限管理」这一条 → 客户端多一条 →
73
+ * 实测触发 Hydration 链式 mismatch(插件管理/系统设置的图标与文案整体错位一格)。
74
+ * 用 navHydrated 门控后,服务端与客户端首帧的 v-for 长度一致,水合干净。 */
75
+ .map(g => ({ ...g, items: g.items.filter(m => !m.adminOnly || (navHydrated.value && userStore.isAdmin)) }))
65
76
  .filter(g => g.items.length > 0))
66
77
 
67
78
  const isActive = (key: string): boolean =>
68
79
  key === '/' ? route.path === '/' : route.path.startsWith(key)
69
80
 
70
81
  const go = (key: string) => {
82
+ // 抽屉是浮层:点完必须收起来,否则用户看到的是"导航没反应"(内容被浮层盖着)
83
+ if (isDrawer.value) store.closeMobileNav()
71
84
  if (!isActive(key)) navigateTo(key)
72
85
  }
86
+
87
+ /* ── 响应式形态 ──────────────────────────────────────────────────────────
88
+ * 同一份导航有三种形态,由视口决定,不新增组件(避免三份 IA 各自漂移):
89
+ * ≥1024 三栏仪表台:跟随用户的折叠偏好
90
+ * 900–1023 双栏:强制图标轨 —— 228px 文字轨会把画布压到不可用
91
+ * <900 抽屉:强制展开(抽屉关着时展开与否无意义),汉堡开合 */
92
+ const { isDrawer, isTablet } = useResponsive()
93
+
94
+ /* 形态属性只在挂载后渲染:SSR 没有视口、一律按桌面档出 HTML,
95
+ * 若首帧就把 data-nav-mode="drawer" 打上去,水合时属性对不上会报 mismatch。
96
+ * 布局本身由 body 类 + CSS 媒体查询兜住,不依赖这个属性。 */
97
+ onMounted(() => {
98
+ navHydrated.value = true
99
+ })
100
+ const navMode = computed(() =>
101
+ navHydrated.value ? (isDrawer.value ? 'drawer' : (isTablet.value ? 'rail' : 'full')) : undefined)
102
+
103
+ const effectiveCollapsed = computed(() =>
104
+ isDrawer.value ? false : isTablet.value ? true : store.sidebarCollapsed)
105
+
106
+ const showLabels = computed(() => !effectiveCollapsed.value)
107
+
108
+ const drawerOpen = computed(() => isDrawer.value && store.mobileNavOpen)
109
+
110
+ /** 路由变化即收抽屉:抽屉是"去别处"的中转,不是常驻面板 */
111
+ watch(() => route.path, () => {
112
+ if (store.mobileNavOpen) store.closeMobileNav()
113
+ })
114
+
115
+ /**
116
+ * 形态镜像到 <body>(nav-drawer / nav-drawer-open)。
117
+ *
118
+ * 为什么不用 :class 直接打在 a-layout-sider 上:实测 antd 的 Sider 不会把
119
+ * 动态 class 落到它渲染的 <aside> 上(静态 class 可以,DOM 里查不到 is-drawer)。
120
+ * 依赖第三方组件的 attr 透传行为来做**结构性**布局是脆的 ——
121
+ * 改为把形态写在 body 上,CSS 由 main.css 的响应式层接管,只依赖自己的状态。
122
+ */
123
+ watchEffect(() => {
124
+ if (typeof document === 'undefined') return
125
+ document.body.classList.toggle('nav-drawer', isDrawer.value)
126
+ document.body.classList.toggle('nav-drawer-open', drawerOpen.value)
127
+ })
128
+
129
+ onBeforeUnmount(() => {
130
+ if (typeof document === 'undefined') return
131
+ document.body.classList.remove('nav-drawer', 'nav-drawer-open')
132
+ })
133
+
134
+ /** 抽屉展开时锁画布滚动(否则背景跟着手指跑,浮层失去"压在台面上"的物理感) */
135
+ watch(drawerOpen, (open) => {
136
+ if (typeof document === 'undefined') return
137
+ document.body.style.overflow = open ? 'hidden' : ''
138
+ })
139
+
140
+ /** Esc 关闭:仅抽屉形态接管,桌面侧栏不受影响 */
141
+ const onKeydown = (e: KeyboardEvent) => {
142
+ if (e.key === 'Escape' && drawerOpen.value) store.closeMobileNav()
143
+ }
144
+ onMounted(() => window.addEventListener('keydown', onKeydown))
145
+ onBeforeUnmount(() => {
146
+ window.removeEventListener('keydown', onKeydown)
147
+ if (typeof document !== 'undefined') document.body.style.overflow = ''
148
+ })
73
149
  </script>
74
150
 
75
151
  <template>
76
152
  <a-layout-sider
77
- v-model:collapsed="store.sidebarCollapsed"
153
+ :collapsed="effectiveCollapsed"
78
154
  :trigger="null"
79
155
  collapsible
80
- breakpoint="lg"
81
156
  :width="228"
82
157
  :collapsed-width="64"
83
158
  class="app-sider"
159
+ :data-nav-mode="navMode"
160
+ :aria-hidden="isDrawer && !drawerOpen ? 'true' : undefined"
84
161
  >
85
162
  <!-- 品牌区:AwLogo 六边形标志(绿→青渐变 + 孪生虚影 + 三节点互连,与 favicon 同源) -->
86
163
  <div class="logo">
@@ -92,7 +169,7 @@ const go = (key: string) => {
92
169
  </div>
93
170
  <transition name="slide-fade">
94
171
  <div
95
- v-show="!store.sidebarCollapsed"
172
+ v-show="showLabels"
96
173
  class="logo-text"
97
174
  >
98
175
  <span class="logo-title">{{ site.name }}</span>
@@ -109,7 +186,7 @@ const go = (key: string) => {
109
186
  >
110
187
  <!-- 分组标:mono 微字 + 收尾 hairline(仪器命名牌 + 刻度线的同一语言) -->
111
188
  <div
112
- v-show="!store.sidebarCollapsed"
189
+ v-show="showLabels"
113
190
  class="menu-group-label"
114
191
  >
115
192
  <span class="menu-group-text">{{ group.label }}</span>
@@ -119,7 +196,7 @@ const go = (key: string) => {
119
196
  />
120
197
  </div>
121
198
  <div
122
- v-show="store.sidebarCollapsed"
199
+ v-show="!showLabels"
123
200
  class="menu-group-sep"
124
201
  aria-hidden="true"
125
202
  />
@@ -129,7 +206,7 @@ const go = (key: string) => {
129
206
  type="button"
130
207
  class="menu-item im"
131
208
  :class="{ active: isActive(item.key) }"
132
- :title="store.sidebarCollapsed ? item.label : undefined"
209
+ :title="!showLabels ? item.label : undefined"
133
210
  @click="go(item.key)"
134
211
  >
135
212
  <span
@@ -137,7 +214,7 @@ const go = (key: string) => {
137
214
  :class="[item.icon, item.motion]"
138
215
  />
139
216
  <span
140
- v-show="!store.sidebarCollapsed"
217
+ v-show="showLabels"
141
218
  class="menu-label"
142
219
  >{{ item.label }}</span>
143
220
  </button>
@@ -146,7 +223,7 @@ const go = (key: string) => {
146
223
 
147
224
  <!-- 底部铭牌:版本与运行模式(上缘刻度收边,与画布分节同语言) -->
148
225
  <div
149
- v-show="!store.sidebarCollapsed"
226
+ v-show="showLabels"
150
227
  class="sider-footer"
151
228
  >
152
229
  <div class="footer-rule" />
@@ -157,6 +234,14 @@ const go = (key: string) => {
157
234
  </div>
158
235
  </div>
159
236
  </a-layout-sider>
237
+
238
+ <!-- 抽屉遮罩:点空白处关闭(与 esc-close 的 @click.self 契约一致) -->
239
+ <div
240
+ v-if="drawerOpen"
241
+ class="nav-scrim"
242
+ aria-hidden="true"
243
+ @click="store.closeMobileNav()"
244
+ />
160
245
  </template>
161
246
 
162
247
  <style scoped>
@@ -216,8 +301,10 @@ const go = (key: string) => {
216
301
 
217
302
  .logo-sub {
218
303
  font-family: var(--font-mono);
219
- font-size: 8.5px;
220
- letter-spacing: 0.2em;
304
+ /* 8.5px 在这块铭牌上连"看得见"都勉强(实测全站每页稳定被判为不可读);
305
+ 9.5px 是这套 mono 铭牌的下限,字距同步收一点以保持行长。 */
306
+ font-size: 9.5px;
307
+ letter-spacing: 0.16em;
221
308
  text-transform: uppercase;
222
309
  color: var(--sider-ink-faint);
223
310
  }
@@ -391,4 +478,23 @@ const go = (key: string) => {
391
478
  opacity: 0;
392
479
  transform: translateX(-8px);
393
480
  }
481
+
482
+ /* 抽屉形态的定位/位移样式在 main.css 响应式层(body.nav-drawer)—— 见那里的说明。 */
483
+
484
+ .nav-scrim {
485
+ position: fixed;
486
+ inset: 0;
487
+ z-index: 1100;
488
+ background: rgb(6 12 20 / 58%);
489
+ backdrop-filter: blur(2px);
490
+ animation: nav-scrim-in 0.2s ease both;
491
+ }
492
+
493
+ @keyframes nav-scrim-in {
494
+ from { opacity: 0; }
495
+ }
496
+
497
+ @media (prefers-reduced-motion: reduce) {
498
+ .nav-scrim { animation: none; }
499
+ }
394
500
  </style>
@@ -14,6 +14,7 @@ import VChart from 'vue-echarts'
14
14
  import { computed } from 'vue'
15
15
  import type { PropType } from 'vue'
16
16
  import type { EChartsOption } from 'echarts'
17
+ import type { SetOptionOpts } from 'echarts/core'
17
18
 
18
19
  // 按需注册 ECharts 模块(必须在 <ClientOnly> 内使用:canvas 仅客户端可渲染)
19
20
  use([
@@ -61,7 +62,7 @@ const merged = computed<EChartsOption>(() => ({
61
62
  * series 数量**减少**时(如筛选后趋势线变少),旧 series 必须被移除,否则会残留幽灵曲线;
62
63
  * - `lazyUpdate: true` → 同一 tick 内多次 setOption 合并到下一帧渲染,避免重复绘制。
63
64
  */
64
- const updateOptions = { notMerge: false, replaceMerge: ['series'], lazyUpdate: true } as const
65
+ const updateOptions: SetOptionOpts = { notMerge: false, replaceMerge: ['series'], lazyUpdate: true }
65
66
  </script>
66
67
 
67
68
  <template>
@@ -224,13 +224,13 @@ const stateDot: Record<string, string> = {
224
224
  {{ group[0] }}({{ (group[1] as typeof assignedTasks.working).length }})
225
225
  </div>
226
226
  <div
227
- v-for="t in group[1]"
228
- :key="t.id"
227
+ v-for="task in group[1]"
228
+ :key="task.id"
229
229
  class="queue-task"
230
230
  >
231
- <span class="state-chip aw-mono">{{ t.state }}</span>
232
- <span class="qt-title">{{ t.title }}</span>
233
- <span class="qt-meta">{{ t.progress }}%</span>
231
+ <span class="state-chip aw-mono">{{ task.state }}</span>
232
+ <span class="qt-title">{{ task.title }}</span>
233
+ <span class="qt-meta">{{ task.progress }}%</span>
234
234
  </div>
235
235
  <div
236
236
  v-if="(group[1] as typeof assignedTasks.working).length === 0"
@@ -384,7 +384,7 @@ const stateDot: Record<string, string> = {
384
384
  .state-chip {
385
385
  flex: none;
386
386
  padding: 1px 6px;
387
- font-size: 9px;
387
+ font-size: 10px;
388
388
  line-height: 15px;
389
389
  letter-spacing: 0.03em;
390
390
  color: var(--ink-soft);
@@ -822,7 +822,7 @@ onBeforeUnmount(() => {
822
822
  align-items: center;
823
823
  padding: 0 6px;
824
824
  font-family: var(--font-mono);
825
- font-size: 9px;
825
+ font-size: 10px;
826
826
  line-height: 15px;
827
827
  color: var(--ink-faint);
828
828
  border: 1px solid var(--line-strong);
@@ -944,4 +944,55 @@ onBeforeUnmount(() => {
944
944
  background: color-mix(in srgb, currentColor 5%, transparent);
945
945
  border-radius: var(--radius-chip);
946
946
  }
947
+
948
+ /* ── 窄屏(≤1023):泳道从"并排仪表"改为"一次一泳道"的横向卡片流 ──
949
+ 桌面 min-width 240px 的泳道在 390px 下并排 = 每列都被压到极限;
950
+ 改为 88% 宽 + scroll-snap:一屏一路信号,横扫切换成员。 */
951
+ @media (max-width: 1023.98px) {
952
+ .toolbar {
953
+ flex-wrap: wrap;
954
+ gap: 8px;
955
+ padding: 8px 10px 6px;
956
+ }
957
+
958
+ .ts-label,
959
+ .ts-unit,
960
+ .ts-detail,
961
+ .lane-meta,
962
+ .empty-hint {
963
+ font-size: 11.5px;
964
+ }
965
+
966
+ .lanes {
967
+ padding: 8px;
968
+ scroll-snap-type: x mandatory;
969
+ -webkit-overflow-scrolling: touch;
970
+ }
971
+
972
+ .lane {
973
+ flex: 0 0 88%;
974
+ min-width: 0;
975
+ scroll-snap-align: center;
976
+ }
977
+
978
+ .lane-name {
979
+ font-size: 14px;
980
+ }
981
+
982
+ .lane-chip,
983
+ .lane-role,
984
+ .term-badge {
985
+ font-size: 11.5px;
986
+ line-height: 18px;
987
+ }
988
+
989
+ .lane-actions .ant-btn {
990
+ min-width: 40px;
991
+ min-height: 40px;
992
+ }
993
+
994
+ .empty-title {
995
+ font-size: 13px;
996
+ }
997
+ }
947
998
  </style>
@@ -262,7 +262,7 @@ async function doRemove(id: string): Promise<void> {
262
262
  .head-hint {
263
263
  margin-left: auto;
264
264
  font-family: var(--font-mono);
265
- font-size: 8.5px;
265
+ font-size: 10px;
266
266
  color: var(--hud-faint, #5b6c7b);
267
267
  white-space: nowrap;
268
268
  }
@@ -384,7 +384,9 @@ async function doRemove(id: string): Promise<void> {
384
384
  }
385
385
  .model-badge {
386
386
  font-family: var(--font-mono);
387
- font-size: 8.5px;
387
+ /* 8.5px 在这套 HUD 里是"看得见读不了"的下限之外(实测被审计稳定判为不可读);
388
+ 10px 是同类铭牌(--hud 微字)在 1440 下的地板。 */
389
+ font-size: 10px;
388
390
  letter-spacing: 0.08em;
389
391
  color: var(--hud-faint, #5b6c7b);
390
392
  text-align: left;
@@ -188,6 +188,8 @@ const onLlmModelChange = (): void => {
188
188
  }
189
189
  const settingsSaving = ref(false)
190
190
  const fileSelectorOpen2 = ref(false)
191
+ /** channel 设置弹窗预填的默认 LLM(llmJson 反序列化形状;与服务端 channelLlmSchema 对齐) */
192
+ interface ChannelLlmDefaults { provider?: string, model?: string, effort?: string }
191
193
  const openSettings = (channelId: string): void => {
192
194
  const meta = channels.value.find(c => c.id === channelId)
193
195
  settingsChannelId.value = channelId
@@ -195,10 +197,10 @@ const openSettings = (channelId: string): void => {
195
197
  settingsForm.scenarioPrompt = meta?.scenarioPrompt ?? ''
196
198
  settingsForm.workspace = meta?.workspace ?? ''
197
199
  // 预填 channel 默认 LLM(llmJson 由列表接口透传)
198
- let saved: { provider?: string, model?: string, effort?: string } | null = null
200
+ let saved: ChannelLlmDefaults | null = null
199
201
  try {
200
202
  const metaAny = meta as unknown as { llmJson?: string } | undefined
201
- saved = metaAny?.llmJson ? JSON.parse(metaAny.llmJson) as typeof saved : null
203
+ saved = metaAny?.llmJson ? JSON.parse(metaAny.llmJson) as ChannelLlmDefaults : null
202
204
  }
203
205
  catch { saved = null }
204
206
  llmForm.enabled = !!saved?.model
@@ -728,4 +728,100 @@ const placeholder = computed(() =>
728
728
  background: var(--tone-live-dot);
729
729
  opacity: 1;
730
730
  }
731
+
732
+ /* ── 窄屏(≤1023):输入区是手持设备的"主操作面",键盘弹出时它必须还在 ──
733
+ 桌面工具栏是「一行左簇右钮」;390px 下这行会折成一列竖排字,
734
+ 所以窄屏改为「模式行 → 目标行 → 发送行」三段堆叠,发送占满一行且 ≥44px。 */
735
+ @media (max-width: 1023.98px) {
736
+ .composer {
737
+ padding: 8px 10px calc(10px + env(safe-area-inset-bottom));
738
+ }
739
+
740
+ .composer-box {
741
+ padding: 8px 10px;
742
+ }
743
+
744
+ /* 状态 chip:桌面宽度自适应内容,窄屏必须允许折行,否则顶破输入卡 */
745
+ .composer-status-chip {
746
+ width: auto;
747
+ flex-wrap: wrap;
748
+ row-gap: 2px;
749
+ font-size: 11.5px;
750
+ line-height: 1.45;
751
+ }
752
+
753
+ .chip-hint {
754
+ flex: 1 1 100%;
755
+ padding-left: 0;
756
+ margin-left: 0;
757
+ }
758
+
759
+ .reach-chip,
760
+ .mention-role,
761
+ .mention-title {
762
+ font-size: 11.5px;
763
+ }
764
+
765
+ /* 16px 是 iOS 不缩放输入框的下限(小于它聚焦时整页被放大) */
766
+ .composer-input {
767
+ min-height: 42px;
768
+ max-height: 30dvh;
769
+ font-size: 16px;
770
+ }
771
+
772
+ .composer-bar {
773
+ flex-wrap: wrap;
774
+ gap: 8px;
775
+ margin-top: 8px;
776
+ }
777
+
778
+ .cb-left {
779
+ flex: 1 1 100%;
780
+ row-gap: 8px;
781
+ }
782
+
783
+ .cb-right {
784
+ flex: 1 1 100%;
785
+ }
786
+
787
+ /* 主操作:整行墨色药丸(触摸目标 44px) */
788
+ .send-btn {
789
+ width: 100%;
790
+ height: 44px;
791
+ font-size: 18px;
792
+ }
793
+
794
+ .aw-seg button {
795
+ min-height: 40px;
796
+ padding: 0 12px;
797
+ }
798
+
799
+ .chip-toggle {
800
+ min-height: 40px;
801
+ }
802
+
803
+ .target {
804
+ flex: 1 1 130px;
805
+ width: auto;
806
+ }
807
+
808
+ .composer-bar :deep(.ant-select-selector) {
809
+ min-height: 40px;
810
+ align-items: center;
811
+ }
812
+
813
+ .loop-number,
814
+ .loop-number.iterations {
815
+ flex: 1 1 96px;
816
+ width: auto;
817
+ }
818
+
819
+ .composer-bar :deep(.ant-input-number) {
820
+ min-height: 40px;
821
+ }
822
+
823
+ .mention-opt {
824
+ min-height: 44px;
825
+ }
826
+ }
731
827
  </style>
@@ -544,6 +544,25 @@ tr.row-recipe-alarm td:first-child { box-shadow: inset 3px 0 0 var(--tone-danger
544
544
  border-color: transparent;
545
545
  opacity: 1;
546
546
  }
547
+ /* ── 窄屏字号地板 ────────────────────────────────────────────────────────
548
+ * 节点行是"一台仪表的铭牌":桌面 10–11px 的 mono 微字是刻意的仪器语言。
549
+ * 但 375px 下这一行同时是**横向卷轴里的账页**,读距近、字号小、还要左右扫 ——
550
+ * 实测审计在 /daq 单页稳定报出近 2000 个 <11px 的文本节点,全部来自这里。
551
+ * 手持档把二级/三级信息抬到 11.5px(一级不受影响),布局不变(它们本就在
552
+ * 允许换行的单元格里),只是把"看得见"变成"读得了"。 */
553
+ @media (max-width: 900px) {
554
+ .ch,
555
+ .drv-tag,
556
+ .st-pill,
557
+ .node-meta small,
558
+ .dev-unbind,
559
+ .dev-bind-chip,
560
+ .dev-add,
561
+ small.mono {
562
+ font-size: 11.5px;
563
+ }
564
+ }
565
+
547
566
  @media (prefers-reduced-motion: no-preference) {
548
567
  .run-pill.on .rp-dot { animation: rpPulse 1.8s ease-in-out infinite; }
549
568
  }
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * 数采/智控模板图标 —— 全项目唯一的 SVG 片段注入口。
4
+ *
5
+ * 为什么这里必须用 v-html:DAQ_ICONS 的值是 SVG **绘制片段**(path/circle/rect),
6
+ * 必须按 SVG 命名空间解析成图元,文本插值只会把它们画成字面文本。
7
+ * 为什么是安全的:DAO_ICONS 是编译期静态字面量表 —— 键来自 #shared 协议的图标枚举,
8
+ * 值全部是本文件里手写的字符串,不含用户输入、不含 <script>/on* 事件属性/外部引用。
9
+ * 收敛收益:TownView 原先有 6 处 v-html(各自重复同样的判断),现在只此一处。
10
+ */
11
+ const props = defineProps<{ icon: string }>()
12
+
13
+ /** 数采模板图标(设计稿 ICONS;SVG path 直嵌) */
14
+ const DAQ_ICONS: Record<string, string> = {
15
+ thermo: '<path d="M10 4a2 2 0 0 1 4 0v9a4 4 0 1 1-4 0V4Z"/><circle cx="12" cy="16.5" r="1.6"/>',
16
+ pressure: '<circle cx="12" cy="12" r="8"/><path d="m12 12 3.5-3.5"/><circle cx="12" cy="12" r="1.2"/>',
17
+ tension: '<circle cx="12" cy="10" r="4"/><path d="M4 18.5h16M8 18.5V14M16 18.5V14"/><path d="M2.5 10H8M16 10h5.5"/>',
18
+ encoder: '<circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2"/><path d="M12 4v3M12 17v3M4 12h3M17 12h3"/>',
19
+ camera: '<rect x="3" y="7" width="13" height="10" rx="2"/><path d="m16 11 5-3v8l-5-3"/><circle cx="8" cy="12" r="2.5"/>',
20
+ gateway: '<rect x="8" y="11" width="8" height="10" rx="1.5"/><circle cx="12" cy="5.5" r="1.5"/><path d="M12 10V7M8.5 8.5a5 5 0 0 1 7 0M6 6a8.5 8.5 0 0 1 12 0"/>',
21
+ }
22
+
23
+ const markup = computed(() => DAQ_ICONS[props.icon] ?? DAQ_ICONS.gateway!)
24
+ </script>
25
+
26
+ <template>
27
+ <!-- eslint-disable vue/no-v-html -- DAQ_ICONS 是编译期静态 SVG 绘制片段(见 script 顶部),不含任何用户输入 -->
28
+ <svg
29
+ viewBox="0 0 24 24"
30
+ v-html="markup"
31
+ />
32
+ <!-- eslint-enable vue/no-v-html -->
33
+ </template>