agentworkshop 0.7.8 → 0.7.9

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 (253) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/-6OnbLFb.js +1 -0
  3. package/.output/public/_nuxt/{BUxYN2mw.js → -nb2uqVg.js} +1 -1
  4. package/.output/public/_nuxt/{DM8DS9MA.js → 6PZPfFcO.js} +1 -1
  5. package/.output/public/_nuxt/91DZTUMJ.js +1 -0
  6. package/.output/public/_nuxt/B0HpdCKS.js +1 -0
  7. package/.output/public/_nuxt/B1g8pJmr.js +2 -0
  8. package/.output/public/_nuxt/B1kA8LhC.js +14 -0
  9. package/.output/public/_nuxt/{uBbDCfTz.js → B5S_UyaC.js} +1 -1
  10. package/.output/public/_nuxt/{DZk24ego.js → B7wL3pDk.js} +1 -1
  11. package/.output/public/_nuxt/B9MUiDFl.js +1 -0
  12. package/.output/public/_nuxt/B9dLFSYI.js +1 -0
  13. package/.output/public/_nuxt/BC8s1Guv.js +1 -0
  14. package/.output/public/_nuxt/{BSXx2vqR.js → BCJFMBQ6.js} +1 -1
  15. package/.output/public/_nuxt/{BYL0Rjqj.js → BDASpD_i.js} +3 -3
  16. package/.output/public/_nuxt/{VnIWJ0ts.js → BN_PdN3J.js} +1 -1
  17. package/.output/public/_nuxt/BUPj10t4.js +1 -0
  18. package/.output/public/_nuxt/BZGNTgTQ2.js +1 -0
  19. package/.output/public/_nuxt/{NIM0Wglj2.js → BaMkWl5i2.js} +1 -1
  20. package/.output/public/_nuxt/BmHvC_OU.js +1 -0
  21. package/.output/public/_nuxt/{BkfchkK62.js → Bp5luxkg2.js} +1 -1
  22. package/.output/public/_nuxt/{ZugRk0CM2.js → BuktKVqK2.js} +1 -1
  23. package/.output/public/_nuxt/By8BpbKH.js +1 -0
  24. package/.output/public/_nuxt/{pRQri7vQ2.js → BytVi9VX2.js} +1 -1
  25. package/.output/public/_nuxt/{D5KJ7_0V.js → C3tCneTM.js} +1 -1
  26. package/.output/public/_nuxt/{CblLEiCZ.js → C9cU_Ujd.js} +3 -3
  27. package/.output/public/_nuxt/{BJ-fxrSw.js → CBciOiTQ.js} +1 -1
  28. package/.output/public/_nuxt/CFn4vHwD.js +1 -0
  29. package/.output/public/_nuxt/{DCXIGxzT.js → CKfhtOt7.js} +2 -2
  30. package/.output/public/_nuxt/CUMdhxg9.js +1 -0
  31. package/.output/public/_nuxt/{ChEKFMxj.js → CUXCQXjG.js} +1 -1
  32. package/.output/public/_nuxt/CfVAr2nf.js +1 -0
  33. package/.output/public/_nuxt/{CvbHIGQY2.js → CgvGu2IO.js} +1 -1
  34. package/.output/public/_nuxt/CjDQPXfv.js +1 -0
  35. package/.output/public/_nuxt/{B4Fia4FB.js → CmHzfVc5.js} +1 -1
  36. package/.output/public/_nuxt/{Do88WZG2.js → Cn3J3NXR.js} +1 -1
  37. package/.output/public/_nuxt/{DNzaswei.js → Cst47G4-.js} +1 -1
  38. package/.output/public/_nuxt/{DYZBdSSg2.js → Ct68Z0232.js} +1 -1
  39. package/.output/public/_nuxt/{BsMpJf7S.js → D-Ca4BGY.js} +6 -6
  40. package/.output/public/_nuxt/D0Szyn_D.js +1 -0
  41. package/.output/public/_nuxt/{CsCpu2Zh.js → D1z7i2UP.js} +1 -1
  42. package/.output/public/_nuxt/{Du-eSpo2.js → D3VJ3lex.js} +1 -1
  43. package/.output/public/_nuxt/D8CqF0yy.js +1 -0
  44. package/.output/public/_nuxt/D8EfUxO2.js +1 -0
  45. package/.output/public/_nuxt/D8wyHvcz2.js +1 -0
  46. package/.output/public/_nuxt/{zwdqvGN_.js → DDdEnkdw.js} +1 -1
  47. package/.output/public/_nuxt/DM4CNkXz.js +1 -0
  48. package/.output/public/_nuxt/DN5RuZ8k.js +18 -0
  49. package/.output/public/_nuxt/DXRZPxGs.js +1 -0
  50. package/.output/public/_nuxt/{C2iWjzEC2.js → DoLasgPj2.js} +1 -1
  51. package/.output/public/_nuxt/{DRq09ZmT.js → DpojD719.js} +1 -1
  52. package/.output/public/_nuxt/Dqj2h40U.js +1 -0
  53. package/.output/public/_nuxt/{BCipft_k2.js → DsUUYP292.js} +1 -1
  54. package/.output/public/_nuxt/DtBu71ev.js +32 -0
  55. package/.output/public/_nuxt/{fQUs58kX2.js → DvgKXPgu2.js} +1 -1
  56. package/.output/public/_nuxt/{C_gFA2H_2.js → DxrgFxIr2.js} +1 -1
  57. package/.output/public/_nuxt/Dy-mxvXY2.js +1 -0
  58. package/.output/public/_nuxt/G0qIw7Gq2.js +1 -0
  59. package/.output/public/_nuxt/{DCEyMaN-.js → MyA0Oeqd.js} +3 -3
  60. package/.output/public/_nuxt/{tRBT-plo.js → OV6PBW2z.js} +1 -1
  61. package/.output/public/_nuxt/TownView.BHLKAjEu.css +1 -0
  62. package/.output/public/_nuxt/VLI2Zy4t.js +5 -0
  63. package/.output/public/_nuxt/_id_.DIxEKj88.css +1 -0
  64. package/.output/public/_nuxt/_id_.DTvjd6VN.css +1 -0
  65. package/.output/public/_nuxt/{_wsId_.COUzMXpP.css → _wsId_.BFyCuUwS.css} +1 -1
  66. package/.output/public/_nuxt/agents.CEbox5-D.css +1 -0
  67. package/.output/public/_nuxt/builds/latest.json +1 -1
  68. package/.output/public/_nuxt/builds/meta/92d6bd39-dbc5-46d5-90d8-8387f36715fa.json +1 -0
  69. package/.output/public/_nuxt/channel-templates.De5ZvrGz.css +1 -0
  70. package/.output/public/_nuxt/daq.6IrhVVfy.css +1 -0
  71. package/.output/public/_nuxt/dcw.DcDjwvqv.css +1 -0
  72. package/.output/public/_nuxt/{default.V3_hUJq1.css → default.BR3e5fPY.css} +1 -1
  73. package/.output/public/_nuxt/{Cyk3du4K2.js → kZV5TQvh2.js} +1 -1
  74. package/.output/public/_nuxt/logs.BO-BSyjm.css +1 -0
  75. package/.output/public/_nuxt/{D4qXvjuV.js → niDwBOZW.js} +2 -2
  76. package/.output/public/_nuxt/pKv_VWR4.js +1 -0
  77. package/.output/public/_nuxt/plugins.Clsky_kl.css +1 -0
  78. package/.output/public/_nuxt/rqZ-1SoP.js +2 -0
  79. package/.output/public/_nuxt/teams.CUMnbQGf.css +1 -0
  80. package/.output/public/_nuxt/tokens.BPLe9ioQ.css +1 -0
  81. package/.output/public/_nuxt/{C8dxXc6K.js → u7KWCGSb.js} +1 -1
  82. package/.output/public/_nuxt/{Bi6AiCuP.js → vJ4FPb-_.js} +1 -1
  83. package/.output/public/_nuxt/wirVyscc.js +1 -0
  84. package/.output/public/_nuxt/workshop.BIdoGfoC.css +1 -0
  85. package/.output/server/chunks/_/nitro.mjs +896 -882
  86. package/.output/server/chunks/build/{TownView-B5KifIaT.mjs → TownView-D8DSdO3H.mjs} +181 -180
  87. package/.output/server/chunks/build/{TownView-B5KifIaT.mjs.map → TownView-D8DSdO3H.mjs.map} +1 -1
  88. package/.output/server/chunks/build/{_id_-Ct4Jhvl1.mjs → _id_-BV4FfiYd.mjs} +36 -35
  89. package/.output/server/chunks/build/_id_-BV4FfiYd.mjs.map +1 -0
  90. package/.output/server/chunks/build/{_id_-C-ewLgfl.mjs → _id_-TP9hvnBM.mjs} +125 -124
  91. package/.output/server/chunks/build/_id_-TP9hvnBM.mjs.map +1 -0
  92. package/.output/server/chunks/build/{_wsId_-CanI_6Su.mjs → _wsId_-Mm9sQSz2.mjs} +125 -124
  93. package/.output/server/chunks/build/{_wsId_-CanI_6Su.mjs.map → _wsId_-Mm9sQSz2.mjs.map} +1 -1
  94. package/.output/server/chunks/build/{agents-DSOptxXA.mjs → agents-To3a5xcZ.mjs} +16 -15
  95. package/.output/server/chunks/build/agents-To3a5xcZ.mjs.map +1 -0
  96. package/.output/server/chunks/build/api-error-dul30BYQ.mjs +47 -0
  97. package/.output/server/chunks/build/api-error-dul30BYQ.mjs.map +1 -0
  98. package/.output/server/chunks/build/{channel-templates-BK0KuPOd.mjs → channel-templates-DRsP-qxl.mjs} +23 -22
  99. package/.output/server/chunks/build/channel-templates-DRsP-qxl.mjs.map +1 -0
  100. package/.output/server/chunks/build/{daq-D9RA_uze.mjs → daq-_hCEaYLd.mjs} +111 -110
  101. package/.output/server/chunks/build/daq-_hCEaYLd.mjs.map +1 -0
  102. package/.output/server/chunks/build/{dcw-BTM5YU-B.mjs → dcw-C7pJ4Y0p.mjs} +46 -45
  103. package/.output/server/chunks/build/dcw-C7pJ4Y0p.mjs.map +1 -0
  104. package/.output/server/chunks/build/{default-BfWGTlbj.mjs → default-Dnjs36e8.mjs} +16 -15
  105. package/.output/server/chunks/build/{default-BfWGTlbj.mjs.map → default-Dnjs36e8.mjs.map} +1 -1
  106. package/.output/server/chunks/build/{logs-Dyk0I2I9.mjs → logs-C039TFW1.mjs} +38 -37
  107. package/.output/server/chunks/build/logs-C039TFW1.mjs.map +1 -0
  108. package/.output/server/chunks/build/{pages-DR2bzczM.mjs → pages-C_VSGSGo.mjs} +5 -4
  109. package/.output/server/chunks/build/pages-C_VSGSGo.mjs.map +1 -0
  110. package/.output/server/chunks/build/{plugins-DnOBIWGg.mjs → plugins-4FMWkN8d.mjs} +25 -22
  111. package/.output/server/chunks/build/plugins-4FMWkN8d.mjs.map +1 -0
  112. package/.output/server/chunks/build/table-Cswq-l2r.mjs +1 -1
  113. package/.output/server/chunks/build/{teams-BhSKBBBM.mjs → teams-DA1lkf1n.mjs} +19 -18
  114. package/.output/server/chunks/build/teams-DA1lkf1n.mjs.map +1 -0
  115. package/.output/server/chunks/build/{tokens-D_eyxmcv.mjs → tokens-DKMvvk3e.mjs} +18 -17
  116. package/.output/server/chunks/build/tokens-DKMvvk3e.mjs.map +1 -0
  117. package/.output/server/chunks/build/{town-DPtOPRRO.mjs → town-D0thZ7PK.mjs} +6 -5
  118. package/.output/server/chunks/build/town-D0thZ7PK.mjs.map +1 -0
  119. package/.output/server/chunks/build/{useDaqStream-hwkhJHFU.mjs → useDaqStream-BVTRw8_H.mjs} +4 -3
  120. package/.output/server/chunks/build/useDaqStream-BVTRw8_H.mjs.map +1 -0
  121. package/.output/server/chunks/build/{useDcwStream-Bdew_yrr.mjs → useDcwStream-DNsivqI_.mjs} +4 -3
  122. package/.output/server/chunks/build/useDcwStream-DNsivqI_.mjs.map +1 -0
  123. package/.output/server/chunks/build/{useDeviceTwins-C6EBg9oN.mjs → useDeviceTwins-WeIom7A6.mjs} +4 -3
  124. package/.output/server/chunks/build/useDeviceTwins-WeIom7A6.mjs.map +1 -0
  125. package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs +1 -1
  126. package/.output/server/chunks/build/{useOpsLog-DdCqKVVG.mjs → useOpsLog-DcKnPO43.mjs} +5 -4
  127. package/.output/server/chunks/build/useOpsLog-DcKnPO43.mjs.map +1 -0
  128. package/.output/server/chunks/build/useWorkshopApi-D2gq06N2.mjs +1 -1
  129. package/.output/server/chunks/build/{workshop-D5CQj2A8.mjs → workshop-BhWnJMWs.mjs} +19 -18
  130. package/.output/server/chunks/build/workshop-BhWnJMWs.mjs.map +1 -0
  131. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +3 -3
  132. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs.map +1 -1
  133. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +3 -3
  134. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs.map +1 -1
  135. package/.output/server/chunks/routes/renderer.mjs +1 -1
  136. package/.output/server/chunks/virtual/entry.mjs +48 -22
  137. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  138. package/.output/server/package.json +1 -1
  139. package/app/components/AppHeader.vue +1 -1
  140. package/app/components/workshop/A2aRpcDebugger.vue +1 -1
  141. package/app/components/workshop/AgentInspectorDrawer.vue +3 -3
  142. package/app/components/workshop/AgentLanesView.vue +6 -6
  143. package/app/components/workshop/AssetLibrary.vue +2 -2
  144. package/app/components/workshop/ChannelSessionList.vue +5 -5
  145. package/app/components/workshop/Composer.vue +1 -1
  146. package/app/components/workshop/DeviceTwinPanel.vue +2 -2
  147. package/app/components/workshop/TaskBoardView.vue +1 -1
  148. package/app/components/workshop/TaskInspectorDrawer.vue +2 -2
  149. package/app/components/workshop/town/TownView.vue +23 -23
  150. package/app/composables/workshop/apiClient.ts +1 -1
  151. package/app/composables/workshop/useCharacterAssets.ts +1 -1
  152. package/app/composables/workshop/useDaqStream.ts +1 -1
  153. package/app/composables/workshop/useDcwStream.ts +1 -1
  154. package/app/composables/workshop/useDeviceTwins.ts +1 -1
  155. package/app/composables/workshop/useOpsLog.ts +2 -2
  156. package/app/composables/workshop/useSceneLayouts.ts +1 -1
  157. package/app/pages/daq/[id].vue +1 -1
  158. package/app/pages/daq/index.vue +8 -8
  159. package/app/pages/dcw/[id].vue +13 -13
  160. package/app/pages/dcw/index.vue +7 -7
  161. package/app/pages/logs/index.vue +1 -1
  162. package/app/pages/plugins/index.vue +14 -6
  163. package/app/pages/tokens.vue +3 -3
  164. package/app/pages/workshop/agents.vue +2 -2
  165. package/app/pages/workshop/channel-templates.vue +3 -3
  166. package/app/pages/workshop/index.vue +4 -4
  167. package/app/pages/workshop/teams.vue +3 -3
  168. package/app/utils/api-error.ts +75 -0
  169. package/cli/commands/plugin.mjs +2 -2
  170. package/config.yml +1 -1
  171. package/i18n/locales/en.ts +16 -3
  172. package/i18n/locales/zh-CN.ts +16 -3
  173. package/package.json +1 -1
  174. package/scripts/_dbg-interval-config.mjs +17 -6
  175. package/scripts/_dbg-plugins-e2e.mjs +101 -0
  176. package/scripts/_dbg-repo-setup-verify.mjs +31 -0
  177. package/scripts/_dbg-setup-e2e.mjs +1 -1
  178. package/server/api/workshop/plugins/[name]/disable.post.ts +5 -3
  179. package/server/api/workshop/plugins/[name]/enable.post.ts +5 -3
  180. package/server/data/daqs.json +88 -44
  181. package/server/data/dcw-lines.json +21 -0
  182. package/server/data/dcw-products.json +119 -0
  183. package/server/data/dcw-recipes.json +422 -0
  184. package/server/data/dcw-rollback.json +193 -6
  185. package/server/data/dcw-runs.json +459 -348
  186. package/server/data/dcw-writes.json +204 -0
  187. package/server/data/dcws.json +730 -305
  188. package/server/data/line-runs.json +26 -6
  189. package/server/services/system-config.ts +5 -0
  190. package/server/services/workshop/daq/storage/sqlite.adapter.ts +10 -5
  191. package/server/services/workshop/plugins/host.mjs +2 -1
  192. package/server/services/workshop/settings.ts +10 -0
  193. package/.output/public/_nuxt/2LwEn9gX.js +0 -2
  194. package/.output/public/_nuxt/3612gD2V.js +0 -32
  195. package/.output/public/_nuxt/8eIQAVlb.js +0 -1
  196. package/.output/public/_nuxt/Ah9qOv1m.js +0 -1
  197. package/.output/public/_nuxt/B7aqqzkY.js +0 -1
  198. package/.output/public/_nuxt/BH0Z05CS.js +0 -1
  199. package/.output/public/_nuxt/BJvGPTpC.js +0 -1
  200. package/.output/public/_nuxt/BVZjSVs2.js +0 -1
  201. package/.output/public/_nuxt/BVzDoF8t.js +0 -1
  202. package/.output/public/_nuxt/BjVLsC3M.js +0 -1
  203. package/.output/public/_nuxt/BnVoQ74r.js +0 -1
  204. package/.output/public/_nuxt/Bnp4vIAf.js +0 -1
  205. package/.output/public/_nuxt/Bt_HDizI.js +0 -5
  206. package/.output/public/_nuxt/Bu-P92Pe.js +0 -18
  207. package/.output/public/_nuxt/ButLXkjo.js +0 -2
  208. package/.output/public/_nuxt/By-LNp3k.js +0 -1
  209. package/.output/public/_nuxt/CGdPdJPP.js +0 -1
  210. package/.output/public/_nuxt/CRGlf1Gb.js +0 -1
  211. package/.output/public/_nuxt/CS8R0_J3.js +0 -1
  212. package/.output/public/_nuxt/CUxV8Bw_.js +0 -1
  213. package/.output/public/_nuxt/Cd15nPnG2.js +0 -1
  214. package/.output/public/_nuxt/DNJSkm3Q.js +0 -1
  215. package/.output/public/_nuxt/DXK1U43I.js +0 -1
  216. package/.output/public/_nuxt/Dc46i75T.js +0 -14
  217. package/.output/public/_nuxt/Dk6pq9JB2.js +0 -1
  218. package/.output/public/_nuxt/GP2wXyuY.js +0 -1
  219. package/.output/public/_nuxt/PQLnLxYe.js +0 -1
  220. package/.output/public/_nuxt/R_Wv_Nd9.js +0 -1
  221. package/.output/public/_nuxt/TownView.Bt33bo1M.css +0 -1
  222. package/.output/public/_nuxt/_id_.BzKMZnLe.css +0 -1
  223. package/.output/public/_nuxt/_id_.CbpDAWRh.css +0 -1
  224. package/.output/public/_nuxt/agents.BlejnOOC.css +0 -1
  225. package/.output/public/_nuxt/builds/meta/e5bb1803-86d9-43b3-85be-dc787dc9a978.json +0 -1
  226. package/.output/public/_nuxt/channel-templates.lkqEYlWY.css +0 -1
  227. package/.output/public/_nuxt/daq.zZ8GR433.css +0 -1
  228. package/.output/public/_nuxt/dcw.C46dGiF_.css +0 -1
  229. package/.output/public/_nuxt/eHGLpQSg2.js +0 -1
  230. package/.output/public/_nuxt/logs.DaIsHWZE.css +0 -1
  231. package/.output/public/_nuxt/p7wSGMtc.js +0 -1
  232. package/.output/public/_nuxt/plugins.FTm0PcEe.css +0 -1
  233. package/.output/public/_nuxt/teams.B8JNbUZg.css +0 -1
  234. package/.output/public/_nuxt/tokens.CWOTXM-Z.css +0 -1
  235. package/.output/public/_nuxt/ubPfs9mQ.js +0 -1
  236. package/.output/public/_nuxt/workshop.3kAcLB_M.css +0 -1
  237. package/.output/server/chunks/build/_id_-C-ewLgfl.mjs.map +0 -1
  238. package/.output/server/chunks/build/_id_-Ct4Jhvl1.mjs.map +0 -1
  239. package/.output/server/chunks/build/agents-DSOptxXA.mjs.map +0 -1
  240. package/.output/server/chunks/build/channel-templates-BK0KuPOd.mjs.map +0 -1
  241. package/.output/server/chunks/build/daq-D9RA_uze.mjs.map +0 -1
  242. package/.output/server/chunks/build/dcw-BTM5YU-B.mjs.map +0 -1
  243. package/.output/server/chunks/build/logs-Dyk0I2I9.mjs.map +0 -1
  244. package/.output/server/chunks/build/pages-DR2bzczM.mjs.map +0 -1
  245. package/.output/server/chunks/build/plugins-DnOBIWGg.mjs.map +0 -1
  246. package/.output/server/chunks/build/teams-BhSKBBBM.mjs.map +0 -1
  247. package/.output/server/chunks/build/tokens-D_eyxmcv.mjs.map +0 -1
  248. package/.output/server/chunks/build/town-DPtOPRRO.mjs.map +0 -1
  249. package/.output/server/chunks/build/useDaqStream-hwkhJHFU.mjs.map +0 -1
  250. package/.output/server/chunks/build/useDcwStream-Bdew_yrr.mjs.map +0 -1
  251. package/.output/server/chunks/build/useDeviceTwins-C6EBg9oN.mjs.map +0 -1
  252. package/.output/server/chunks/build/useOpsLog-DdCqKVVG.mjs.map +0 -1
  253. package/.output/server/chunks/build/workshop-D5CQj2A8.mjs.map +0 -1
@@ -124,7 +124,7 @@ async function doWrite(nodeId: string, value: number): Promise<void> {
124
124
  }
125
125
  }
126
126
  catch (err) {
127
- writeError.value = err instanceof Error ? err.message : String(err)
127
+ writeError.value = apiErrorMessage(err)
128
128
  }
129
129
  finally {
130
130
  writingId.value = ''
@@ -141,7 +141,7 @@ async function doRead(nodeId: string): Promise<void> {
141
141
  await dcw.readNode(nodeId)
142
142
  }
143
143
  catch (err) {
144
- writeError.value = err instanceof Error ? err.message : String(err)
144
+ writeError.value = apiErrorMessage(err)
145
145
  }
146
146
  finally {
147
147
  readingId.value = ''
@@ -164,7 +164,7 @@ async function toggleControl(nodeId: string, enabled: boolean): Promise<void> {
164
164
  }
165
165
  }
166
166
  catch (err) {
167
- writeError.value = err instanceof Error ? err.message : String(err)
167
+ writeError.value = apiErrorMessage(err)
168
168
  }
169
169
  finally {
170
170
  togglingId.value = ''
@@ -207,7 +207,7 @@ async function doTestConnection(): Promise<void> {
207
207
  addTest.value = await dcw.testDriver(addDriver.value, addCfg.value)
208
208
  }
209
209
  catch (err) {
210
- addTest.value = { ok: false, message: err instanceof Error ? err.message : String(err) }
210
+ addTest.value = { ok: false, message: apiErrorMessage(err) }
211
211
  }
212
212
  finally {
213
213
  addTesting.value = false
@@ -241,7 +241,7 @@ async function doAddNode(): Promise<void> {
241
241
  addSemantics.value = ''
242
242
  }
243
243
  catch (err) {
244
- addError.value = err instanceof Error ? err.message : String(err)
244
+ addError.value = apiErrorMessage(err)
245
245
  }
246
246
  finally {
247
247
  addSaving.value = false
@@ -304,7 +304,7 @@ async function doCreateTemplate(): Promise<void> {
304
304
  tplForm.semantics = ''
305
305
  }
306
306
  catch (err) {
307
- tplError.value = err instanceof Error ? err.message : String(err)
307
+ tplError.value = apiErrorMessage(err)
308
308
  }
309
309
  finally {
310
310
  tplSaving.value = false
@@ -332,7 +332,7 @@ async function doLineStart(): Promise<void> {
332
332
  lineMsg.value = t('dcwDetail.k17jteb9186', { p0: ls.value.productName, p1: ls.value.recipeName, p2: ls.value.runId })
333
333
  }
334
334
  catch (err) {
335
- lineErr.value = err instanceof Error ? err.message : String(err)
335
+ lineErr.value = apiErrorMessage(err)
336
336
  }
337
337
  finally {
338
338
  lineBusy.value = false
@@ -349,7 +349,7 @@ async function doLineStop(): Promise<void> {
349
349
  lineMsg.value = t('dcwDetail.kzl49pd187', { p0: was })
350
350
  }
351
351
  catch (err) {
352
- lineErr.value = err instanceof Error ? err.message : String(err)
352
+ lineErr.value = apiErrorMessage(err)
353
353
  }
354
354
  finally {
355
355
  lineBusy.value = false
@@ -375,7 +375,7 @@ async function doCreateProduct(): Promise<void> {
375
375
  productForm.description = ''
376
376
  }
377
377
  catch (err) {
378
- productError.value = err instanceof Error ? err.message : String(err)
378
+ productError.value = apiErrorMessage(err)
379
379
  }
380
380
  finally {
381
381
  productSaving.value = false
@@ -421,7 +421,7 @@ async function doQuery(): Promise<void> {
421
421
  if (queryResult.value.channels.length === 0) queryError.value = t('dcwDetail.kszv5sq136')
422
422
  }
423
423
  catch (err) {
424
- queryError.value = err instanceof Error ? err.message : String(err)
424
+ queryError.value = apiErrorMessage(err)
425
425
  }
426
426
  finally {
427
427
  queryBusy.value = false
@@ -509,7 +509,7 @@ async function saveRecipe(): Promise<void> {
509
509
  recipeOpen.value = false
510
510
  }
511
511
  catch (err) {
512
- recipeError.value = err instanceof Error ? err.message : String(err)
512
+ recipeError.value = apiErrorMessage(err)
513
513
  }
514
514
  finally {
515
515
  recipeSaving.value = false
@@ -526,7 +526,7 @@ async function doApplyRecipe(id: string): Promise<void> {
526
526
  if (ok < run.results.length) writeError.value = t('dcwDetail.ks7szkt188', { p0: run.results.filter(r => !r.ok).map(r => r.message).join(';') })
527
527
  }
528
528
  catch (err) {
529
- writeError.value = err instanceof Error ? err.message : String(err)
529
+ writeError.value = apiErrorMessage(err)
530
530
  }
531
531
  }
532
532
 
@@ -537,7 +537,7 @@ async function doViewRun(id: string): Promise<void> {
537
537
  runDataView.value = { runId: id, data }
538
538
  }
539
539
  catch (err) {
540
- writeError.value = err instanceof Error ? err.message : String(err)
540
+ writeError.value = apiErrorMessage(err)
541
541
  }
542
542
  finally {
543
543
  runDataLoading.value = false
@@ -69,7 +69,7 @@ async function doCreateLine(): Promise<void> {
69
69
  createOpen.value = false
70
70
  }
71
71
  catch (err) {
72
- createError.value = err instanceof Error ? err.message : String(err)
72
+ createError.value = apiErrorMessage(err)
73
73
  }
74
74
  finally {
75
75
  createSaving.value = false
@@ -90,7 +90,7 @@ async function quickStart(card: LineCard): Promise<void> {
90
90
  await dcw.startLine(card.line.id, rid)
91
91
  }
92
92
  catch (err) {
93
- quickErr.value = err instanceof Error ? err.message : String(err)
93
+ quickErr.value = apiErrorMessage(err)
94
94
  }
95
95
  finally {
96
96
  quickBusy.value = ''
@@ -104,7 +104,7 @@ async function quickStop(card: LineCard): Promise<void> {
104
104
  await dcw.stopLine(card.line.id)
105
105
  }
106
106
  catch (err) {
107
- quickErr.value = err instanceof Error ? err.message : String(err)
107
+ quickErr.value = apiErrorMessage(err)
108
108
  }
109
109
  finally {
110
110
  quickBusy.value = ''
@@ -140,7 +140,7 @@ async function doDeleteLine(): Promise<void> {
140
140
  delOpen.value = false
141
141
  }
142
142
  catch (err) {
143
- delErr.value = err instanceof Error ? err.message : String(err)
143
+ delErr.value = apiErrorMessage(err)
144
144
  }
145
145
  finally {
146
146
  delBusy.value = false
@@ -174,7 +174,7 @@ async function doEditLine(): Promise<void> {
174
174
  editOpen.value = false
175
175
  }
176
176
  catch (err) {
177
- editError.value = err instanceof Error ? err.message : String(err)
177
+ editError.value = apiErrorMessage(err)
178
178
  }
179
179
  finally {
180
180
  editSaving.value = false
@@ -218,7 +218,7 @@ async function doCreateTemplate(): Promise<void> {
218
218
  tplForm.max = ''
219
219
  }
220
220
  catch (err) {
221
- tplError.value = err instanceof Error ? err.message : String(err)
221
+ tplError.value = apiErrorMessage(err)
222
222
  }
223
223
  }
224
224
 
@@ -236,7 +236,7 @@ async function doRemoveTemplate(key: string): Promise<void> {
236
236
  if (i >= 0) dcw.templates.splice(i, 1)
237
237
  }
238
238
  catch (err) {
239
- tplError.value = err instanceof Error ? err.message : String(err)
239
+ tplError.value = apiErrorMessage(err)
240
240
  }
241
241
  }
242
242
 
@@ -436,7 +436,7 @@ async function submitManual(): Promise<void> {
436
436
  doQuery()
437
437
  }
438
438
  catch (err) {
439
- message.error(err instanceof Error ? err.message : String(err))
439
+ message.error(apiErrorMessage(err))
440
440
  }
441
441
  }
442
442
 
@@ -17,6 +17,8 @@ interface PluginInfo {
17
17
  version: string
18
18
  description: string
19
19
  scope: 'project' | 'user'
20
+ /** 内置示例插件(随项目检出提供);false/undefined = 用户级扩展 */
21
+ builtin?: boolean
20
22
  enabled: boolean
21
23
  hasClient: boolean
22
24
  routes: PluginRoute[]
@@ -43,8 +45,8 @@ async function load() {
43
45
  plugins.value = d.plugins ?? []
44
46
  failures.value = d.failures ?? []
45
47
  }
46
- catch {
47
- message.error(t('plugins.enableFail'))
48
+ catch (err) {
49
+ message.error(apiErrorMessage(err, t('plugins.loadFail')))
48
50
  }
49
51
  finally {
50
52
  loading.value = false
@@ -54,13 +56,15 @@ async function load() {
54
56
  async function toggle(p: PluginInfo) {
55
57
  busyName.value = p.name
56
58
  try {
57
- const d = await $fetch<{ enabled: boolean }>(`/api/workshop/plugins/${p.name}/${p.enabled ? 'disable' : 'enable'}`, { method: 'POST', headers: authHeaders() })
58
- p.enabled = d.enabled
59
- message.success(`${p.name} · ${d.enabled ? t('plugins.enabled') : t('plugins.disabled')}`)
59
+ const d = await $fetch<{ code: number, data?: { enabled: boolean } }>(`/api/workshop/plugins/${p.name}/${p.enabled ? 'disable' : 'enable'}`, { method: 'POST', headers: authHeaders() })
60
+ if (d.code !== 0 || !d.data) throw new Error(t('plugins.enableFail'))
61
+ p.enabled = d.data.enabled
62
+ message.success(`${p.name} · ${d.data.enabled ? t('plugins.enabled') : t('plugins.disabled')}`)
60
63
  setTimeout(load, 800) // 热重载完成后刷新路由/客户端状态
61
64
  }
62
65
  catch (err) {
63
- message.error(`${t('plugins.enableFail')}: ${(err as Error)?.message ?? ''}`)
66
+ // 403 权限不足/404 插件不存在等:信封 message 直出人话,不再渲染码式文本
67
+ message.error(apiErrorMessage(err, t('plugins.enableFail')))
64
68
  }
65
69
  finally {
66
70
  busyName.value = ''
@@ -189,6 +193,9 @@ onMounted(load)
189
193
  <dl class="detail">
190
194
  <dt>version</dt><dd>{{ current.version }}</dd>
191
195
  <dt>scope</dt><dd>{{ scopeLabel(current.scope) }}</dd>
196
+ <dd class="scope-hint">
197
+ {{ current.scope === 'project' ? $t('plugins.scopeBuiltinHint') : $t('plugins.scopeUserHint') }}
198
+ </dd>
192
199
  <dt>enabled</dt><dd>{{ current.enabled }}</dd>
193
200
  <dt>client</dt><dd>{{ current.hasClient ? '✓' : '—' }}</dd>
194
201
  <dt v-if="current.error">
@@ -252,6 +259,7 @@ onMounted(load)
252
259
  .card-routes code { font-size: 10px; opacity: .65; }
253
260
  .detail dt { margin-top: 10px; font-size: 11px; opacity: .5; }
254
261
  .detail dd { margin: 2px 0 0; font-family: ui-monospace, monospace; font-size: 12px; }
262
+ .detail .scope-hint { font-family: inherit; font-size: 11px; opacity: .6; margin-bottom: 6px; }
255
263
  .detail-route { display: block; font-size: 11px; opacity: .8; margin-bottom: 4px; }
256
264
  h4 { margin: 16px 0 6px; }
257
265
  .dim { opacity: .45; }
@@ -62,7 +62,7 @@ const doCreate = async (): Promise<void> => {
62
62
  await load()
63
63
  }
64
64
  catch (e) {
65
- message.error(e instanceof Error ? e.message : String(e))
65
+ message.error(apiErrorMessage(e))
66
66
  }
67
67
  finally {
68
68
  createLoading.value = false
@@ -84,7 +84,7 @@ const doRename = async (): Promise<void> => {
84
84
  message.success(tt('tokens.k3n9aij015'))
85
85
  }
86
86
  catch (e) {
87
- message.error(e instanceof Error ? e.message : String(e))
87
+ message.error(apiErrorMessage(e))
88
88
  }
89
89
  finally {
90
90
  renameLoading.value = false
@@ -103,7 +103,7 @@ const doRevoke = (t: { id?: string }): void => {
103
103
  await load()
104
104
  }
105
105
  catch (e) {
106
- message.error(e instanceof Error ? e.message : String(e))
106
+ message.error(apiErrorMessage(e))
107
107
  }
108
108
  })()
109
109
  }
@@ -136,7 +136,7 @@ const save = async (): Promise<void> => {
136
136
  void load()
137
137
  }
138
138
  catch (e) {
139
- message.error(e instanceof Error ? e.message : String(e))
139
+ message.error(apiErrorMessage(e))
140
140
  }
141
141
  }
142
142
  const remove = async (t: AgentTemplateDto): Promise<void> => {
@@ -158,7 +158,7 @@ const toggleVisibility = async (t: AgentTemplateDto, pub: boolean): Promise<void
158
158
  void load()
159
159
  }
160
160
  catch (e) {
161
- message.error(e instanceof Error ? e.message : String(e))
161
+ message.error(apiErrorMessage(e))
162
162
  }
163
163
  }
164
164
 
@@ -104,7 +104,7 @@ const create = async (): Promise<void> => {
104
104
  void load()
105
105
  }
106
106
  catch (e) {
107
- message.error(e instanceof Error ? e.message : String(e))
107
+ message.error(apiErrorMessage(e))
108
108
  }
109
109
  }
110
110
 
@@ -116,7 +116,7 @@ const toggleVisibility = async (t: ChannelTemplateDto, pub: boolean): Promise<vo
116
116
  void load()
117
117
  }
118
118
  catch (e) {
119
- message.error(e instanceof Error ? e.message : String(e))
119
+ message.error(apiErrorMessage(e))
120
120
  }
121
121
  }
122
122
 
@@ -130,7 +130,7 @@ const instantiate = async (t: ChannelTemplateDto): Promise<void> => {
130
130
  message.success(tt('ctpl.kefkfnl030', { p0: t.name, p1: data?.agentCount ?? 0 }))
131
131
  }
132
132
  catch (e) {
133
- message.error(e instanceof Error ? e.message : String(e))
133
+ message.error(apiErrorMessage(e))
134
134
  }
135
135
  finally {
136
136
  instantiating.value = null
@@ -63,7 +63,7 @@ const doRegister = async (): Promise<void> => {
63
63
  authPassword.value = ''
64
64
  }
65
65
  catch (e) {
66
- message.error(e instanceof Error ? e.message : String(e))
66
+ message.error(apiErrorMessage(e))
67
67
  }
68
68
  finally {
69
69
  authLoading.value = false
@@ -82,7 +82,7 @@ const doLogin = async (): Promise<void> => {
82
82
  authPassword.value = ''
83
83
  }
84
84
  catch (e) {
85
- message.error(e instanceof Error ? e.message : String(e))
85
+ message.error(apiErrorMessage(e))
86
86
  }
87
87
  finally {
88
88
  authLoading.value = false
@@ -97,7 +97,7 @@ const doLoginWithToken = async (): Promise<void> => {
97
97
  authTokenInput.value = ''
98
98
  }
99
99
  catch (e) {
100
- message.error(e instanceof Error ? e.message : String(e))
100
+ message.error(apiErrorMessage(e))
101
101
  }
102
102
  finally {
103
103
  authLoading.value = false
@@ -157,7 +157,7 @@ const create = async (): Promise<void> => {
157
157
  navigateTo(`/workshop/w/${ws.id}`)
158
158
  }
159
159
  catch (e) {
160
- message.error(e instanceof Error ? e.message : String(e))
160
+ message.error(apiErrorMessage(e))
161
161
  }
162
162
  finally {
163
163
  createLoading.value = false
@@ -79,7 +79,7 @@ const toggleVisibility = async (team: TeamDto, pub: boolean): Promise<void> => {
79
79
  void load()
80
80
  }
81
81
  catch (e) {
82
- message.error(e instanceof Error ? e.message : String(e))
82
+ message.error(apiErrorMessage(e))
83
83
  }
84
84
  }
85
85
 
@@ -105,7 +105,7 @@ const addMember = async (): Promise<void> => {
105
105
  void load()
106
106
  }
107
107
  catch (e) {
108
- message.error(e instanceof Error ? e.message : String(e))
108
+ message.error(apiErrorMessage(e))
109
109
  }
110
110
  }
111
111
  const removeMember = async (team: TeamDto, templateId: string): Promise<void> => {
@@ -135,7 +135,7 @@ const deploy = async (): Promise<void> => {
135
135
  deployOpen.value = false
136
136
  }
137
137
  catch (e) {
138
- message.error(e instanceof Error ? e.message : String(e))
138
+ message.error(apiErrorMessage(e))
139
139
  }
140
140
  finally {
141
141
  deploying.value = false
@@ -0,0 +1,75 @@
1
+ /**
2
+ * 统一错误文案解析 —— 任何 fetch/axios/业务异常 → 面向用户的可读提示。
3
+ *
4
+ * 项目约定:API 错误一律走 {code, message} 信封(defineApiHandler/AppError),
5
+ * 服务端 message 本就是人话;但 ofetch/axios 抛出的错误对象把 "[POST] /api/x
6
+ * 403 (forbidden)" 这类码式文本放在 err.message 上,信封在 err.data 里。
7
+ * 本解析器统一取值顺序:
8
+ * 1. 服务端信封 message(人话,优先);
9
+ * 2. HTTP 状态码 → 本地化映射(errors.* i18n,取不到回退内置中文);
10
+ * 3. 网络层失败特征 → "无法连接服务器";
11
+ * 4. 原始 message(最后兜底,通常已可读)。
12
+ * 永远返回非空字符串;message.error(messageError(err)) 即可替换一切裸 err.message 渲染。
13
+ */
14
+ interface ErrLike {
15
+ data?: unknown
16
+ statusCode?: number
17
+ status?: number
18
+ message?: string
19
+ code?: string | number
20
+ }
21
+
22
+ /** i18n 取不到时的内置回退(与 locales errors.* 保持一致,zh 优先项目) */
23
+ const FALLBACK: Record<string, string> = {
24
+ http400: '请求参数有误,请检查后重试',
25
+ http401: '登录已过期,请重新登录',
26
+ http403: '权限不足:该操作需要管理员权限',
27
+ http404: '目标不存在或已被删除',
28
+ http409: '操作冲突:资源已存在或状态不允许',
29
+ http5xx: '服务器内部错误,请稍后重试',
30
+ network: '无法连接服务器,请检查网络与服务状态',
31
+ fallback: '操作失败,请稍后重试',
32
+ }
33
+
34
+ /** 事件回调里 useI18n 不可靠,经 nuxt app 取 $i18n;任何失败静默回退内置文案 */
35
+ function tt(key: string): string | null {
36
+ try {
37
+ const nuxt = useNuxtApp()
38
+ const i18n = (nuxt as { $i18n?: { t?: (k: string) => string } }).$i18n
39
+ const v = i18n?.t?.(key)
40
+ return typeof v === 'string' && v && !v.startsWith('errors.') ? v : null
41
+ }
42
+ catch {
43
+ return null
44
+ }
45
+ }
46
+
47
+ function statusKey(status: number): keyof typeof FALLBACK | null {
48
+ if (status === 400) return 'http400'
49
+ if (status === 401) return 'http401'
50
+ if (status === 403) return 'http403'
51
+ if (status === 404) return 'http404'
52
+ if (status === 409) return 'http409'
53
+ if (status >= 500) return 'http5xx'
54
+ return null
55
+ }
56
+
57
+ export function apiErrorMessage(err: unknown, fallback?: string): string {
58
+ const e = (err ?? {}) as ErrLike
59
+ // 1. 服务端信封(ofetch: err.data = {code,message};axios: err.response.data)
60
+ const data = (e.data ?? null) as { message?: unknown } | null
61
+ if (data && typeof data.message === 'string' && data.message.trim()) return data.message.trim()
62
+ // 2. HTTP 状态码 → 本地化映射
63
+ const status = Number(e.statusCode ?? e.status ?? 0)
64
+ const key = statusKey(status)
65
+ if (key) return tt(`errors.${key}`) ?? FALLBACK[key]
66
+ // 3. 网络层失败(fetch failed / ECONNREFUSED / 超时)
67
+ const raw = String(e.message ?? '')
68
+ if (/fetch failed|network|ECONNREFUSED|ENOTFOUND|ECONNRESET|aborted|timeout/i.test(raw)) {
69
+ return tt('errors.network') ?? FALLBACK.network
70
+ }
71
+ // 4. 原始 message 兜底(裸 Error 等通常已可读;剥掉 "Error: " 前缀)
72
+ const cleaned = raw.replace(/^Error:\s*/, '').trim()
73
+ if (cleaned) return cleaned
74
+ return fallback ?? tt('errors.fallback') ?? FALLBACK.fallback
75
+ }
@@ -158,8 +158,8 @@ function findPluginDir(ctx, name) {
158
158
 
159
159
  function scopes(ctx) {
160
160
  return [
161
- { scope: 'project', dir: ctx.root ? join(ctx.root, '.AgentWorkShop', 'plugins') : null, label: '项目级' },
162
- { scope: 'user', dir: ctx.commandsDir?.global ? join(ctx.home, 'plugins') : join(ctx.home, 'plugins'), label: '用户级' },
161
+ { scope: 'project', dir: ctx.root ? join(ctx.root, '.AgentWorkShop', 'plugins') : null, label: '内置示例' },
162
+ { scope: 'user', dir: ctx.commandsDir?.global ? join(ctx.home, 'plugins') : join(ctx.home, 'plugins'), label: '用户级扩展' },
163
163
  ]
164
164
  }
165
165
 
package/config.yml CHANGED
@@ -10,7 +10,7 @@
10
10
  app:
11
11
  name: AgentWorkShop
12
12
  title: AgentWorkShop
13
- version: 0.7.8
13
+ version: 0.7.9
14
14
  description: 基于 Nuxt 4 的配置驱动运行范式
15
15
 
16
16
  # 运行模式(dev/prod 实际由启动命令决定,此处仅作运行时展示)
@@ -1872,12 +1872,15 @@ export default {
1872
1872
  },
1873
1873
  plugins: {
1874
1874
  title: 'Plugins',
1875
- subtitle: 'Config-root plugins/ · toggles hot-reload instantly',
1875
+ subtitle: 'Built-in samples & user extensions · toggles hot-reload instantly',
1876
1876
  refresh: 'Refresh',
1877
1877
  enabled: 'Enabled',
1878
1878
  disabled: 'Disabled',
1879
- scopeProject: 'Project',
1880
- scopeUser: 'User',
1879
+ scopeProject: 'Built-in sample',
1880
+ scopeUser: 'User extension',
1881
+ scopeBuiltinHint: 'Built-in sample plugin: shipped with the project checkout (repo .AgentWorkShop/plugins), can be toggled',
1882
+ scopeUserHint: 'User extension plugin: lives in ~/.AgentWorkShop/plugins, created and maintained by you',
1883
+ loadFail: 'Failed to load plugin list',
1881
1884
  hasClient: 'Client enhancer',
1882
1885
  routes: 'API routes',
1883
1886
  empty: 'No plugins yet — aw plugin create <name>, or aw plugin enable to turn on examples',
@@ -1886,6 +1889,16 @@ export default {
1886
1889
  enableFail: 'Toggle failed',
1887
1890
  detail: 'Plugin detail',
1888
1891
  },
1892
+ errors: {
1893
+ http400: 'Invalid request, please check and retry',
1894
+ http401: 'Session expired, please sign in again',
1895
+ http403: 'Insufficient permission: this action requires an administrator',
1896
+ http404: 'Target not found or already removed',
1897
+ http409: 'Conflict: resource already exists or state does not allow it',
1898
+ http5xx: 'Server error, please retry later',
1899
+ network: 'Cannot reach the server, check network and service status',
1900
+ fallback: 'Action failed, please retry later',
1901
+ },
1889
1902
  error: {
1890
1903
  backHome: 'Back to Home',
1891
1904
  lost: 'Page lost',
@@ -1871,12 +1871,15 @@ export default {
1871
1871
  },
1872
1872
  plugins: {
1873
1873
  title: '插件管理',
1874
- subtitle: '配置根 plugins/ 目录 · 启停即时热重载',
1874
+ subtitle: '内置示例与用户级扩展插件 · 启停即时热重载',
1875
1875
  refresh: '刷新',
1876
1876
  enabled: '已启用',
1877
1877
  disabled: '已停用',
1878
- scopeProject: '项目级',
1879
- scopeUser: '用户级',
1878
+ scopeProject: '内置示例',
1879
+ scopeUser: '用户级扩展',
1880
+ scopeBuiltinHint: '内置示例插件:随项目检出提供(仓库 .AgentWorkShop/plugins),可启停',
1881
+ scopeUserHint: '用户级扩展插件:位于 ~/.AgentWorkShop/plugins,由使用者自行创建维护',
1882
+ loadFail: '插件列表加载失败',
1880
1883
  hasClient: '浏览器增强',
1881
1884
  routes: 'API 路由',
1882
1885
  empty: '暂无插件 —— aw plugin create <name> 创建,或 aw plugin enable 开启示例',
@@ -1885,6 +1888,16 @@ export default {
1885
1888
  enableFail: '启停操作失败',
1886
1889
  detail: '插件详情',
1887
1890
  },
1891
+ errors: {
1892
+ http400: '请求参数有误,请检查后重试',
1893
+ http401: '登录已过期,请重新登录',
1894
+ http403: '权限不足:该操作需要管理员权限',
1895
+ http404: '目标不存在或已被删除',
1896
+ http409: '操作冲突:资源已存在或状态不允许',
1897
+ http5xx: '服务器内部错误,请稍后重试',
1898
+ network: '无法连接服务器,请检查网络与服务状态',
1899
+ fallback: '操作失败,请稍后重试',
1900
+ },
1888
1901
  error: {
1889
1902
  backHome: '返回首页',
1890
1903
  lost: '页面走失了',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentworkshop",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "type": "module",
5
5
  "description": "AgentWorkShop 软件开发系统 - 基于 Nuxt 4 的配置驱动运行范式",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
@@ -37,15 +37,19 @@ async function main() {
37
37
  const reg = await api('POST', '/api/users/register', { body: { email: `cfg-${Date.now().toString(36)}@test.local`, password: 'Passw0rd!123', name: `cfg-${Date.now().toString(36)}` } })
38
38
  const token = reg.data?.token
39
39
  if (!token) throw new Error('注册失败')
40
- // 设置修改需 admin:读取种子凭据存档(.AgentWorkShop/data/seed-credentials.txt)
40
+ // 设置修改需 admin:凭据存档支持两种格式 —— 旧版「password: <pw>」(zhangwei@awshop.io)
41
+ // 与新版「admin@awshop.local / <pw>」(首注册自注册制);env AW_ADMIN_PW 可直接覆盖
41
42
  const fs = await import('node:fs')
42
43
  let adminToken = token
43
44
  try {
44
45
  const cred = fs.readFileSync('.AgentWorkShop/data/seed-credentials.txt', 'utf-8')
45
- const pw = cred.match(/password:\s*(\S+)/)?.[1]
46
- const lg = await api('POST', '/api/users/login', { body: { email: 'zhangwei@awshop.io', password: pw } })
46
+ const legacyPw = cred.match(/password:\s*(\S+)/)?.[1]
47
+ const newFmt = cred.match(/admin@awshop\.local\s*\/\s*(\S+)/)
48
+ const email = legacyPw && !newFmt ? 'zhangwei@awshop.io' : 'admin@awshop.local'
49
+ const pw = process.env.AW_ADMIN_PW ?? (legacyPw && !newFmt ? legacyPw : newFmt?.[1])
50
+ const lg = await api('POST', '/api/users/login', { body: { email, password: pw } })
47
51
  adminToken = lg.data?.token ?? token
48
- console.log(` [setup] admin 登录: ${lg.data?.token ? 'ok' : '失败(回退 user token)'}`)
52
+ console.log(` [setup] admin 登录(${email}): ${lg.data?.token ? 'ok' : '失败(回退 user token)'}`)
49
53
  }
50
54
  catch {
51
55
  console.log(' [setup] 无种子凭据存档,回退 user token')
@@ -92,8 +96,15 @@ async function main() {
92
96
  check('C4.2', 'samples 传 500 → 钳到 minBucketMs=800', q2.data?.bucketMs === 800, `bucketMs=${q2.data?.bucketMs}`)
93
97
  const lq = await api('GET', `/api/workshop/dcw/line/query?lineId=${line.id}`, { token })
94
98
  const lpts = lq.data?.channels?.[0]?.points ?? []
95
- const gaps = lpts.slice(1).map((p, i) => p.at - lpts[i].at)
96
- check('C4.3', '产线查询桶距 ≈3000ms(3000±400)', gaps.length > 0 && gaps.every(g => Math.abs(g - 3000) <= 400), `gaps=${gaps.slice(0, 4).join(',')}`)
99
+ // 桶宽生效的数学证据:同一 time_bucket 调用产出的桶必然落在同一网格,
100
+ // 任意两点差 = 桶宽整数倍(±2ms 浮点尾差);跨网格点会破坏该性质
101
+ const B = 3000
102
+ let mult = true
103
+ for (let i = 1; i < lpts.length && mult; i++) {
104
+ const d = lpts[i].at - lpts[0].at
105
+ if (Math.abs(d / B - Math.round(d / B)) * B > 2) mult = false
106
+ }
107
+ check('C4.3', `产线查询桶间距均为 ${B}ms 整数倍(同网格)`, lpts.length > 1 && mult, `pts=${lpts.length} firstDiff=${lpts.length > 1 ? (lpts[1].at - lpts[0].at).toFixed(1) : '-'}`)
97
108
 
98
109
  // ── C5 CLI 同源(直接写 runtime-settings.json + reload API 模拟 aw config set 的收敛点) ──
99
110
  const rl = await api('POST', '/api/system/settings/reload', { body: {}, token })