agentworkshop 0.2.1

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 (895) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +631 -0
  2. package/.AgentWorkShop/prompts/lead-supervise.md +42 -0
  3. package/.AgentWorkShop/prompts/mode-goal.md +26 -0
  4. package/.AgentWorkShop/prompts/mode-loop.md +10 -0
  5. package/.AgentWorkShop/prompts/mode-pipeline.md +16 -0
  6. package/.AgentWorkShop/prompts/peer-lead-roster.md +3 -0
  7. package/.AgentWorkShop/prompts/peer-message.md +14 -0
  8. package/.AgentWorkShop/prompts/peer-reply-optional.md +2 -0
  9. package/.AgentWorkShop/prompts/peer-reply-required.md +8 -0
  10. package/.AgentWorkShop/prompts/scenario-default.md +11 -0
  11. package/.AgentWorkShop/prompts/system-manual.md +18 -0
  12. package/.AgentWorkShop/prompts/team-roster.md +9 -0
  13. package/.AgentWorkShop/prompts/worker-workflow.md +19 -0
  14. package/.env.example +34 -0
  15. package/README-zh.md +424 -0
  16. package/README.md +424 -0
  17. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.json +1 -0
  18. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/1459e6269990a5d229b9228c8b2f62ffaa7d350068380ae8b875fee0db45cca6.source +180 -0
  19. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/c2991e909c70c5c12b90a407c7adcf63384c51668a2b334e6e047fa675c268fe.source +305 -0
  20. package/app/.mimosa/hook-state/sess_05189059-e42d-4188-8911-4f7baabe009b.mtg0vz68-49792-75b0709555.baseline/e09129039d1e27e3fac24becc9bdafd2d1a7c8049bff24173df007be865f0165.source +264 -0
  21. package/app/.mimosa/hook-status/sess_05189059-e42d-4188-8911-4f7baabe009b-28ef7c75ea.json +14 -0
  22. package/app/app.vue +139 -0
  23. package/app/assets/css/main.css +1257 -0
  24. package/app/components/AppHeader.vue +675 -0
  25. package/app/components/AppSidebar.vue +286 -0
  26. package/app/components/AwChart.vue +44 -0
  27. package/app/components/AwLogo.vue +75 -0
  28. package/app/components/workshop/A2aRpcDebugger.vue +237 -0
  29. package/app/components/workshop/AgentInspectorDrawer.vue +424 -0
  30. package/app/components/workshop/AgentLanesView.vue +947 -0
  31. package/app/components/workshop/ArtifactCard.vue +120 -0
  32. package/app/components/workshop/AssetLibrary.vue +450 -0
  33. package/app/components/workshop/ChannelSessionList.vue +593 -0
  34. package/app/components/workshop/CommandPalette.vue +270 -0
  35. package/app/components/workshop/Composer.vue +731 -0
  36. package/app/components/workshop/DeviceTwinPanel.vue +607 -0
  37. package/app/components/workshop/EventBlock.vue +602 -0
  38. package/app/components/workshop/FileSelectorModal.vue +188 -0
  39. package/app/components/workshop/InspectorPanel.vue +265 -0
  40. package/app/components/workshop/LiveAgentBar.vue +362 -0
  41. package/app/components/workshop/MemoryPanel.vue +364 -0
  42. package/app/components/workshop/MentionHoverCard.vue +155 -0
  43. package/app/components/workshop/MultiChannelView.vue +189 -0
  44. package/app/components/workshop/PaneSplitter.vue +142 -0
  45. package/app/components/workshop/StatsPanel.vue +168 -0
  46. package/app/components/workshop/TaskBoardView.vue +636 -0
  47. package/app/components/workshop/TaskInspectorDrawer.vue +390 -0
  48. package/app/components/workshop/TranscriptTimeline.vue +545 -0
  49. package/app/components/workshop/blocks/ClusterArtifact.vue +77 -0
  50. package/app/components/workshop/blocks/ClusterError.vue +85 -0
  51. package/app/components/workshop/blocks/ClusterLife.vue +87 -0
  52. package/app/components/workshop/blocks/ClusterMember.vue +93 -0
  53. package/app/components/workshop/blocks/ClusterMemory.vue +84 -0
  54. package/app/components/workshop/blocks/ClusterOther.vue +67 -0
  55. package/app/components/workshop/blocks/ClusterRoute.vue +359 -0
  56. package/app/components/workshop/blocks/ClusterStatus.vue +147 -0
  57. package/app/components/workshop/blocks/ClusterStream.vue +325 -0
  58. package/app/components/workshop/blocks/ClusterTask.vue +151 -0
  59. package/app/components/workshop/blocks/ClusterTool.vue +158 -0
  60. package/app/components/workshop/lanes/LaneBlocks.vue +149 -0
  61. package/app/components/workshop/terminal/OmpTerminalPanel.vue +1010 -0
  62. package/app/components/workshop/town/ModelPreview3D.vue +276 -0
  63. package/app/components/workshop/town/TownScene.ts +1355 -0
  64. package/app/components/workshop/town/TownScene3D.ts +4533 -0
  65. package/app/components/workshop/town/TownView.vue +7071 -0
  66. package/app/composables/useCodeCopy.ts +30 -0
  67. package/app/composables/useHttp.ts +8 -0
  68. package/app/composables/useRouteMeta.ts +50 -0
  69. package/app/composables/useSiteConfig.ts +21 -0
  70. package/app/composables/workshop/apiClient.ts +95 -0
  71. package/app/composables/workshop/useCharacterAssets.ts +292 -0
  72. package/app/composables/workshop/useClusteredBlocks.ts +150 -0
  73. package/app/composables/workshop/useComposerBus.ts +16 -0
  74. package/app/composables/workshop/useDaqStream.ts +379 -0
  75. package/app/composables/workshop/useDcwStream.ts +300 -0
  76. package/app/composables/workshop/useDeviceTwins.ts +147 -0
  77. package/app/composables/workshop/useEventBlocks.ts +662 -0
  78. package/app/composables/workshop/useLocalTime.ts +33 -0
  79. package/app/composables/workshop/useOpsLog.ts +164 -0
  80. package/app/composables/workshop/useSceneLayouts.ts +166 -0
  81. package/app/composables/workshop/useTownBus.ts +47 -0
  82. package/app/composables/workshop/useVisibleInterval.ts +42 -0
  83. package/app/composables/workshop/useWorkshopApi.ts +224 -0
  84. package/app/composables/workshop/useWorkshopWs.ts +113 -0
  85. package/app/config/index.ts +66 -0
  86. package/app/config/schema.ts +68 -0
  87. package/app/error.vue +76 -0
  88. package/app/layouts/default.vue +100 -0
  89. package/app/layouts/town.vue +16 -0
  90. package/app/pages/daq/[id].vue +796 -0
  91. package/app/pages/daq/index.vue +2577 -0
  92. package/app/pages/dcw/[id].vue +2259 -0
  93. package/app/pages/dcw/index.vue +1079 -0
  94. package/app/pages/index.vue +830 -0
  95. package/app/pages/logs/index.vue +621 -0
  96. package/app/pages/monitor.vue +665 -0
  97. package/app/pages/settings.vue +757 -0
  98. package/app/pages/tokens.vue +610 -0
  99. package/app/pages/town.vue +145 -0
  100. package/app/pages/users.vue +257 -0
  101. package/app/pages/workshop/agents.vue +382 -0
  102. package/app/pages/workshop/channel-templates.vue +456 -0
  103. package/app/pages/workshop/index.vue +604 -0
  104. package/app/pages/workshop/teams.vue +448 -0
  105. package/app/pages/workshop/w/[wsId].vue +516 -0
  106. package/app/plugins/http.ts +71 -0
  107. package/app/plugins/locale-restore.client.ts +13 -0
  108. package/app/plugins/runtime-config.client.ts +65 -0
  109. package/app/plugins/session-restore.client.ts +24 -0
  110. package/app/plugins/theme.client.ts +15 -0
  111. package/app/stores/app.ts +32 -0
  112. package/app/stores/route-trail.ts +45 -0
  113. package/app/stores/runtime-config.ts +212 -0
  114. package/app/stores/workshop/connection.ts +184 -0
  115. package/app/stores/workshop/entities.ts +350 -0
  116. package/app/stores/workshop/events.ts +292 -0
  117. package/app/stores/workshop/user.ts +176 -0
  118. package/app/stores/workshop/workspaces.ts +133 -0
  119. package/bin/aw.mjs +13 -0
  120. package/cli/aw.mjs +184 -0
  121. package/cli/commands/build.mjs +33 -0
  122. package/cli/commands/config.mjs +157 -0
  123. package/cli/commands/dev.mjs +74 -0
  124. package/cli/commands/doctor.mjs +120 -0
  125. package/cli/commands/home.mjs +75 -0
  126. package/cli/commands/init.mjs +150 -0
  127. package/cli/commands/register.mjs +123 -0
  128. package/cli/commands/start.mjs +106 -0
  129. package/cli/commands/status.mjs +67 -0
  130. package/cli/commands/update.mjs +116 -0
  131. package/cli/commands/version.mjs +32 -0
  132. package/cli/core/args.mjs +95 -0
  133. package/cli/core/context.mjs +264 -0
  134. package/cli/core/errors.mjs +18 -0
  135. package/cli/core/help.mjs +68 -0
  136. package/cli/core/logger.mjs +40 -0
  137. package/cli/core/registry.mjs +111 -0
  138. package/config.yml +70 -0
  139. package/docker-compose.yml +34 -0
  140. package/docs/cli.md +220 -0
  141. package/i18n/dicts/_en.json +1097 -0
  142. package/i18n/dicts/_en2.json +300 -0
  143. package/i18n/dicts/_en3.json +102 -0
  144. package/i18n/dicts/_en4.json +115 -0
  145. package/i18n/dicts/_en5.json +33 -0
  146. package/i18n/dicts/a2aRpcDebugger.json +10 -0
  147. package/i18n/dicts/agentInspectorDrawer.json +25 -0
  148. package/i18n/dicts/agentLanesView.json +57 -0
  149. package/i18n/dicts/agents.json +27 -0
  150. package/i18n/dicts/appHeader.json +7 -0
  151. package/i18n/dicts/appSidebar.json +1 -0
  152. package/i18n/dicts/artifactCard.json +6 -0
  153. package/i18n/dicts/assetLibrary.json +18 -0
  154. package/i18n/dicts/awChart.json +1 -0
  155. package/i18n/dicts/awLogo.json +1 -0
  156. package/i18n/dicts/channelSessionList.json +45 -0
  157. package/i18n/dicts/clusterArtifact.json +4 -0
  158. package/i18n/dicts/clusterError.json +3 -0
  159. package/i18n/dicts/clusterLife.json +5 -0
  160. package/i18n/dicts/clusterMember.json +3 -0
  161. package/i18n/dicts/clusterMemory.json +3 -0
  162. package/i18n/dicts/clusterOther.json +3 -0
  163. package/i18n/dicts/clusterRoute.json +15 -0
  164. package/i18n/dicts/clusterStatus.json +3 -0
  165. package/i18n/dicts/clusterStream.json +3 -0
  166. package/i18n/dicts/clusterTask.json +10 -0
  167. package/i18n/dicts/clusterTool.json +3 -0
  168. package/i18n/dicts/commandPalette.json +16 -0
  169. package/i18n/dicts/composer.json +38 -0
  170. package/i18n/dicts/ctpl.json +32 -0
  171. package/i18n/dicts/daq.json +157 -0
  172. package/i18n/dicts/daqDetail.json +55 -0
  173. package/i18n/dicts/dcw.json +68 -0
  174. package/i18n/dicts/dcwDetail.json +199 -0
  175. package/i18n/dicts/deviceTwinPanel.json +12 -0
  176. package/i18n/dicts/eventBlock.json +8 -0
  177. package/i18n/dicts/fileSelectorModal.json +6 -0
  178. package/i18n/dicts/inspectorPanel.json +12 -0
  179. package/i18n/dicts/laneBlocks.json +6 -0
  180. package/i18n/dicts/liveAgentBar.json +8 -0
  181. package/i18n/dicts/logs.json +39 -0
  182. package/i18n/dicts/memoryPanel.json +20 -0
  183. package/i18n/dicts/mentionHoverCard.json +4 -0
  184. package/i18n/dicts/modelPreview3D.json +1 -0
  185. package/i18n/dicts/monitor.json +5 -0
  186. package/i18n/dicts/multiChannelView.json +13 -0
  187. package/i18n/dicts/ompTerminalPanel.json +7 -0
  188. package/i18n/dicts/paneSplitter.json +3 -0
  189. package/i18n/dicts/settings.json +1 -0
  190. package/i18n/dicts/statsPanel.json +6 -0
  191. package/i18n/dicts/taskBoardView.json +22 -0
  192. package/i18n/dicts/taskInspectorDrawer.json +19 -0
  193. package/i18n/dicts/teams.json +33 -0
  194. package/i18n/dicts/tokens.json +30 -0
  195. package/i18n/dicts/town.json +7 -0
  196. package/i18n/dicts/townView.json +209 -0
  197. package/i18n/dicts/transcriptTimeline.json +31 -0
  198. package/i18n/dicts/users.json +15 -0
  199. package/i18n/dicts/wsHome.json +33 -0
  200. package/i18n/dicts/wsView.json +15 -0
  201. package/i18n/locales/en.ts +1737 -0
  202. package/i18n/locales/zh-CN.ts +1736 -0
  203. package/nuxt.config.ts +209 -0
  204. package/package.json +123 -0
  205. package/public/assets/game/character/bot.png +0 -0
  206. package/public/assets/game/character/device-3d.glb +0 -0
  207. package/public/assets/game/character/hero-3d.glb +0 -0
  208. package/public/assets/game/character/hero-anime-1.glb +0 -0
  209. package/public/assets/game/character/hero-anime-2.glb +0 -0
  210. package/public/assets/game/character/hero-anime-3.glb +0 -0
  211. package/public/assets/game/character/hero-anime-4.glb +0 -0
  212. package/public/assets/game/character/knight.png +0 -0
  213. package/public/assets/game/character/mage.png +0 -0
  214. package/public/assets/game/coin.png +0 -0
  215. package/public/assets/game/devices/agv.glb +0 -0
  216. package/public/assets/game/devices/caster.glb +0 -0
  217. package/public/assets/game/devices/device-console.glb +0 -0
  218. package/public/assets/game/devices/device-robot-arm.glb +0 -0
  219. package/public/assets/game/devices/device-scanner.glb +0 -0
  220. package/public/assets/game/devices/extruder.glb +0 -0
  221. package/public/assets/game/devices/mdo.glb +0 -0
  222. package/public/assets/game/devices/power-cabinet.glb +0 -0
  223. package/public/assets/game/devices/pump.glb +0 -0
  224. package/public/assets/game/devices/tdo.glb +0 -0
  225. package/public/assets/game/devices/thickness-scanner.glb +0 -0
  226. package/public/assets/game/devices/winder.glb +0 -0
  227. package/public/assets/game/npc/boltnu-sheet.png +0 -0
  228. package/public/assets/game/npc/fluttaflap-sheet.png +0 -0
  229. package/public/assets/game/npc/rockitten-sheet.png +0 -0
  230. package/public/assets/game/npc/tux-sheet.png +0 -0
  231. package/public/assets/game/player/misa-back-walk.000.png +0 -0
  232. package/public/assets/game/player/misa-back-walk.001.png +0 -0
  233. package/public/assets/game/player/misa-back-walk.002.png +0 -0
  234. package/public/assets/game/player/misa-back-walk.003.png +0 -0
  235. package/public/assets/game/player/misa-back.png +0 -0
  236. package/public/assets/game/player/misa-front-walk.000.png +0 -0
  237. package/public/assets/game/player/misa-front-walk.001.png +0 -0
  238. package/public/assets/game/player/misa-front-walk.002.png +0 -0
  239. package/public/assets/game/player/misa-front-walk.003.png +0 -0
  240. package/public/assets/game/player/misa-front.png +0 -0
  241. package/public/assets/game/player/misa-left-walk.000.png +0 -0
  242. package/public/assets/game/player/misa-left-walk.001.png +0 -0
  243. package/public/assets/game/player/misa-left-walk.002.png +0 -0
  244. package/public/assets/game/player/misa-left-walk.003.png +0 -0
  245. package/public/assets/game/player/misa-left.png +0 -0
  246. package/public/assets/game/player/misa-right-walk.000.png +0 -0
  247. package/public/assets/game/player/misa-right-walk.001.png +0 -0
  248. package/public/assets/game/player/misa-right-walk.002.png +0 -0
  249. package/public/assets/game/player/misa-right-walk.003.png +0 -0
  250. package/public/assets/game/player/misa-right.png +0 -0
  251. package/public/assets/game/player-sheet.png +0 -0
  252. package/public/assets/game/tuxemon-town.json +1 -0
  253. package/public/assets/game/tuxmon-sample-32px-extruded.png +0 -0
  254. package/public/assets/game/wuwa/scene-map.png +0 -0
  255. package/public/assets/game/wuwa/world-far.png +0 -0
  256. package/public/assets/game/wuwa/world-middle.png +0 -0
  257. package/public/assets/game/wuwa/world-near.png +0 -0
  258. package/public/assets/game/wuwa/wu-aura.png +0 -0
  259. package/public/assets/game/wuwa/wu-lead.png +0 -0
  260. package/public/assets/game/wuwa/wu-ring.png +0 -0
  261. package/public/assets/game/wuwa/wu-slash.png +0 -0
  262. package/public/assets/game/wuwa/wu-worker-0.png +0 -0
  263. package/public/assets/game/wuwa/wu-worker-1.png +0 -0
  264. package/public/assets/game/wuwa/wu-worker-2.png +0 -0
  265. package/public/favicon.svg +14 -0
  266. package/public/scene/background/cyber-town-background.svg +110 -0
  267. package/scripts/_daq-realtime-probe.mjs +68 -0
  268. package/scripts/_daq-warn-probe.mjs +50 -0
  269. package/scripts/_dbg-agent-tools-audit.mjs +154 -0
  270. package/scripts/_dbg-agent-workflow-audit.mjs +177 -0
  271. package/scripts/_dbg-anim-verify.mjs +81 -0
  272. package/scripts/_dbg-audit-all-pages.mjs +43 -0
  273. package/scripts/_dbg-autoframe.mjs +103 -0
  274. package/scripts/_dbg-beacon-final.mjs +181 -0
  275. package/scripts/_dbg-bind-bidi-e2e.mjs +239 -0
  276. package/scripts/_dbg-callout-near.mjs +108 -0
  277. package/scripts/_dbg-chan-focus.mjs +49 -0
  278. package/scripts/_dbg-cleanup.mjs +31 -0
  279. package/scripts/_dbg-closedloop-ui-shot.mjs +61 -0
  280. package/scripts/_dbg-console-audit.mjs +61 -0
  281. package/scripts/_dbg-console-probe.mjs +23 -0
  282. package/scripts/_dbg-context-inject-audit.mjs +231 -0
  283. package/scripts/_dbg-crash-recovery.mjs +143 -0
  284. package/scripts/_dbg-crop-shot.mjs +16 -0
  285. package/scripts/_dbg-daq-acc-probe.mjs +24 -0
  286. package/scripts/_dbg-daq-attrib.mjs +34 -0
  287. package/scripts/_dbg-daq-bind-audit.mjs +119 -0
  288. package/scripts/_dbg-daq-cadence.mjs +104 -0
  289. package/scripts/_dbg-daq-debug.mjs +22 -0
  290. package/scripts/_dbg-daq-diag.mjs +33 -0
  291. package/scripts/_dbg-daq-e2e.mjs +171 -0
  292. package/scripts/_dbg-daq-film.mjs +136 -0
  293. package/scripts/_dbg-daq-filter-e2e.mjs +109 -0
  294. package/scripts/_dbg-daq-filter-e2e2.mjs +62 -0
  295. package/scripts/_dbg-daq-final-regression.mjs +78 -0
  296. package/scripts/_dbg-daq-full-check.mjs +179 -0
  297. package/scripts/_dbg-daq-line-note-verify.mjs +61 -0
  298. package/scripts/_dbg-daq-linebanner-audit.mjs +107 -0
  299. package/scripts/_dbg-daq-pages-shot.mjs +37 -0
  300. package/scripts/_dbg-daq-perf.mjs +61 -0
  301. package/scripts/_dbg-daq-probe.mjs +27 -0
  302. package/scripts/_dbg-daq-recipe-e2e.mjs +30 -0
  303. package/scripts/_dbg-daq-redesign-shot.mjs +88 -0
  304. package/scripts/_dbg-daq-rows-probe.mjs +26 -0
  305. package/scripts/_dbg-daq-rowstate-e2e.mjs +152 -0
  306. package/scripts/_dbg-daq-rowstate-shot.mjs +45 -0
  307. package/scripts/_dbg-daq-rowstate-shot2.mjs +38 -0
  308. package/scripts/_dbg-daq-tpl.mjs +144 -0
  309. package/scripts/_dbg-dash-console-check.mjs +49 -0
  310. package/scripts/_dbg-dash-deep-probe.mjs +61 -0
  311. package/scripts/_dbg-dash-hitpoint.mjs +44 -0
  312. package/scripts/_dbg-dash-live-shot.mjs +36 -0
  313. package/scripts/_dbg-dash-shot.mjs +21 -0
  314. package/scripts/_dbg-dashboard-shot.mjs +35 -0
  315. package/scripts/_dbg-dcw-audit.mjs +126 -0
  316. package/scripts/_dbg-dcw-card-e2e.mjs +108 -0
  317. package/scripts/_dbg-dcw-channel-ui.mjs +144 -0
  318. package/scripts/_dbg-dcw-examples.mjs +81 -0
  319. package/scripts/_dbg-dcw-light-shot.mjs +19 -0
  320. package/scripts/_dbg-dcw-line-audit.mjs +107 -0
  321. package/scripts/_dbg-dcw-pause-tpl-audit.mjs +161 -0
  322. package/scripts/_dbg-dcw-pause-ui.mjs +175 -0
  323. package/scripts/_dbg-dcw-scene.mjs +72 -0
  324. package/scripts/_dbg-dcw-shot2.mjs +14 -0
  325. package/scripts/_dbg-dcw-twin-e2e.mjs +192 -0
  326. package/scripts/_dbg-dt-interact.mjs +193 -0
  327. package/scripts/_dbg-error-probe.mjs +54 -0
  328. package/scripts/_dbg-filter-light-verify.mjs +54 -0
  329. package/scripts/_dbg-final-acceptance-2.mjs +72 -0
  330. package/scripts/_dbg-final-acceptance.mjs +192 -0
  331. package/scripts/_dbg-final-agent-e2e.mjs +151 -0
  332. package/scripts/_dbg-final-full-e2e.mjs +218 -0
  333. package/scripts/_dbg-final-line-e2e.mjs +173 -0
  334. package/scripts/_dbg-final-t6-hitl.mjs +38 -0
  335. package/scripts/_dbg-focus-range.mjs +115 -0
  336. package/scripts/_dbg-fresh-scene-e2e.mjs +125 -0
  337. package/scripts/_dbg-full-feature-e2e.mjs +219 -0
  338. package/scripts/_dbg-fullchain-e2e.mjs +178 -0
  339. package/scripts/_dbg-gate-debug.mjs +37 -0
  340. package/scripts/_dbg-gif-encode.mjs +111 -0
  341. package/scripts/_dbg-gizmo.mjs +95 -0
  342. package/scripts/_dbg-glass-probe.mjs +57 -0
  343. package/scripts/_dbg-glass-shot.mjs +50 -0
  344. package/scripts/_dbg-glass-sweep.mjs +25 -0
  345. package/scripts/_dbg-glb-probe.mjs +43 -0
  346. package/scripts/_dbg-hardening-probe.mjs +90 -0
  347. package/scripts/_dbg-hero-btn-probe.mjs +21 -0
  348. package/scripts/_dbg-hidden-check.mjs +21 -0
  349. package/scripts/_dbg-hitl-timeout-e2e.mjs +93 -0
  350. package/scripts/_dbg-hmi-audit.mjs +164 -0
  351. package/scripts/_dbg-home-repro.mjs +24 -0
  352. package/scripts/_dbg-home-stack.mjs +13 -0
  353. package/scripts/_dbg-huashu-survey.mjs +31 -0
  354. package/scripts/_dbg-huashu-survey2.mjs +35 -0
  355. package/scripts/_dbg-huashu-verify.mjs +25 -0
  356. package/scripts/_dbg-huashu-verify2.mjs +26 -0
  357. package/scripts/_dbg-hydration-detail.mjs +18 -0
  358. package/scripts/_dbg-i18n-debug.mjs +27 -0
  359. package/scripts/_dbg-i18n-debug2.mjs +26 -0
  360. package/scripts/_dbg-i18n-final.mjs +42 -0
  361. package/scripts/_dbg-i18n-scan.mjs +38 -0
  362. package/scripts/_dbg-infra-lifecycle.mjs +44 -0
  363. package/scripts/_dbg-line-aura-shots.mjs +54 -0
  364. package/scripts/_dbg-line-control-e2e.mjs +120 -0
  365. package/scripts/_dbg-line-gate-audit.mjs +108 -0
  366. package/scripts/_dbg-line-live-e2e.mjs +144 -0
  367. package/scripts/_dbg-line-scenario-e2e.mjs +256 -0
  368. package/scripts/_dbg-minimal-omp.mjs +77 -0
  369. package/scripts/_dbg-mode-nav.mjs +173 -0
  370. package/scripts/_dbg-mqtt-chain-e2e.mjs +90 -0
  371. package/scripts/_dbg-nav-rpg.mjs +84 -0
  372. package/scripts/_dbg-nav-shot.mjs +28 -0
  373. package/scripts/_dbg-nav.mjs +27 -0
  374. package/scripts/_dbg-opslog-e2e.mjs +121 -0
  375. package/scripts/_dbg-opslog-shots.mjs +62 -0
  376. package/scripts/_dbg-opt-team-e2e.mjs +133 -0
  377. package/scripts/_dbg-optimization-e2e.mjs +94 -0
  378. package/scripts/_dbg-orbit.mjs +58 -0
  379. package/scripts/_dbg-panesplitter-fix-check.mjs +62 -0
  380. package/scripts/_dbg-phase-e3-monitor.mjs +25 -0
  381. package/scripts/_dbg-pop-clamp-verify.mjs +77 -0
  382. package/scripts/_dbg-preset-e2e.mjs +116 -0
  383. package/scripts/_dbg-preview-console.mjs +28 -0
  384. package/scripts/_dbg-preview-minrepro.mjs +156 -0
  385. package/scripts/_dbg-preview-pixels.mjs +93 -0
  386. package/scripts/_dbg-quality-pages-e2e.mjs +84 -0
  387. package/scripts/_dbg-query-cancel.ts +12 -0
  388. package/scripts/_dbg-rail-tree-e2e.mjs +183 -0
  389. package/scripts/_dbg-real-driver-e2e.mjs +55 -0
  390. package/scripts/_dbg-redesign-shots.mjs +34 -0
  391. package/scripts/_dbg-restart-persist.mjs +41 -0
  392. package/scripts/_dbg-rollback-mgr-audit.mjs +169 -0
  393. package/scripts/_dbg-rpg.mjs +71 -0
  394. package/scripts/_dbg-sc001-dispatch.mjs +63 -0
  395. package/scripts/_dbg-scenario-final-shot.mjs +24 -0
  396. package/scripts/_dbg-scenario-phase-e2.mjs +75 -0
  397. package/scripts/_dbg-scenario-phase-e3.mjs +96 -0
  398. package/scripts/_dbg-scenario-phase1.mjs +90 -0
  399. package/scripts/_dbg-scenario-phase2.mjs +105 -0
  400. package/scripts/_dbg-scenario-phase3-monitor.mjs +48 -0
  401. package/scripts/_dbg-scenario-phase3.mjs +111 -0
  402. package/scripts/_dbg-scene-polish-shot.mjs +118 -0
  403. package/scripts/_dbg-selring-probe.mjs +47 -0
  404. package/scripts/_dbg-sideinfo.mjs +101 -0
  405. package/scripts/_dbg-splitter.mjs +88 -0
  406. package/scripts/_dbg-team-repro.mjs +76 -0
  407. package/scripts/_dbg-town-alarm-e2e.mjs +40 -0
  408. package/scripts/_dbg-town-beauty-shots.mjs +54 -0
  409. package/scripts/_dbg-town-daq-shot.mjs +26 -0
  410. package/scripts/_dbg-town-full-e2e.mjs +104 -0
  411. package/scripts/_dbg-town-gate.mjs +44 -0
  412. package/scripts/_dbg-town-ins-probe.mjs +37 -0
  413. package/scripts/_dbg-town-perf.mjs +50 -0
  414. package/scripts/_dbg-town-polish-shots.mjs +82 -0
  415. package/scripts/_dbg-town-realtime.mjs +42 -0
  416. package/scripts/_dbg-town-shot3.mjs +17 -0
  417. package/scripts/_dbg-town-truth.mjs +37 -0
  418. package/scripts/_dbg-town-truth2.mjs +27 -0
  419. package/scripts/_dbg-transform-audit.mjs +98 -0
  420. package/scripts/_dbg-trend-expand-test.mjs +38 -0
  421. package/scripts/_dbg-twindaq-focus.mjs +81 -0
  422. package/scripts/_dbg-ui-polish-shot.mjs +43 -0
  423. package/scripts/_dbg-ui-polish-verify1.mjs +92 -0
  424. package/scripts/_dbg-ui-polish-verify2.mjs +50 -0
  425. package/scripts/_dbg-ui-polish-verify3.mjs +51 -0
  426. package/scripts/_dbg-ui-polish-verify4.mjs +50 -0
  427. package/scripts/_dbg-ui-shot.mjs +26 -0
  428. package/scripts/_dbg-unify-shot.mjs +43 -0
  429. package/scripts/_dbg-uplink-probe.mjs +36 -0
  430. package/scripts/_dbg-wizard-preview-shot.mjs +58 -0
  431. package/scripts/_dbg-wizard-ui-e2e.mjs +93 -0
  432. package/scripts/_dbg-ws-probe.mjs +86 -0
  433. package/scripts/_dbg-ws-shot2.mjs +23 -0
  434. package/scripts/_dbg-wsdot-sanity.mjs +25 -0
  435. package/scripts/_dev-stack.mjs +46 -0
  436. package/scripts/_http-driver-probe.mjs +30 -0
  437. package/scripts/_lib-dcw-line.mjs +24 -0
  438. package/scripts/_mqtt-driver-probe.mjs +30 -0
  439. package/scripts/_newdriver-rest-probe.mjs +100 -0
  440. package/scripts/_node-state-probe.mjs +5 -0
  441. package/scripts/_opcua-driver-probe.mjs +31 -0
  442. package/scripts/_rtu-debug.mjs +41 -0
  443. package/scripts/_rtu-direct.mjs +6 -0
  444. package/scripts/_rtu-driver-probe.mjs +53 -0
  445. package/scripts/_rtu-mini-slave.mjs +63 -0
  446. package/scripts/_townview_style.css +1185 -0
  447. package/scripts/_townview_template.html +1215 -0
  448. package/scripts/_wizard-shots.mjs +90 -0
  449. package/scripts/acceptance-suite.py +207 -0
  450. package/scripts/api-live-e2e.mjs +467 -0
  451. package/scripts/build-anime-models.mjs +339 -0
  452. package/scripts/build-character-models.mjs +175 -0
  453. package/scripts/build-film-devices.mjs +227 -0
  454. package/scripts/build-model-3d.mjs +173 -0
  455. package/scripts/build-player-sheet.mjs +58 -0
  456. package/scripts/build-world-map.mjs +188 -0
  457. package/scripts/build-wuwa-assets.mjs +345 -0
  458. package/scripts/collab-live-test.py +177 -0
  459. package/scripts/debug-mcp-http.ts +64 -0
  460. package/scripts/demo-lead-worker.ts +256 -0
  461. package/scripts/demo-modes.ts +415 -0
  462. package/scripts/demo-omp-channel.ts +135 -0
  463. package/scripts/design-preflight.mjs +223 -0
  464. package/scripts/design-verify-templates.mjs +110 -0
  465. package/scripts/design-verify.mjs +170 -0
  466. package/scripts/dev-guard.mjs +74 -0
  467. package/scripts/dev-modbus-simulator.mjs +55 -0
  468. package/scripts/dev-opcua-simulator.mjs +57 -0
  469. package/scripts/dev-protocol-simulators.mjs +145 -0
  470. package/scripts/dev-window.cmd +6 -0
  471. package/scripts/device-line-restore.mjs +34 -0
  472. package/scripts/diag-lead-status.ts +101 -0
  473. package/scripts/e2e-a2a-steer-live.mjs +193 -0
  474. package/scripts/e2e-agent-channel-task.ts +151 -0
  475. package/scripts/e2e-agent-team.mjs +168 -0
  476. package/scripts/e2e-auth-matrix.mjs +119 -0
  477. package/scripts/e2e-channel-isolation.ts +325 -0
  478. package/scripts/e2e-dual-drive-comm.ts +259 -0
  479. package/scripts/e2e-lead-team-mgmt.ts +217 -0
  480. package/scripts/e2e-memory-persistence.ts +320 -0
  481. package/scripts/e2e-memory-system.ts +332 -0
  482. package/scripts/e2e-omp-modes.ts +274 -0
  483. package/scripts/e2e-omp-realtime.ts +258 -0
  484. package/scripts/e2e-omp-workspace.ts +180 -0
  485. package/scripts/e2e-parallel-execution.mjs +151 -0
  486. package/scripts/e2e-rest-memory.mjs +251 -0
  487. package/scripts/e2e-rest-robustness.mjs +177 -0
  488. package/scripts/e2e-resume-crash.mjs +254 -0
  489. package/scripts/e2e-tab-close.mjs +136 -0
  490. package/scripts/e2e-task-queue.ts +277 -0
  491. package/scripts/e2e-template-isolation.mjs +267 -0
  492. package/scripts/e2e-token-ui.mjs +149 -0
  493. package/scripts/final-soup-run.py +192 -0
  494. package/scripts/final-soup-watch.py +83 -0
  495. package/scripts/home-bootstrap.mjs +117 -0
  496. package/scripts/i18n-codemod.mjs +173 -0
  497. package/scripts/i18n-fix-en.py +28 -0
  498. package/scripts/i18n-fix-en2.py +31 -0
  499. package/scripts/i18n-merge.mjs +67 -0
  500. package/scripts/omp-real-test.py +328 -0
  501. package/scripts/smoke-optimization-verify.ts +72 -0
  502. package/scripts/start.mjs +60 -0
  503. package/scripts/test-a2a-relay.mjs +222 -0
  504. package/scripts/test-a2a-types.ts +296 -0
  505. package/scripts/test-agent-brain.ts +135 -0
  506. package/scripts/test-agent-multi-channel.ts +160 -0
  507. package/scripts/test-agent-runtime.ts +348 -0
  508. package/scripts/test-api-client.ts +108 -0
  509. package/scripts/test-api-suite.mjs +271 -0
  510. package/scripts/test-block-consumption.mjs +194 -0
  511. package/scripts/test-channel-routing.ts +301 -0
  512. package/scripts/test-cmd-render.mjs +218 -0
  513. package/scripts/test-collab-e2e.mjs +136 -0
  514. package/scripts/test-collab-omp.mjs +192 -0
  515. package/scripts/test-dedup-logic.ts +132 -0
  516. package/scripts/test-dual-drive.ts +227 -0
  517. package/scripts/test-e2e-collaboration.ts +262 -0
  518. package/scripts/test-e2e-monitor.ts +192 -0
  519. package/scripts/test-event-history.ts +112 -0
  520. package/scripts/test-event-persistence.mjs +169 -0
  521. package/scripts/test-exec-modes.ts +316 -0
  522. package/scripts/test-fifo-realtime.mjs +193 -0
  523. package/scripts/test-final-e2e.mjs +290 -0
  524. package/scripts/test-full-system.ts +439 -0
  525. package/scripts/test-game-session.ts +160 -0
  526. package/scripts/test-goal-summary.ts +202 -0
  527. package/scripts/test-harness-liveness.ts +109 -0
  528. package/scripts/test-harness-terminal.ts +164 -0
  529. package/scripts/test-header-trail.mjs +95 -0
  530. package/scripts/test-hitl.ts +360 -0
  531. package/scripts/test-koda-restyle.mjs +105 -0
  532. package/scripts/test-lane-history-live.mjs +103 -0
  533. package/scripts/test-lane-raw.ts +67 -0
  534. package/scripts/test-lanes-history-render.mjs +138 -0
  535. package/scripts/test-loop-omp.mjs +154 -0
  536. package/scripts/test-mcp-tools.ts +285 -0
  537. package/scripts/test-mdlite.ts +53 -0
  538. package/scripts/test-memory-dynamic.ts +99 -0
  539. package/scripts/test-memory-maintenance.ts +117 -0
  540. package/scripts/test-memory-vector.ts +154 -0
  541. package/scripts/test-memory.ts +431 -0
  542. package/scripts/test-mock-collab.mjs +226 -0
  543. package/scripts/test-modern-render.mjs +174 -0
  544. package/scripts/test-omp-terminal.mjs +187 -0
  545. package/scripts/test-orchestration.ts +425 -0
  546. package/scripts/test-persistence-lazy.ts +323 -0
  547. package/scripts/test-prompt-system.mjs +181 -0
  548. package/scripts/test-prompts-loader.ts +56 -0
  549. package/scripts/test-protocol.ts +156 -0
  550. package/scripts/test-real-scenario.mjs +290 -0
  551. package/scripts/test-route-reason.mjs +111 -0
  552. package/scripts/test-scheduler-loop.ts +469 -0
  553. package/scripts/test-stream-render.ts +37 -0
  554. package/scripts/test-task-drawer.mjs +204 -0
  555. package/scripts/test-task-engine.ts +433 -0
  556. package/scripts/test-task-invariants.mjs +169 -0
  557. package/scripts/test-terminal-e2e.mjs +264 -0
  558. package/scripts/test-town-3d.mjs +121 -0
  559. package/scripts/test-town-drag.mjs +218 -0
  560. package/scripts/test-town-layout.mjs +200 -0
  561. package/scripts/test-town-page.mjs +136 -0
  562. package/scripts/test-town-scene-math.ts +169 -0
  563. package/scripts/test-town-twin.mjs +121 -0
  564. package/scripts/test-town-upload.mjs +89 -0
  565. package/scripts/test-town-user-flow.mjs +619 -0
  566. package/scripts/test-town-world.mjs +76 -0
  567. package/scripts/test-town-wuwa.mjs +198 -0
  568. package/scripts/test-user-isolation.mjs +193 -0
  569. package/scripts/test-workshop-db.ts +280 -0
  570. package/scripts/test-workshop-entries.ts +370 -0
  571. package/scripts/test-workspace-api.ts +329 -0
  572. package/scripts/test-ws-aep.mjs +187 -0
  573. package/scripts/test-ws-protocol.ts +134 -0
  574. package/scripts/test-ws-stress.mjs +208 -0
  575. package/scripts/town-demo-seed.mjs +75 -0
  576. package/scripts/town-scene-clear.mjs +56 -0
  577. package/scripts/ui-screenshot.mjs +128 -0
  578. package/scripts/verify-a2a-live.mjs +124 -0
  579. package/scripts/verify-exec-modes-report.ts +248 -0
  580. package/scripts/verify-game.mjs +477 -0
  581. package/scripts/verify-lead-mail.ts +188 -0
  582. package/scripts/verify-page-smoke.mjs +87 -0
  583. package/scripts/verify-ws-events.mjs +123 -0
  584. package/scripts/ws-test.mjs +176 -0
  585. package/scripts/ws-test.py +4 -0
  586. package/server/api/health.get.ts +32 -0
  587. package/server/api/mcp/workshop.ts +78 -0
  588. package/server/api/metrics.ts +75 -0
  589. package/server/api/system/config.get.ts +12 -0
  590. package/server/api/system/monitor/terminal/ws.ts +177 -0
  591. package/server/api/system/monitor/terminate.post.ts +36 -0
  592. package/server/api/system/monitor.get.ts +13 -0
  593. package/server/api/system/settings/events.get.ts +28 -0
  594. package/server/api/system/settings/index.get.ts +14 -0
  595. package/server/api/system/settings/index.patch.ts +22 -0
  596. package/server/api/system/settings/reset.post.ts +12 -0
  597. package/server/api/users/[id].delete.ts +11 -0
  598. package/server/api/users/[id].get.ts +11 -0
  599. package/server/api/users/[id].put.ts +14 -0
  600. package/server/api/users/index.get.ts +13 -0
  601. package/server/api/users/index.post.ts +13 -0
  602. package/server/api/users/login.post.ts +11 -0
  603. package/server/api/users/logout.post.ts +9 -0
  604. package/server/api/users/me.get.ts +9 -0
  605. package/server/api/users/register.post.ts +11 -0
  606. package/server/api/users/tokens/[id]/token.get.ts +11 -0
  607. package/server/api/users/tokens/[id].delete.ts +11 -0
  608. package/server/api/users/tokens/[id].patch.ts +14 -0
  609. package/server/api/users/tokens/index.get.ts +9 -0
  610. package/server/api/users/tokens/index.post.ts +13 -0
  611. package/server/api/workshop/[...path].ts +13 -0
  612. package/server/api/workshop/a2a/[agentId]/card/index.get.ts +75 -0
  613. package/server/api/workshop/a2a/[agentId]/rpc/index.post.ts +429 -0
  614. package/server/api/workshop/a2a/send.post.ts +28 -0
  615. package/server/api/workshop/agent-tools/approvals/[id]/decide.post.ts +21 -0
  616. package/server/api/workshop/agent-tools/approvals/index.get.ts +18 -0
  617. package/server/api/workshop/agent-tools/bindings/[id].delete.ts +21 -0
  618. package/server/api/workshop/agent-tools/bindings/[id].patch.ts +14 -0
  619. package/server/api/workshop/agent-tools/bindings/index.get.ts +14 -0
  620. package/server/api/workshop/agent-tools/bindings/index.post.ts +20 -0
  621. package/server/api/workshop/agent-tools/invoke.post.ts +34 -0
  622. package/server/api/workshop/agents/[id].delete.ts +20 -0
  623. package/server/api/workshop/agents/[id].get.ts +19 -0
  624. package/server/api/workshop/agents/[id].patch.ts +30 -0
  625. package/server/api/workshop/agents/index.get.ts +13 -0
  626. package/server/api/workshop/agents/index.post.ts +29 -0
  627. package/server/api/workshop/agents/subscribe.post.ts +21 -0
  628. package/server/api/workshop/approvals/[id]/decide.post.ts +30 -0
  629. package/server/api/workshop/approvals/index.get.ts +22 -0
  630. package/server/api/workshop/assets/character/[id].delete.ts +33 -0
  631. package/server/api/workshop/assets/character/index.get.ts +17 -0
  632. package/server/api/workshop/assets/character/index.post.ts +87 -0
  633. package/server/api/workshop/assets/devices/[id].delete.ts +43 -0
  634. package/server/api/workshop/assets/devices/index.get.ts +103 -0
  635. package/server/api/workshop/assets/devices/index.post.ts +53 -0
  636. package/server/api/workshop/audit.get.ts +43 -0
  637. package/server/api/workshop/caller.ts +141 -0
  638. package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +31 -0
  639. package/server/api/workshop/channel-templates/[id].delete.ts +20 -0
  640. package/server/api/workshop/channel-templates/[id].get.ts +19 -0
  641. package/server/api/workshop/channel-templates/[id].patch.ts +48 -0
  642. package/server/api/workshop/channel-templates/from-channel.post.ts +31 -0
  643. package/server/api/workshop/channel-templates/index.get.ts +13 -0
  644. package/server/api/workshop/channel-templates/index.post.ts +61 -0
  645. package/server/api/workshop/channels/[id]/activate.post.ts +19 -0
  646. package/server/api/workshop/channels/[id]/agents/[agentId]/memories/[memoryId].delete.ts +30 -0
  647. package/server/api/workshop/channels/[id]/agents/[agentId]/memories/index.get.ts +29 -0
  648. package/server/api/workshop/channels/[id]/agents/[agentId]/memories/index.post.ts +48 -0
  649. package/server/api/workshop/channels/[id]/agents/[agentId]/memories/search.post.ts +43 -0
  650. package/server/api/workshop/channels/[id]/agents/[agentId]/model.patch.ts +39 -0
  651. package/server/api/workshop/channels/[id]/agents/[agentId]/position.patch.ts +33 -0
  652. package/server/api/workshop/channels/[id]/agents/[agentId]/range.patch.ts +54 -0
  653. package/server/api/workshop/channels/[id]/agents/[agentId]/stop.post.ts +25 -0
  654. package/server/api/workshop/channels/[id]/agents/[agentId].delete.ts +23 -0
  655. package/server/api/workshop/channels/[id]/agents/[agentId].patch.ts +28 -0
  656. package/server/api/workshop/channels/[id]/agents/index.get.ts +27 -0
  657. package/server/api/workshop/channels/[id]/agents/index.post.ts +61 -0
  658. package/server/api/workshop/channels/[id]/events.get.ts +55 -0
  659. package/server/api/workshop/channels/[id]/index.get.ts +18 -0
  660. package/server/api/workshop/channels/[id]/index.patch.ts +30 -0
  661. package/server/api/workshop/channels/[id]/memories/[memoryId].delete.ts +29 -0
  662. package/server/api/workshop/channels/[id]/memories/index.get.ts +28 -0
  663. package/server/api/workshop/channels/[id]/memories/index.post.ts +42 -0
  664. package/server/api/workshop/channels/[id]/messages/index.get.ts +56 -0
  665. package/server/api/workshop/channels/[id]/messages/index.post.ts +75 -0
  666. package/server/api/workshop/channels/[id]/queue.get.ts +25 -0
  667. package/server/api/workshop/channels/[id]/tasks/index.get.ts +24 -0
  668. package/server/api/workshop/channels/[id]/tasks/index.post.ts +79 -0
  669. package/server/api/workshop/channels/[id]/terminals.get.ts +21 -0
  670. package/server/api/workshop/channels/[id].delete.ts +18 -0
  671. package/server/api/workshop/channels.get.ts +11 -0
  672. package/server/api/workshop/channels.post.ts +48 -0
  673. package/server/api/workshop/daq/[id]/bind.post.ts +19 -0
  674. package/server/api/workshop/daq/[id]/samples.get.ts +22 -0
  675. package/server/api/workshop/daq/[id]/test.post.ts +17 -0
  676. package/server/api/workshop/daq/[id].delete.ts +30 -0
  677. package/server/api/workshop/daq/[id].patch.ts +31 -0
  678. package/server/api/workshop/daq/alarms/[id]/ack.post.ts +15 -0
  679. package/server/api/workshop/daq/alarms.get.ts +16 -0
  680. package/server/api/workshop/daq/controller.post.ts +52 -0
  681. package/server/api/workshop/daq/index.get.ts +40 -0
  682. package/server/api/workshop/daq/index.post.ts +33 -0
  683. package/server/api/workshop/daq/infra/reconnect.post.ts +17 -0
  684. package/server/api/workshop/daq/infra.get.ts +11 -0
  685. package/server/api/workshop/daq/templates/[key].delete.ts +17 -0
  686. package/server/api/workshop/daq/templates/[key].patch.ts +18 -0
  687. package/server/api/workshop/daq/templates/index.post.ts +17 -0
  688. package/server/api/workshop/daq/test-driver.post.ts +23 -0
  689. package/server/api/workshop/dcw/[id]/bind.post.ts +17 -0
  690. package/server/api/workshop/dcw/[id]/param-ledger.get.ts +15 -0
  691. package/server/api/workshop/dcw/[id]/test.post.ts +15 -0
  692. package/server/api/workshop/dcw/[id]/write.post.ts +19 -0
  693. package/server/api/workshop/dcw/[id].delete.ts +30 -0
  694. package/server/api/workshop/dcw/[id].patch.ts +18 -0
  695. package/server/api/workshop/dcw/controller.post.ts +43 -0
  696. package/server/api/workshop/dcw/index.get.ts +25 -0
  697. package/server/api/workshop/dcw/index.post.ts +20 -0
  698. package/server/api/workshop/dcw/journal/index.get.ts +21 -0
  699. package/server/api/workshop/dcw/journal/node/[nodeId]/rollback.post.ts +22 -0
  700. package/server/api/workshop/dcw/line/query.get.ts +31 -0
  701. package/server/api/workshop/dcw/lines/[id]/start.post.ts +35 -0
  702. package/server/api/workshop/dcw/lines/[id]/stop.post.ts +34 -0
  703. package/server/api/workshop/dcw/lines/[id].delete.ts +35 -0
  704. package/server/api/workshop/dcw/lines/[id].patch.ts +15 -0
  705. package/server/api/workshop/dcw/lines/index.get.ts +14 -0
  706. package/server/api/workshop/dcw/lines/index.post.ts +31 -0
  707. package/server/api/workshop/dcw/optimizations/[id]/judge.post.ts +24 -0
  708. package/server/api/workshop/dcw/optimizations/[id]/rollback.post.ts +29 -0
  709. package/server/api/workshop/dcw/optimizations/[id]/series.get.ts +18 -0
  710. package/server/api/workshop/dcw/optimizations/[id].get.ts +17 -0
  711. package/server/api/workshop/dcw/optimizations/index.get.ts +23 -0
  712. package/server/api/workshop/dcw/products/[id].delete.ts +16 -0
  713. package/server/api/workshop/dcw/products/[id].patch.ts +17 -0
  714. package/server/api/workshop/dcw/products/index.post.ts +16 -0
  715. package/server/api/workshop/dcw/recipes/[id]/apply.post.ts +40 -0
  716. package/server/api/workshop/dcw/recipes/[id]/mark-good.post.ts +21 -0
  717. package/server/api/workshop/dcw/recipes/[id]/rollback-good.post.ts +19 -0
  718. package/server/api/workshop/dcw/recipes/[id].delete.ts +14 -0
  719. package/server/api/workshop/dcw/recipes/[id].patch.ts +16 -0
  720. package/server/api/workshop/dcw/recipes/index.get.ts +12 -0
  721. package/server/api/workshop/dcw/recipes/index.post.ts +15 -0
  722. package/server/api/workshop/dcw/runs/[id]/close.post.ts +15 -0
  723. package/server/api/workshop/dcw/runs/[id]/data.get.ts +15 -0
  724. package/server/api/workshop/dcw/runs/[id]/rollback.post.ts +20 -0
  725. package/server/api/workshop/dcw/runs/index.get.ts +11 -0
  726. package/server/api/workshop/dcw/templates/[key].delete.ts +14 -0
  727. package/server/api/workshop/dcw/templates/[key].patch.ts +16 -0
  728. package/server/api/workshop/dcw/templates/index.post.ts +15 -0
  729. package/server/api/workshop/dcw/test-driver.post.ts +16 -0
  730. package/server/api/workshop/device-twins/[id]/control.post.ts +21 -0
  731. package/server/api/workshop/device-twins/[id]/telemetry.post.ts +21 -0
  732. package/server/api/workshop/device-twins/[id].delete.ts +25 -0
  733. package/server/api/workshop/device-twins/[id].patch.ts +29 -0
  734. package/server/api/workshop/device-twins/index.get.ts +16 -0
  735. package/server/api/workshop/device-twins/index.post.ts +32 -0
  736. package/server/api/workshop/fs/dirs.get.ts +40 -0
  737. package/server/api/workshop/mailbox/all.get.ts +19 -0
  738. package/server/api/workshop/mailbox.get.ts +14 -0
  739. package/server/api/workshop/memories/maintenance.post.ts +15 -0
  740. package/server/api/workshop/ops-logs/index.get.ts +30 -0
  741. package/server/api/workshop/ops-logs/index.post.ts +39 -0
  742. package/server/api/workshop/runtime.get.ts +11 -0
  743. package/server/api/workshop/scene/layouts/[channelId].delete.ts +23 -0
  744. package/server/api/workshop/scene/layouts/[channelId].put.ts +31 -0
  745. package/server/api/workshop/scene/layouts.get.ts +13 -0
  746. package/server/api/workshop/tasks/[id]/cancel/index.post.ts +34 -0
  747. package/server/api/workshop/tasks/[id]/complete.post.ts +32 -0
  748. package/server/api/workshop/tasks/[id]/dispatch.post.ts +30 -0
  749. package/server/api/workshop/tasks/[id]/report.post.ts +38 -0
  750. package/server/api/workshop/tasks/[id]/retry.post.ts +33 -0
  751. package/server/api/workshop/tasks/[id].get.ts +32 -0
  752. package/server/api/workshop/tasks.get.ts +13 -0
  753. package/server/api/workshop/teams/[id]/deploy.post.ts +40 -0
  754. package/server/api/workshop/teams/[id]/members/[agentId].delete.ts +19 -0
  755. package/server/api/workshop/teams/[id]/members/index.get.ts +19 -0
  756. package/server/api/workshop/teams/[id]/members/index.post.ts +32 -0
  757. package/server/api/workshop/teams/[id].delete.ts +20 -0
  758. package/server/api/workshop/teams/[id].get.ts +19 -0
  759. package/server/api/workshop/teams/[id].patch.ts +32 -0
  760. package/server/api/workshop/teams/index.get.ts +13 -0
  761. package/server/api/workshop/teams/index.post.ts +27 -0
  762. package/server/api/workshop/users/me.get.ts +23 -0
  763. package/server/api/workshop/users/register.post.ts +33 -0
  764. package/server/api/workshop/workspaces/[id]/channel-templates/[tplId].post.ts +31 -0
  765. package/server/api/workshop/workspaces/[id]/channels/[channelId].delete.ts +15 -0
  766. package/server/api/workshop/workspaces/[id]/channels/[channelId].post.ts +15 -0
  767. package/server/api/workshop/workspaces/[id]/index.delete.ts +14 -0
  768. package/server/api/workshop/workspaces/index.get.ts +11 -0
  769. package/server/api/workshop/workspaces/index.post.ts +17 -0
  770. package/server/api/workshop/ws.ts +694 -0
  771. package/server/data/agent-node-bindings.json +554 -0
  772. package/server/data/daq-templates.json +16 -0
  773. package/server/data/daqs.json +2680 -0
  774. package/server/data/dcw-lines.json +919 -0
  775. package/server/data/dcw-products.json +835 -0
  776. package/server/data/dcw-recipes.json +1650 -0
  777. package/server/data/dcw-rollback.json +9339 -0
  778. package/server/data/dcw-runs.json +4633 -0
  779. package/server/data/dcw-templates.json +26 -0
  780. package/server/data/dcw-writes.json +9770 -0
  781. package/server/data/dcws.json +1736 -0
  782. package/server/data/device-twins.json +133 -0
  783. package/server/data/line-runs.json +152 -0
  784. package/server/data/scene-layouts.json +200 -0
  785. package/server/mcp/workshop-server.ts +510 -0
  786. package/server/middleware/request-log.ts +15 -0
  787. package/server/plugins/backup.ts +85 -0
  788. package/server/plugins/daq.ts +65 -0
  789. package/server/plugins/dev-stability-guard.ts +42 -0
  790. package/server/plugins/security.ts +29 -0
  791. package/server/plugins/system-config.ts +38 -0
  792. package/server/plugins/workshop.ts +145 -0
  793. package/server/repositories/user.repository.ts +391 -0
  794. package/server/schemas/user.schema.ts +67 -0
  795. package/server/services/system-config.ts +356 -0
  796. package/server/services/user.service.ts +186 -0
  797. package/server/services/workshop/agents/adapters/omp-rpc-client.ts +539 -0
  798. package/server/services/workshop/agents/adapters/to-a2a.ts +40 -0
  799. package/server/services/workshop/agents/agent-interface.ts +219 -0
  800. package/server/services/workshop/agents/claude-agent.ts +47 -0
  801. package/server/services/workshop/agents/factory.ts +24 -0
  802. package/server/services/workshop/agents/harness-process.ts +158 -0
  803. package/server/services/workshop/agents/harness-terminal.ts +545 -0
  804. package/server/services/workshop/agents/industrial-context.ts +222 -0
  805. package/server/services/workshop/agents/industrial-tools.ts +362 -0
  806. package/server/services/workshop/agents/mock-agent.ts +396 -0
  807. package/server/services/workshop/agents/node-bindings.repo.ts +165 -0
  808. package/server/services/workshop/agents/omp-agent.ts +1598 -0
  809. package/server/services/workshop/agents/tool-approvals.ts +174 -0
  810. package/server/services/workshop/assets/character-asset.repo.ts +120 -0
  811. package/server/services/workshop/assets/device-twin.repo.ts +236 -0
  812. package/server/services/workshop/daq/alarm-notify.ts +100 -0
  813. package/server/services/workshop/daq/bus/index.ts +46 -0
  814. package/server/services/workshop/daq/bus/inproc.adapter.ts +62 -0
  815. package/server/services/workshop/daq/bus/mqtt.adapter.ts +112 -0
  816. package/server/services/workshop/daq/bus/queue-port.ts +36 -0
  817. package/server/services/workshop/daq/daq-controller.ts +778 -0
  818. package/server/services/workshop/daq/daq-node.repo.ts +96 -0
  819. package/server/services/workshop/daq/daq-node.ts +247 -0
  820. package/server/services/workshop/daq/daq-runtime.ts +168 -0
  821. package/server/services/workshop/daq/daq-templates.ts +157 -0
  822. package/server/services/workshop/daq/drivers.ts +771 -0
  823. package/server/services/workshop/daq/host-bindings.ts +71 -0
  824. package/server/services/workshop/daq/host-ports.ts +64 -0
  825. package/server/services/workshop/daq/infra.ts +202 -0
  826. package/server/services/workshop/daq/storage/index.ts +96 -0
  827. package/server/services/workshop/daq/storage/sqlite.adapter.ts +205 -0
  828. package/server/services/workshop/daq/storage/timescale.adapter.ts +185 -0
  829. package/server/services/workshop/daq/storage/tsdb-port.ts +74 -0
  830. package/server/services/workshop/db/agent.repo.ts +105 -0
  831. package/server/services/workshop/db/channel-agent.repo.ts +119 -0
  832. package/server/services/workshop/db/channel-event.repo.ts +154 -0
  833. package/server/services/workshop/db/channel-template.repo.ts +113 -0
  834. package/server/services/workshop/db/channel.repo.ts +101 -0
  835. package/server/services/workshop/db/database.ts +934 -0
  836. package/server/services/workshop/db/memory.repo.ts +249 -0
  837. package/server/services/workshop/db/message.repo.ts +149 -0
  838. package/server/services/workshop/db/ops.repo.ts +323 -0
  839. package/server/services/workshop/db/schema.sql +143 -0
  840. package/server/services/workshop/db/subscription.repo.ts +62 -0
  841. package/server/services/workshop/db/task.repo.ts +175 -0
  842. package/server/services/workshop/db/team-member.repo.ts +70 -0
  843. package/server/services/workshop/db/team.repo.ts +109 -0
  844. package/server/services/workshop/db/user.repo.ts +100 -0
  845. package/server/services/workshop/dcw/dcw-controller.ts +841 -0
  846. package/server/services/workshop/dcw/dcw-line.repo.ts +86 -0
  847. package/server/services/workshop/dcw/dcw-node.repo.ts +89 -0
  848. package/server/services/workshop/dcw/dcw-node.ts +200 -0
  849. package/server/services/workshop/dcw/dcw-product.repo.ts +95 -0
  850. package/server/services/workshop/dcw/dcw-recipe.repo.ts +349 -0
  851. package/server/services/workshop/dcw/dcw-runtime.ts +82 -0
  852. package/server/services/workshop/dcw/dcw-templates.ts +138 -0
  853. package/server/services/workshop/dcw/drivers.ts +523 -0
  854. package/server/services/workshop/dcw/line-run.ts +101 -0
  855. package/server/services/workshop/dcw/recipe-rollback-manager.ts +702 -0
  856. package/server/services/workshop/dcw/recipe-rollback.repo.ts +197 -0
  857. package/server/services/workshop/logger.ts +58 -0
  858. package/server/services/workshop/ops/ops.ts +78 -0
  859. package/server/services/workshop/prompts/loader.ts +112 -0
  860. package/server/services/workshop/runtime/agent-runtime.ts +698 -0
  861. package/server/services/workshop/runtime/channel-runtime.ts +202 -0
  862. package/server/services/workshop/runtime/embedding-provider.ts +79 -0
  863. package/server/services/workshop/runtime/execution-mode.ts +215 -0
  864. package/server/services/workshop/runtime/mailbox.ts +148 -0
  865. package/server/services/workshop/runtime/manager.ts +2543 -0
  866. package/server/services/workshop/runtime/memory.ts +439 -0
  867. package/server/services/workshop/runtime/monitor.ts +194 -0
  868. package/server/services/workshop/runtime/scheduler-loop.ts +773 -0
  869. package/server/services/workshop/runtime/task-engine.ts +574 -0
  870. package/server/services/workshop/scene/scene-layout.repo.ts +112 -0
  871. package/server/services/workshop/scene-events.ts +63 -0
  872. package/server/services/workshop/types/a2a.ts +61 -0
  873. package/server/services/workshop/types/task.ts +85 -0
  874. package/server/types/user.ts +53 -0
  875. package/server/utils/approval-gate.ts +67 -0
  876. package/server/utils/auth.ts +13 -0
  877. package/server/utils/config.ts +40 -0
  878. package/server/utils/errors.ts +24 -0
  879. package/server/utils/response.ts +49 -0
  880. package/server/utils/validate.ts +19 -0
  881. package/shared/config/engine.d.mts +41 -0
  882. package/shared/config/engine.mjs +291 -0
  883. package/shared/config/home.d.mts +48 -0
  884. package/shared/config/home.mjs +146 -0
  885. package/shared/config/schema.json +30 -0
  886. package/shared/daq-protocol.ts +361 -0
  887. package/shared/dcw-protocol.ts +576 -0
  888. package/shared/terminal-protocol.ts +70 -0
  889. package/shared/town-anim.ts +56 -0
  890. package/shared/town-behavior.ts +136 -0
  891. package/shared/town-protocol.ts +110 -0
  892. package/shared/town-scene-math.ts +283 -0
  893. package/shared/workshop-protocol.ts +199 -0
  894. package/tsconfig.json +10 -0
  895. package/uno.config.ts +37 -0
@@ -0,0 +1,280 @@
1
+ /**
2
+ * workshop 持久化层测试(node + tsx 直跑,无浏览器)
3
+ *
4
+ * 覆盖(v2:Agent 与 Channel 分离):
5
+ * 1. 建表:6 张表 + 4 个索引
6
+ * 2. channel CRUD
7
+ * 3. agent 定义 CRUD(全局,无 channel 绑定)
8
+ * 4. channel_agents 成员 CRUD + findByToken(成员级 token)
9
+ * 5. message 状态机(pending→consuming→consumed + resetConsuming)+ channel 作用域
10
+ * 6. subscription 复合主键去重(channel 隔离)
11
+ * 7. task CRUD + listNonTerminal
12
+ */
13
+ import { DatabaseSync } from 'node:sqlite'
14
+ import { openWorkshopDb, initWorkshopDb, parseJson } from '../server/services/workshop/db/database'
15
+ import { createChannelRepo } from '../server/services/workshop/db/channel.repo'
16
+ import { createAgentRepo } from '../server/services/workshop/db/agent.repo'
17
+ import { createChannelAgentRepo } from '../server/services/workshop/db/channel-agent.repo'
18
+ import { createMessageRepo } from '../server/services/workshop/db/message.repo'
19
+ import { createSubscriptionRepo } from '../server/services/workshop/db/subscription.repo'
20
+ import { createTaskRepo } from '../server/services/workshop/db/task.repo'
21
+
22
+ let failures = 0
23
+ function check(name: string, ok: boolean, detail = ''): void {
24
+ console.log(`${ok ? 'PASS' : 'FAIL'} ${name}${detail ? ` — ${detail}` : ''}`)
25
+ if (!ok) {
26
+ failures += 1
27
+ }
28
+ }
29
+
30
+ function testSchema(db: DatabaseSync): void {
31
+ console.log('\n--- 1. 建表与索引 ---')
32
+ const tables = db
33
+ .prepare(
34
+ `SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('channels','agents','channel_agents','messages','subscriptions','tasks') ORDER BY name`,
35
+ )
36
+ .all() as { name: string }[]
37
+ const names = tables.map(t => t.name)
38
+ check('6 张表全部创建', names.length === 6, names.join(','))
39
+
40
+ const indexes = db
41
+ .prepare(
42
+ `SELECT name FROM sqlite_master WHERE type = 'index' AND name IN ('idx_channel_agents_token','idx_channel_agents_channel','idx_messages_queue','idx_tasks_channel','idx_tasks_assignee')`,
43
+ )
44
+ .all()
45
+ check('5 个索引全部创建', indexes.length === 5)
46
+ }
47
+
48
+ function testChannelCrud(db: DatabaseSync): void {
49
+ console.log('\n--- 2. channel CRUD ---')
50
+ const repo = createChannelRepo(db)
51
+
52
+ const created = repo.create({ name: '频道A' })
53
+ check('create 生成 id 且 description 默认空串', created.id.length > 0 && created.description === '' && created.enabled === 1)
54
+ check('create 支持 description', repo.create({ name: '频道B', description: '描述B' }).description === '描述B')
55
+
56
+ check('list 返回 2 条', repo.list().length === 2)
57
+ check('findById 命中', repo.findById(created.id)?.name === '频道A')
58
+ check('findById 未命中返回 undefined', repo.findById('nope') === undefined)
59
+
60
+ const updated = repo.update(created.id, { name: '频道A改', description: '新描述' })
61
+ check('update 修改 name/description', updated?.name === '频道A改' && updated?.description === '新描述')
62
+ check('update 未命中返回 undefined', repo.update('nope', { name: 'x' }) === undefined)
63
+ check('update 保留未提供字段', repo.findById(created.id)?.leadAgentId === null)
64
+
65
+ repo.remove(created.id)
66
+ check('remove 后 findById 未命中', repo.findById(created.id) === undefined)
67
+ check('remove 后 list 长度 1', repo.list().length === 1)
68
+ }
69
+
70
+ function testAgentCrud(db: DatabaseSync): void {
71
+ console.log('\n--- 3. agent 定义 CRUD(全局) ---')
72
+ const repo = createAgentRepo(db)
73
+
74
+ // v10:初始化已种入内置公共模板(owner NULL);断言按"相对基线"计数,避免与种子数据耦合
75
+ const baseline = repo.list().length
76
+
77
+ const lead = repo.create({ name: '主理人', harness: 'mock' })
78
+ check('create 生成 id', lead.id.length > 0)
79
+ check('create 默认 configJson {}', lead.configJson === '{}')
80
+
81
+ const worker = repo.create({ name: '工人', harness: 'claude', config: { model: 'x' } })
82
+ check('create config 序列化为 JSON', worker.configJson === JSON.stringify({ model: 'x' }))
83
+
84
+ check('list 返回基线+2 条', repo.list().length === baseline + 2, `n=${repo.list().length}`)
85
+ check('findById 命中', repo.findById(lead.id)?.name === '主理人')
86
+
87
+ const updated = repo.update(worker.id, { name: '工人改', config: { model: 'y' } })
88
+ check('update 修改 name/config', updated?.name === '工人改' && updated?.configJson === JSON.stringify({ model: 'y' }))
89
+
90
+ repo.remove(worker.id)
91
+ check('remove 后 list 基线+1', repo.list().length === baseline + 1)
92
+ }
93
+
94
+ function testChannelAgentCrud(db: DatabaseSync): void {
95
+ console.log('\n--- 4. channel_agents 实例 CRUD(克隆)+ findByToken ---')
96
+ const channels = createChannelRepo(db)
97
+ const ch = channels.create({ name: '主频道' })
98
+ const agents = createAgentRepo(db)
99
+ const a = agents.create({ name: '主理人', harness: 'mock', config: { k: 'v' } })
100
+ const b = agents.create({ name: '工人', harness: 'claude' })
101
+
102
+ const repo = createChannelAgentRepo(db)
103
+ const mA = repo.create({ channelId: ch.id, templateId: a.id, name: a.name, harness: a.harness, config: { k: 'v' }, role: 'lead' })
104
+ check('create 生成独立身份 id', mA.id.length > 0 && mA.id !== a.id)
105
+ check('create 自动生成实例 token', mA.token.length > 0)
106
+ check('create 复制模板 name/harness/config', mA.name === '主理人' && mA.harness === 'mock' && mA.configJson === JSON.stringify({ k: 'v' }))
107
+ check('create 记录 template_id', mA.templateId === a.id)
108
+
109
+ const mB = repo.create({ channelId: ch.id, templateId: b.id, name: b.name, harness: b.harness, role: 'worker', token: 'tok-1' })
110
+ check('create 接受显式 token', mB.token === 'tok-1')
111
+ check('同模板可克隆多实例且 id 不同', mB.id !== mA.id)
112
+
113
+ check('listByChannel 返回 2 条', repo.listByChannel(ch.id).length === 2)
114
+ check('findById 命中实例', repo.findById(mA.id)?.role === 'lead')
115
+ check('findByChannelAgent 命中', repo.findByChannelAgent(ch.id, mA.id)?.role === 'lead')
116
+ check('findByToken 命中(实例级)', repo.findByToken('tok-1')?.id === mB.id)
117
+ check('findByToken 未命中返回 undefined', repo.findByToken('nope') === undefined)
118
+ check('listByTemplate 返回该模板全部实例', repo.listByTemplate(a.id).length === 1)
119
+
120
+ const updated = repo.update(mB.id, { role: 'lead', name: '工人改' })
121
+ check('update 修改 role/name', updated?.role === 'lead' && updated?.name === '工人改')
122
+
123
+ repo.remove(ch.id, mB.id)
124
+ check('remove 后 listByChannel 长度 1', repo.listByChannel(ch.id).length === 1)
125
+ check('remove 后 findByToken 未命中', repo.findByToken('tok-1') === undefined)
126
+ }
127
+
128
+ function testMessageStateMachine(db: DatabaseSync): void {
129
+ console.log('\n--- 5. message 状态机 + channel 作用域 ---')
130
+ const channels = createChannelRepo(db)
131
+ const ch = channels.create({ name: '消息频道' })
132
+ const repo = createMessageRepo(db)
133
+
134
+ const m1 = repo.create({ channelId: ch.id, toAgentId: 'agent-a', role: 'ROLE_AGENT', parts: [{ text: 'hi' }] })
135
+ const m2 = repo.create({ channelId: ch.id, toAgentId: 'agent-a', role: 'ROLE_AGENT', parts: [{ text: 'yo' }] })
136
+ repo.create({ channelId: ch.id, toAgentId: 'agent-b', role: 'ROLE_USER', parts: [{ text: 'other' }], metadata: { k: 1 } })
137
+
138
+ check('listPendingByChannelAgent 初始 2 条', repo.listPendingByChannelAgent(ch.id, 'agent-a').length === 2)
139
+ check('partsJson 存 JSON.stringify', m1.partsJson === JSON.stringify([{ text: 'hi' }]))
140
+ check('parseJson 读回 parts', parseJson<{ text: string }[]>(m1.partsJson, []).length === 1)
141
+ check('parseJson 解析失败返回默认值', parseJson('{broken', []).length === 0)
142
+
143
+ check('claim 首次认领成功', repo.claim(m1.id) === true)
144
+ check('claim 后 pending 减为 1', repo.listPendingByChannelAgent(ch.id, 'agent-a').length === 1)
145
+ check('claim 重复认领失败(唯一所有权)', repo.claim(m1.id) === false)
146
+ const consuming = db.prepare(`SELECT state FROM messages WHERE id = ?`).get(m1.id) as { state: string }
147
+ check('m1 state 变为 consuming', consuming.state === 'consuming')
148
+
149
+ repo.markConsumed(m1.id)
150
+ const consumed = db.prepare(`SELECT state, consumed_at FROM messages WHERE id = ?`).get(m1.id) as { state: string, consumed_at: string | null }
151
+ check('markConsumed 后 state=consumed 且 consumed_at 非空', consumed.state === 'consumed' && consumed.consumed_at != null)
152
+
153
+ repo.claim(m2.id)
154
+ repo.resetConsuming()
155
+ const m2After = db.prepare(`SELECT state FROM messages WHERE id = ?`).get(m2.id) as { state: string }
156
+ check('resetConsuming 将 consuming 重置为 pending', m2After.state === 'pending')
157
+ check('resetConsuming 后 pending 恢复为 1', repo.listPendingByChannelAgent(ch.id, 'agent-a').length === 1)
158
+
159
+ check('listRecentByChannel 返回 3 条', repo.listRecentByChannel(ch.id, 10).length === 3)
160
+ check('listRecentByChannel 尊重 limit', repo.listRecentByChannel(ch.id, 2).length === 2)
161
+ }
162
+
163
+ function testSubscriptionDedup(db: DatabaseSync): void {
164
+ console.log('\n--- 6. subscription 复合主键去重(channel 隔离) ---')
165
+ const channels = createChannelRepo(db)
166
+ const ch = channels.create({ name: '订阅频道' })
167
+ const agents = createAgentRepo(db)
168
+ const channelAgents = createChannelAgentRepo(db)
169
+ const tplA = agents.create({ name: 'A', harness: 'mock' })
170
+ const tplB = agents.create({ name: 'B', harness: 'mock' })
171
+ const tplC = agents.create({ name: 'C', harness: 'mock' })
172
+ const a = channelAgents.create({ channelId: ch.id, templateId: tplA.id, name: tplA.name, harness: tplA.harness, role: 'worker' })
173
+ const b = channelAgents.create({ channelId: ch.id, templateId: tplB.id, name: tplB.name, harness: tplB.harness, role: 'worker' })
174
+ const c = channelAgents.create({ channelId: ch.id, templateId: tplC.id, name: tplC.name, harness: tplC.harness, role: 'worker' })
175
+
176
+ const repo = createSubscriptionRepo(db)
177
+ repo.add(ch.id, a.id, b.id)
178
+ repo.add(ch.id, a.id, b.id)
179
+ check('重复 add 同一对自动去重', repo.listByAgent(ch.id, a.id).length === 1)
180
+
181
+ repo.add(ch.id, a.id, c.id)
182
+ check('listByAgent 返回 2 个目标', repo.listByAgent(ch.id, a.id).length === 2)
183
+ check('listByTarget(b) 返回 1 个订阅者', repo.listByTarget(ch.id, b.id).length === 1)
184
+
185
+ repo.remove(ch.id, a.id, b.id)
186
+ check('remove 后 listByAgent 长度 1', repo.listByAgent(ch.id, a.id).length === 1)
187
+ check('remove 后 listByTarget(b) 为空', repo.listByTarget(ch.id, b.id).length === 0)
188
+ }
189
+
190
+ function testTaskCrud(db: DatabaseSync): void {
191
+ console.log('\n--- 7. task CRUD + listNonTerminal ---')
192
+ const channels = createChannelRepo(db)
193
+ const ch = channels.create({ name: '任务频道' })
194
+ const agents = createAgentRepo(db)
195
+ const lead = agents.create({ name: '主理人', harness: 'mock' })
196
+ const worker = agents.create({ name: '工人', harness: 'mock' })
197
+
198
+ const repo = createTaskRepo(db)
199
+ const parent = repo.create({ channelId: ch.id, assigneeId: lead.id, creatorId: 'user-1', title: '主任务' })
200
+ check('create 默认 SUBMITTED/progress 0/retryCount 0', parent.state === 'SUBMITTED' && parent.progress === 0 && parent.retryCount === 0)
201
+ check('create artifactsJson 默认 []', parent.artifactsJson === '[]')
202
+
203
+ const child = repo.create({ channelId: ch.id, parentId: parent.id, assigneeId: worker.id, creatorId: lead.id, title: '子任务', state: 'ASSIGNED', artifacts: [{ artifactId: 'a1' }] })
204
+ check('create 子任务 parentId/artifacts 序列化', child.parentId === parent.id && child.artifactsJson === JSON.stringify([{ artifactId: 'a1' }]))
205
+
206
+ check('listByChannel 返回 2 条', repo.listByChannel(ch.id).length === 2)
207
+ check('listByAssignee(worker) 返回 1 条', repo.listByAssignee(worker.id).length === 1)
208
+ check('listNonTerminal 初始 2 条', repo.listNonTerminal().length === 2)
209
+
210
+ const updated = repo.update(child.id, { state: 'COMPLETED', progress: 100 })
211
+ check('update 修改 state/progress', updated?.state === 'COMPLETED' && updated?.progress === 100)
212
+ check('listNonTerminal 排除终态', repo.listNonTerminal().length === 1)
213
+ check('listNonTerminal 只剩父任务', repo.listNonTerminal()[0]?.id === parent.id)
214
+
215
+ check('findById 命中', repo.findById(parent.id)?.title === '主任务')
216
+ check('findById 未命中返回 undefined', repo.findById('nope') === undefined)
217
+ }
218
+
219
+ /** 旧库(v3 前)FK 缺失迁移:重建 tasks/subscriptions 外键 + 清除孤儿行 */
220
+ function testFkMigration(): void {
221
+ console.log('\n--- 8. 旧库 FK 缺失迁移 ---')
222
+ // 手工构造无外键的旧版 tasks/subscriptions + 孤儿行
223
+ const db = new DatabaseSync(':memory:')
224
+ db.exec(`PRAGMA foreign_keys = ON;
225
+ CREATE TABLE channels (id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', lead_agent_id TEXT, workspace TEXT NOT NULL DEFAULT '', enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
226
+ CREATE TABLE agents (id TEXT PRIMARY KEY, name TEXT NOT NULL, harness TEXT NOT NULL, config_json TEXT NOT NULL DEFAULT '{}', enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
227
+ CREATE TABLE channel_agents (id TEXT PRIMARY KEY, channel_id TEXT NOT NULL, template_id TEXT, name TEXT NOT NULL, harness TEXT NOT NULL, config_json TEXT NOT NULL DEFAULT '{}', role TEXT NOT NULL DEFAULT 'worker', token TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
228
+ CREATE TABLE messages (id TEXT PRIMARY KEY, channel_id TEXT NOT NULL, task_id TEXT, from_agent_id TEXT, to_agent_id TEXT, role TEXT NOT NULL, parts_json TEXT NOT NULL, metadata_json TEXT NOT NULL DEFAULT '{}', state TEXT NOT NULL DEFAULT 'pending', created_at TEXT NOT NULL, consumed_at TEXT);
229
+ CREATE TABLE subscriptions (channel_id TEXT NOT NULL, agent_id TEXT NOT NULL, target_agent_id TEXT NOT NULL, created_at TEXT NOT NULL, PRIMARY KEY (channel_id, agent_id, target_agent_id));
230
+ CREATE TABLE tasks (id TEXT PRIMARY KEY, channel_id TEXT NOT NULL, parent_id TEXT, assignee_id TEXT NOT NULL, creator_id TEXT, title TEXT NOT NULL, description TEXT, state TEXT NOT NULL, progress INTEGER NOT NULL DEFAULT 0, retry_count INTEGER NOT NULL DEFAULT 0, artifacts_json TEXT NOT NULL DEFAULT '[]', history_json TEXT NOT NULL DEFAULT '[]', created_at TEXT NOT NULL, updated_at TEXT NOT NULL);`)
231
+ const now = new Date().toISOString()
232
+ db.prepare(`INSERT INTO channels (id, name, created_at, updated_at) VALUES ('ch1', '正常频道', ?, ?)`).run(now, now)
233
+ db.prepare(`INSERT INTO channel_agents (id, channel_id, name, harness, role, token, created_at, updated_at) VALUES ('ag1', 'ch1', 'a', 'mock', 'lead', 'tok1', ?, ?)`).run(now, now)
234
+ db.prepare(`INSERT INTO tasks (id, channel_id, assignee_id, title, state, created_at, updated_at) VALUES ('t1', 'ch1', 'ag1', '正常任务', 'COMPLETED', ?, ?)`).run(now, now)
235
+ // 孤儿:channel 已删,任务/订阅残留
236
+ db.prepare(`INSERT INTO tasks (id, channel_id, assignee_id, title, state, created_at, updated_at) VALUES ('t2', 'ghost-ch', 'ag1', '孤儿任务', 'COMPLETED', ?, ?)`).run(now, now)
237
+ db.prepare(`INSERT INTO subscriptions (channel_id, agent_id, target_agent_id, created_at) VALUES ('ghost-ch', 'ag1', 'ag1', ?)`).run(now)
238
+
239
+ try {
240
+ initWorkshopDb(db)
241
+ const fkTasks = db.prepare('PRAGMA foreign_key_list(tasks)').all() as Array<{ from: string, table: string, on_delete: string }>
242
+ const fkSubs = db.prepare('PRAGMA foreign_key_list(subscriptions)').all() as Array<{ from: string, table: string, on_delete: string }>
243
+ check('迁移后 tasks 带 channel 级联外键', fkTasks.some(f => f.from === 'channel_id' && f.table === 'channels' && f.on_delete === 'CASCADE'))
244
+ check('迁移后 subscriptions 带双级联外键', fkSubs.some(f => f.from === 'channel_id' && f.table === 'channels' && f.on_delete === 'CASCADE') && fkSubs.some(f => f.from === 'agent_id' && f.table === 'channel_agents' && f.on_delete === 'CASCADE'))
245
+ const t2 = db.prepare(`SELECT COUNT(*) c FROM tasks WHERE id = 't2'`).get() as { c: number }
246
+ const s2 = db.prepare(`SELECT COUNT(*) c FROM subscriptions WHERE channel_id = 'ghost-ch'`).get() as { c: number }
247
+ check('孤儿任务/订阅已清除', t2.c === 0 && s2.c === 0)
248
+ const t1 = db.prepare(`SELECT COUNT(*) c FROM tasks WHERE id = 't1'`).get() as { c: number }
249
+ check('正常数据保留', t1.c === 1)
250
+ // 级联删除验证
251
+ db.prepare(`DELETE FROM channels WHERE id = 'ch1'`).run()
252
+ const cascade = db.prepare(`SELECT COUNT(*) c FROM tasks WHERE channel_id = 'ch1'`).get() as { c: number }
253
+ check('删除 channel 级联删任务', cascade.c === 0)
254
+ }
255
+ finally {
256
+ db.close()
257
+ }
258
+ }
259
+
260
+ function main(): void {
261
+ const db = openWorkshopDb(':memory:')
262
+ try {
263
+ testSchema(db)
264
+ testChannelCrud(db)
265
+ testAgentCrud(db)
266
+ testChannelAgentCrud(db)
267
+ testMessageStateMachine(db)
268
+ testSubscriptionDedup(db)
269
+ testTaskCrud(db)
270
+ }
271
+ finally {
272
+ db.close()
273
+ }
274
+ testFkMigration()
275
+
276
+ console.log(`\n${failures === 0 ? 'ALL PASS' : `${failures} FAILED`}`)
277
+ process.exit(failures === 0 ? 0 : 1)
278
+ }
279
+
280
+ main()
@@ -0,0 +1,370 @@
1
+ /**
2
+ * 入口层测试(REST + A2A + plugin 装配;WS 留集成)(node + tsx 直跑,无浏览器)。
3
+ *
4
+ * 装配:真实 :memory: db + 真实 Manager(mock harness,delayMs=0)+ 真实 SchedulerLoop
5
+ * (经 REST 入口创建 channel/lead 时由 handler 自动装配;无真实 HTTP 服务器,
6
+ * 用 h3 的 H3 实例挂载各 handler,app.request 直调,等价 Nitro 测试客户端)。
7
+ *
8
+ * 覆盖:
9
+ * 1. REST:创建 channel(带 lead)/创建 2 worker/发任务 → 任务流转到 COMPLETED(轮询等待)
10
+ * 2. REST:任务列表含进度;任务详情含成果
11
+ * 3. REST 错误码:NO_LEAD_AGENT(400)/LEAD_EXISTS(409)/NOT_FOUND(404)/INVALID_TRANSITION(400)
12
+ * 4. REST:取消任务(慢速 lead 确定性场景)→ CANCELED
13
+ * 5. A2A card:结构(supportedInterfaces.protocolBinding=JSONRPC / capabilities.streaming / modes / skills)
14
+ * 6. A2A rpc:tasks/get 返回任务;tasks/list;tasks/send 同步阻塞至终态;tasks/sendSubscribe(SSE);
15
+ * tasks/cancel;message/send(带 token);agent/getCard;JSON-RPC 错误码(-32601/-32602/-32005/-32700)
16
+ */
17
+ import { H3 } from 'h3'
18
+ import { openWorkshopDb } from '../server/services/workshop/db/database'
19
+ import { createChannelRepo } from '../server/services/workshop/db/channel.repo'
20
+ import { createAgentRepo } from '../server/services/workshop/db/agent.repo'
21
+ import { createChannelAgentRepo } from '../server/services/workshop/db/channel-agent.repo'
22
+ import { createTaskRepo } from '../server/services/workshop/db/task.repo'
23
+ import { createMemoryRepo } from '../server/services/workshop/db/memory.repo'
24
+ import { createChannelEventRepo } from '../server/services/workshop/db/channel-event.repo'
25
+ import { createTeamRepo } from '../server/services/workshop/db/team.repo'
26
+ import { createTeamMemberRepo } from '../server/services/workshop/db/team-member.repo'
27
+ import { createMessageRepo } from '../server/services/workshop/db/message.repo'
28
+ import { createSubscriptionRepo } from '../server/services/workshop/db/subscription.repo'
29
+ import { createAgentImpl } from '../server/services/workshop/agents/factory'
30
+ import { createAgentChannelManager } from '../server/services/workshop/runtime/manager'
31
+ import type { AllRepos, AgentChannelManager } from '../server/services/workshop/runtime/manager'
32
+ import type { ChannelRuntime } from '../server/services/workshop/runtime/channel-runtime'
33
+ import type { AgentRuntime } from '../server/services/workshop/runtime/agent-runtime'
34
+ import createChannelHandler from '../server/api/workshop/channels.post'
35
+ import listChannelsHandler from '../server/api/workshop/channels.get'
36
+ import deleteChannelHandler from '../server/api/workshop/channels/[id].delete'
37
+ import createAgentHandler from '../server/api/workshop/channels/[id]/agents/index.post'
38
+ import listAgentsHandler from '../server/api/workshop/channels/[id]/agents/index.get'
39
+ import deleteAgentHandler from '../server/api/workshop/agents/[id].delete'
40
+ import submitTaskHandler from '../server/api/workshop/channels/[id]/tasks/index.post'
41
+ import listTasksHandler from '../server/api/workshop/channels/[id]/tasks/index.get'
42
+ import getTaskHandler from '../server/api/workshop/tasks/[id].get'
43
+ import cancelTaskHandler from '../server/api/workshop/tasks/[id]/cancel/index.post'
44
+ import cardHandler from '../server/api/workshop/a2a/[agentId]/card/index.get'
45
+ import rpcHandler from '../server/api/workshop/a2a/[agentId]/rpc/index.post'
46
+
47
+ let failures = 0
48
+ function check(name: string, ok: boolean, detail = ''): void {
49
+ console.log(`${ok ? 'PASS' : 'FAIL'} ${name}${detail ? ` — ${detail}` : ''}`)
50
+ if (!ok) failures += 1
51
+ }
52
+
53
+ function sleep(ms: number): Promise<void> {
54
+ const { promise, resolve } = Promise.withResolvers<undefined>()
55
+ setTimeout(resolve, ms)
56
+ return promise
57
+ }
58
+
59
+ async function waitUntil(cond: () => boolean | Promise<boolean>, timeoutMs = 8000): Promise<boolean> {
60
+ const start = Date.now()
61
+ for (;;) {
62
+ if (await cond()) return true
63
+ if (Date.now() - start >= timeoutMs) return await cond()
64
+ await sleep(20)
65
+ }
66
+ }
67
+
68
+ // ===== 装配:真实 Manager + H3 测试客户端 =====
69
+
70
+ const db = openWorkshopDb(':memory:')
71
+ const repos: AllRepos = {
72
+ channels: createChannelRepo(db),
73
+ agents: createAgentRepo(db),
74
+ channelAgents: createChannelAgentRepo(db),
75
+ messages: createMessageRepo(db),
76
+ subscriptions: createSubscriptionRepo(db),
77
+ tasks: createTaskRepo(db),
78
+ memories: createMemoryRepo(db),
79
+
80
+ channelEvents: createChannelEventRepo(db),
81
+
82
+ teams: createTeamRepo(db),
83
+
84
+ teamMembers: createTeamMemberRepo(db),
85
+ }
86
+ const manager: AgentChannelManager = createAgentChannelManager({ repos, implFactory: createAgentImpl, db })
87
+ // plugin 的 getWorkshopManager() 从该全局单例读取(plugin 未在测试中执行)
88
+ globalThis.__workshopManager = manager
89
+
90
+ const app = new H3()
91
+ app.on('post', '/api/workshop/channels', createChannelHandler)
92
+ app.on('get', '/api/workshop/channels', listChannelsHandler)
93
+ app.on('delete', '/api/workshop/channels/:id', deleteChannelHandler)
94
+ app.on('post', '/api/workshop/channels/:id/agents', createAgentHandler)
95
+ app.on('get', '/api/workshop/channels/:id/agents', listAgentsHandler)
96
+ app.on('delete', '/api/workshop/agents/:id', deleteAgentHandler)
97
+ app.on('post', '/api/workshop/channels/:id/tasks', submitTaskHandler)
98
+ app.on('get', '/api/workshop/channels/:id/tasks', listTasksHandler)
99
+ app.on('get', '/api/workshop/tasks/:id', getTaskHandler)
100
+ app.on('post', '/api/workshop/tasks/:id/cancel', cancelTaskHandler)
101
+ app.on('get', '/api/workshop/a2a/:agentId.card', cardHandler)
102
+ app.on('post', '/api/workshop/a2a/:agentId.rpc', rpcHandler)
103
+
104
+ interface ReqInit {
105
+ method?: string
106
+ body?: unknown
107
+ headers?: Record<string, string>
108
+ }
109
+ /** h3 H3 测试客户端:直调 handler,等价 Nitro 客户端(无真实 HTTP 服务器) */
110
+ async function req(path: string, init: ReqInit = {}): Promise<{ status: number, json: () => Promise<Record<string, unknown>>, text: () => Promise<string> }> {
111
+ const res = await app.request(path, {
112
+ method: init.method ?? 'GET',
113
+ headers: { 'content-type': 'application/json', ...(init.headers ?? {}) },
114
+ body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
115
+ })
116
+ return { status: res.status, json: () => res.json() as Promise<Record<string, unknown>>, text: () => res.text() }
117
+ }
118
+
119
+ /** manager 内部结构(停止调度循环与 Agent 用) */
120
+ function internalsOf(m: AgentChannelManager): { channels: Map<string, ChannelRuntime>, agentIndex: Map<string, AgentRuntime> } {
121
+ return m as unknown as { channels: Map<string, ChannelRuntime>, agentIndex: Map<string, AgentRuntime> }
122
+ }
123
+
124
+ /** 停止全部 SchedulerLoop 与 Agent(慢速 lead 的 run 不等待,进程将 exit) */
125
+ function teardown(): void {
126
+ const internal = internalsOf(manager)
127
+ for (const cr of internal.channels.values()) cr.scheduler?.stop()
128
+ for (const agent of internal.agentIndex.values()) {
129
+ void agent.stop().catch(() => {})
130
+ }
131
+ try {
132
+ db.close()
133
+ }
134
+ catch {
135
+ // 已有语句打开时忽略
136
+ }
137
+ }
138
+
139
+ // ===== 场景 =====
140
+
141
+ async function testRestE2E(): Promise<{ channelA: string, leadA: string, workerTokens: string[], completedTaskId: string }> {
142
+ console.log('\n--- 1. REST:创建 channel/lead + 2 worker + 发任务 → COMPLETED ---')
143
+
144
+ // 创建 channel(带 leadAgent)→ handler 自动装配 SchedulerLoop
145
+ const created = await req('/api/workshop/channels', {
146
+ method: 'POST',
147
+ body: { name: '团队A', description: '端到端', leadAgent: { name: 'Lead', harness: 'mock', config: { delayMs: 0 } } },
148
+ })
149
+ const createdJson = await created.json()
150
+ const channelA: string = createdJson.data?.channelId
151
+ const leadA: string = createdJson.data?.leadAgentId
152
+ check('创建 channel 返回 channelId + leadAgentId', typeof channelA === 'string' && typeof leadA === 'string', JSON.stringify(createdJson.data))
153
+
154
+ // 创建 2 个 worker
155
+ const workerTokens: string[] = []
156
+ for (const name of ['Worker1', 'Worker2']) {
157
+ const res = await req(`/api/workshop/channels/${channelA}/agents`, {
158
+ method: 'POST',
159
+ body: { name, harness: 'mock', role: 'worker', config: { delayMs: 0 } },
160
+ })
161
+ const json = await res.json()
162
+ check(`创建 worker ${name} 成功`, json.data?.id != null && json.data?.role === 'worker', JSON.stringify(json.data))
163
+ if (typeof json.data?.token === 'string') workerTokens.push(json.data.token)
164
+ }
165
+ check('worker token 可见(供 A2A message/send 使用)', workerTokens.length === 2)
166
+
167
+ const agentsRes = await req(`/api/workshop/channels/${channelA}/agents`)
168
+ const agentsJson = await agentsRes.json()
169
+ check('列 Agent:3 个(1 lead + 2 worker)', Array.isArray(agentsJson.data) && agentsJson.data.length === 3, `count=${agentsJson.data?.length}`)
170
+
171
+ // 发任务(带 parts → 初始 input artifact,保证"成果"恒可见)
172
+ const taskRes = await req(`/api/workshop/channels/${channelA}/tasks`, {
173
+ method: 'POST',
174
+ body: { title: '端到端任务', description: '集成验证', parts: [{ text: '集成验证载荷' }] },
175
+ })
176
+ const taskJson = await taskRes.json()
177
+ const taskId: string = taskJson.data?.id
178
+ check('发任务成功且状态 SUBMITTED', taskJson.data?.state === 'SUBMITTED', JSON.stringify(taskJson.data))
179
+
180
+ // 轮询等待任务流转到 COMPLETED(mock harness delayMs=0,毫秒级完成)
181
+ const completed = await waitUntil(async () => {
182
+ const res = await req(`/api/workshop/tasks/${taskId}`)
183
+ const json = await res.json()
184
+ return json.data?.state === 'COMPLETED'
185
+ })
186
+ check('任务流转到 COMPLETED(轮询等待)', completed)
187
+
188
+ const detail = await (await req(`/api/workshop/tasks/${taskId}`)).json()
189
+ check('任务详情含成果(artifacts 非空)且进度 100', Array.isArray(detail.data?.artifacts) && detail.data.artifacts.length >= 1 && detail.data.progress === 100,
190
+ `progress=${detail.data?.progress} artifacts=${detail.data?.artifacts?.length}`)
191
+
192
+ const listRes = await (await req(`/api/workshop/channels/${channelA}/tasks`)).json()
193
+ const listed = (listRes.data ?? []).find((t: { id: string }) => t.id === taskId)
194
+ check('任务列表含进度(state=COMPLETED, progress=100)', listed?.state === 'COMPLETED' && listed?.progress === 100, JSON.stringify(listed))
195
+
196
+ return { channelA, leadA, workerTokens, completedTaskId: taskId }
197
+ }
198
+
199
+ async function testRestErrors(ctx: { channelA: string, completedTaskId: string }): Promise<string> {
200
+ console.log('\n--- 2. REST 错误码:NO_LEAD_AGENT / LEAD_EXISTS / NOT_FOUND / INVALID_TRANSITION ---')
201
+
202
+ // 无 lead 的 channel → 发任务 NO_LEAD_AGENT(400)
203
+ const noLead = await req('/api/workshop/channels', { method: 'POST', body: { name: '空团队' } })
204
+ const noLeadJson = await noLead.json()
205
+ const emptyChannel: string = noLeadJson.data?.channelId
206
+ const taskOnEmpty = await (await req(`/api/workshop/channels/${emptyChannel}/tasks`, { method: 'POST', body: { title: 'x' } })).json()
207
+ check('channel 无 lead → 400 NO_LEAD_AGENT', taskOnEmpty.code === 'NO_LEAD_AGENT' && taskOnEmpty.data === null, JSON.stringify(taskOnEmpty))
208
+
209
+ // 重复创建 lead → 409 LEAD_EXISTS
210
+ const dupLead = await (await req(`/api/workshop/channels/${ctx.channelA}/agents`, { method: 'POST', body: { name: 'Lead2', harness: 'mock', role: 'lead' } })).json()
211
+ check('重复创建 lead → 409 LEAD_EXISTS', dupLead.code === 'LEAD_EXISTS', JSON.stringify(dupLead))
212
+
213
+ // 任务不存在 → 404 NOT_FOUND
214
+ const missing = await (await req('/api/workshop/tasks/not-exist')).json()
215
+ check('任务不存在 → 404 NOT_FOUND', missing.code === 'NOT_FOUND', JSON.stringify(missing))
216
+
217
+ // 终态任务取消 → 400 INVALID_TRANSITION
218
+ const cancelDone = await (await req(`/api/workshop/tasks/${ctx.completedTaskId}/cancel`, { method: 'POST' })).json()
219
+ check('取消已终态任务 → 400 INVALID_TRANSITION', cancelDone.code === 'INVALID_TRANSITION', JSON.stringify(cancelDone))
220
+
221
+ // Agent 不存在删除 → 404 NOT_FOUND
222
+ const missingAgent = await (await req('/api/workshop/agents/not-exist', { method: 'DELETE' })).json()
223
+ check('删除不存在 Agent → 404 NOT_FOUND', missingAgent.code === 'NOT_FOUND', JSON.stringify(missingAgent))
224
+
225
+ return emptyChannel
226
+ }
227
+
228
+ async function testCancel(emptyChannel: string): Promise<string> {
229
+ console.log('\n--- 3. REST:取消任务(慢速 lead 确定性场景)→ CANCELED ---')
230
+
231
+ // channel B:仅 lead + delayMs=5000(任务长时间停留 WORKING,取消窗口确定)
232
+ const created = await (await req('/api/workshop/channels', {
233
+ method: 'POST',
234
+ body: { name: '团队B', leadAgent: { name: 'SlowLead', harness: 'mock', config: { delayMs: 5000 } } },
235
+ })).json()
236
+ const channelB: string = created.data?.channelId
237
+
238
+ const submit = await (await req(`/api/workshop/channels/${channelB}/tasks`, { method: 'POST', body: { title: '将被取消' } })).json()
239
+ const taskId: string = submit.data?.id
240
+ const canceled = await (await req(`/api/workshop/tasks/${taskId}/cancel`, { method: 'POST' })).json()
241
+ check('取消任务 → CANCELED(系统身份=lead)', canceled.data?.state === 'CANCELED', JSON.stringify(canceled.data))
242
+
243
+ const after = await (await req(`/api/workshop/tasks/${taskId}`)).json()
244
+ check('取消后任务详情 CANCELED', after.data?.state === 'CANCELED')
245
+
246
+ // 删除 channel 后发任务 → 404
247
+ const del = await (await req(`/api/workshop/channels/${emptyChannel}`, { method: 'DELETE' })).json()
248
+ check('删除 channel → ok', del.data?.ok === true)
249
+ const afterDel = await (await req(`/api/workshop/channels/${emptyChannel}/tasks`, { method: 'POST', body: { title: 'x' } })).json()
250
+ check('删除后发任务 → 404 NOT_FOUND', afterDel.code === 'NOT_FOUND', JSON.stringify(afterDel))
251
+
252
+ return channelB
253
+ }
254
+
255
+ async function testA2ACard(leadA: string): Promise<void> {
256
+ console.log('\n--- 4. A2A card:结构校验 ---')
257
+ const card = await (await req(`/api/workshop/a2a/${leadA}.card`)).json()
258
+ check('card.name 存在', typeof card.name === 'string' && card.name.length > 0, JSON.stringify(card.name))
259
+ check('card.description 存在', typeof card.description === 'string' && card.description.length > 0)
260
+ check(
261
+ 'supportedInterfaces(数组, protocolBinding=JSONRPC, protocolVersion=1.0)',
262
+ Array.isArray(card.supportedInterfaces)
263
+ && card.supportedInterfaces.length > 0
264
+ && card.supportedInterfaces[0].protocolBinding === 'JSONRPC'
265
+ && card.supportedInterfaces[0].protocolVersion === '1.0'
266
+ && typeof card.supportedInterfaces[0].url === 'string',
267
+ JSON.stringify(card.supportedInterfaces),
268
+ )
269
+ check('capabilities{streaming:true, pushNotifications:false}', card.capabilities?.streaming === true && card.capabilities?.pushNotifications === false)
270
+ check('defaultInputModes/OutputModes 含 text/plain', Array.isArray(card.defaultInputModes) && card.defaultInputModes.includes('text/plain') && Array.isArray(card.defaultOutputModes))
271
+ check('skills 为数组', Array.isArray(card.skills))
272
+
273
+ const missing = await req(`/api/workshop/a2a/not-exist.card`)
274
+ const missingJson = await missing.json()
275
+ check('card 不存在 Agent → 404', missing.status === 404 && missingJson.error?.code === 'NOT_FOUND', JSON.stringify(missingJson))
276
+ }
277
+
278
+ async function rpc(agentId: string, body: unknown, headers?: Record<string, string>) {
279
+ return req(`/api/workshop/a2a/${agentId}.rpc`, { method: 'POST', body, headers })
280
+ }
281
+
282
+ async function testA2ARpc(ctx: { channelA: string, leadA: string, workerTokens: string[], completedTaskId: string }, channelB: string): Promise<void> {
283
+ console.log('\n--- 5. A2A rpc:JSON-RPC 2.0 ---')
284
+
285
+ // tasks/get:返回任务(jsonrpc 2.0 信封 + result)
286
+ const got = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 1, method: 'tasks/get', params: { taskId: ctx.completedTaskId } })).json()
287
+ check('tasks/get 返回任务', got.jsonrpc === '2.0' && got.id === 1 && got.result?.id === ctx.completedTaskId, JSON.stringify(got))
288
+
289
+ // tasks/list
290
+ const listed = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 2, method: 'tasks/list', params: {} })).json()
291
+ check('tasks/list 返回任务数组(含已完成任务)', Array.isArray(listed.result) && listed.result.some((t: { id: string }) => t.id === ctx.completedTaskId), `count=${listed.result?.length}`)
292
+
293
+ // tasks/send:同步阻塞至终态
294
+ const sent = await (await rpc(ctx.leadA, {
295
+ jsonrpc: '2.0', id: 3, method: 'tasks/send',
296
+ params: { message: { role: 'ROLE_USER', parts: [{ text: 'A2A 发任务' }] } },
297
+ })).json()
298
+ check('tasks/send 阻塞返回终态任务(COMPLETED)', sent.result?.status?.state === 'COMPLETED' && Array.isArray(sent.result?.artifacts), JSON.stringify(sent.result))
299
+
300
+ // tasks/sendSubscribe:SSE 事件流(task/status-update …直到终态)
301
+ const sseText = await Promise.race([
302
+ rpc(ctx.leadA, { jsonrpc: '2.0', id: 4, method: 'tasks/sendSubscribe', params: { message: { role: 'ROLE_USER', parts: [{ text: 'SSE 任务' }] } } }).then(r => r.text()),
303
+ sleep(10_000).then(() => 'TIMEOUT'),
304
+ ])
305
+ check('sendSubscribe 输出 SSE 事件(task + status-update)', typeof sseText === 'string' && sseText.includes('event: task') && sseText.includes('event: status-update'),
306
+ typeof sseText === 'string' ? sseText.slice(0, 200) : sseText)
307
+
308
+ // tasks/cancel:无 token → 系统身份(lead)取消 channelB 的第二个任务
309
+ const submit2 = await (await req(`/api/workshop/channels/${channelB}/tasks`, { method: 'POST', body: { title: '将被 rpc 取消' } })).json()
310
+ const taskB2: string = submit2.data?.id
311
+ const canceled = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 5, method: 'tasks/cancel', params: { taskId: taskB2 } })).json()
312
+ check('tasks/cancel → CANCELED', canceled.result?.status?.state === 'CANCELED', JSON.stringify(canceled.result))
313
+
314
+ // message/send:带 worker token → 点对点投递
315
+ const msg = await (await rpc(ctx.leadA, {
316
+ jsonrpc: '2.0', id: 6, method: 'message/send',
317
+ params: { message: { role: 'ROLE_AGENT', parts: [{ text: 'hi lead' }] } },
318
+ }, { authorization: `Bearer ${ctx.workerTokens[0]}` })).json()
319
+ check('message/send(带 token)返回 messageId', typeof msg.result?.messageId === 'string' && msg.result?.contextId === ctx.channelA, JSON.stringify(msg.result))
320
+
321
+ // message/send 无 token → -32005 Agent not authorized
322
+ const noToken = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 7, method: 'message/send', params: { message: { role: 'ROLE_AGENT', parts: [{ text: 'x' }] } } })).json()
323
+ check('message/send 无 token → -32005', noToken.error?.code === -32005, JSON.stringify(noToken.error))
324
+
325
+ // agent/getCard
326
+ const card = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 8, method: 'agent/getCard', params: {} })).json()
327
+ check('agent/getCard 返回 card', card.result?.name != null && card.result?.capabilities?.streaming === true, JSON.stringify(card.result?.name))
328
+
329
+ // 未知方法 → -32601;非法参数 → -32602
330
+ const unknown = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 9, method: 'foo.bar', params: {} })).json()
331
+ check('未知方法 → -32601 Method not found', unknown.error?.code === -32601, JSON.stringify(unknown.error))
332
+ const badParams = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 10, method: 'tasks/get', params: {} })).json()
333
+ check('非法参数 → -32602 Invalid params', badParams.error?.code === -32602, JSON.stringify(badParams.error))
334
+
335
+ // 跨 channel 任务 → -32005(作用域隔离)
336
+ const scoped = await (await rpc(ctx.leadA, { jsonrpc: '2.0', id: 11, method: 'tasks/get', params: { taskId: taskB2 } })).json()
337
+ check('跨 channel 访问任务 → -32005', scoped.error?.code === -32005, JSON.stringify(scoped.error))
338
+
339
+ // 坏 JSON → -32700 Parse error
340
+ const badJson = await (await app.request(`/api/workshop/a2a/${ctx.leadA}.rpc`, {
341
+ method: 'POST',
342
+ headers: { 'content-type': 'application/json' },
343
+ body: '{not json',
344
+ })).json()
345
+ check('坏 JSON → -32700 Parse error', badJson.error?.code === -32700, JSON.stringify(badJson.error))
346
+
347
+ // 非 JSON-RPC 请求 → -32600 Invalid Request
348
+ const badRpc = await (await rpc(ctx.leadA, { hello: 'world' })).json()
349
+ check('非 JSON-RPC 请求 → -32600 Invalid Request', badRpc.error?.code === -32600, JSON.stringify(badRpc.error))
350
+ }
351
+
352
+ async function main(): Promise<void> {
353
+ const e2e = await testRestE2E()
354
+ const emptyChannel = await testRestErrors(e2e)
355
+ const channelB = await testCancel(emptyChannel)
356
+ await testA2ACard(e2e.leadA)
357
+ await testA2ARpc(e2e, channelB)
358
+
359
+ console.log('\n--- 6. WS handler 不适合单测,留集成(server/api/workshop/ws.ts 已按 §6.4 实现) ---')
360
+
361
+ teardown()
362
+
363
+ console.log(`\n${failures === 0 ? 'ALL PASS' : `${failures} FAILED`}`)
364
+ process.exit(failures === 0 ? 0 : 1)
365
+ }
366
+
367
+ main().catch((e) => {
368
+ console.error(e)
369
+ process.exit(1)
370
+ })