agentworkshop 0.7.27 → 0.7.33

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 (1030) hide show
  1. package/.AgentWorkShop/prompts/aml-mission-default.md +20 -0
  2. package/.AgentWorkShop/prompts/aml-playbook.md +49 -0
  3. package/.AgentWorkShop/prompts/host-tools.json +314 -0
  4. package/.output/.AgentWorkShop/prompts/aml-mission-default.md +20 -0
  5. package/.output/.AgentWorkShop/prompts/aml-playbook.md +49 -0
  6. package/.output/.AgentWorkShop/prompts/host-tools.json +314 -0
  7. package/.output/.AgentWorkShop/schema.json +120 -0
  8. package/.output/nitro.json +1 -1
  9. package/.output/public/_nuxt/{BTLEvDxM.js → 4bHdIqEg.js} +8 -8
  10. package/.output/public/_nuxt/B9nXmjSB.js +19 -0
  11. package/.output/public/_nuxt/BASN8nZ0.js +1 -0
  12. package/.output/public/_nuxt/{DNQF_TXX.js → BBBtwOpo.js} +1 -1
  13. package/.output/public/_nuxt/{DoAlYsiF.js → BBwMH_hG.js} +1 -1
  14. package/.output/public/_nuxt/BWSE6hR6.js +1 -0
  15. package/.output/public/_nuxt/BZv4RFYN.js +1 -0
  16. package/.output/public/_nuxt/{BgCrZKv_2.js → Bc0AmjfT.js} +1 -1
  17. package/.output/public/_nuxt/BcmbLh2z2.js +1 -0
  18. package/.output/public/_nuxt/BgTB6h_q.js +2 -0
  19. package/.output/public/_nuxt/BkLJA9J5.js +1 -0
  20. package/.output/public/_nuxt/{XY2z78rj.js → BuCHayqN.js} +1 -1
  21. package/.output/public/_nuxt/{0jKrzLuM.js → BuvcLKh1.js} +1 -1
  22. package/.output/public/_nuxt/C-mDhyEd.js +1 -0
  23. package/.output/public/_nuxt/{DosOJEmZ2.js → C77oC8yC2.js} +1 -1
  24. package/.output/public/_nuxt/CQvmN-Mi.js +1 -0
  25. package/.output/public/_nuxt/CUDrOuW7.js +1 -0
  26. package/.output/public/_nuxt/{DjU9Dx5Y.js → CZcC-gpk.js} +1 -1
  27. package/.output/public/_nuxt/{Cz9gD2Yo.js → CbzsPO5H.js} +1 -1
  28. package/.output/public/_nuxt/CdSOrh2c.js +1 -0
  29. package/.output/public/_nuxt/Cgx818r-.js +1 -0
  30. package/.output/public/_nuxt/Cjm7VogC.js +1 -0
  31. package/.output/public/_nuxt/Cm5mDxzH.js +1 -0
  32. package/.output/public/_nuxt/Cp6z0RN7.js +1 -0
  33. package/.output/public/_nuxt/Ct-WOVr4.js +1 -0
  34. package/.output/public/_nuxt/CwqIxJGj.js +2 -0
  35. package/.output/public/_nuxt/{BGhOrgle.js → D0fhp-Ga.js} +2 -2
  36. package/.output/public/_nuxt/DIaTPH1M.js +1 -0
  37. package/.output/public/_nuxt/DLljr7g0.js +1 -0
  38. package/.output/public/_nuxt/DTYBfjRY.js +1 -0
  39. package/.output/public/_nuxt/DYKVPzN-.js +1 -0
  40. package/.output/public/_nuxt/DZzGarBE2.js +13 -0
  41. package/.output/public/_nuxt/DaMCzQhv.js +1 -0
  42. package/.output/public/_nuxt/DoMxCWN52.js +4 -0
  43. package/.output/public/_nuxt/{CucID8qg2.js → DoTdlVVe2.js} +1 -1
  44. package/.output/public/_nuxt/DsVcWfyR.js +1 -0
  45. package/.output/public/_nuxt/{BCJFMBQ6.js → DzuC31-i.js} +2 -2
  46. package/.output/public/_nuxt/FQri3dV3.js +1 -0
  47. package/.output/public/_nuxt/Lp7Ll94I.js +1 -0
  48. package/.output/public/_nuxt/PluginSlot.DmjNbrcX.css +1 -0
  49. package/.output/public/_nuxt/_id_.hRYo-EAB.css +1 -0
  50. package/.output/public/_nuxt/_wsId_.gXMEOYgX.css +1 -0
  51. package/.output/public/_nuxt/agents.BV70ioCv.css +1 -0
  52. package/.output/public/_nuxt/aml.WU_bh87J.css +1 -0
  53. package/.output/public/_nuxt/builds/latest.json +1 -1
  54. package/.output/public/_nuxt/builds/meta/291ef3e6-fa6a-4dee-8f46-05da1aeab815.json +1 -0
  55. package/.output/public/_nuxt/daq.Bb6l44-O.css +1 -0
  56. package/.output/public/_nuxt/default.jNT73_hq.css +1 -0
  57. package/.output/public/_nuxt/ekuGmQ7R.js +1 -0
  58. package/.output/public/_nuxt/entry.jFrFAWuA.css +1 -0
  59. package/.output/public/_nuxt/pMoIO6rr.js +14 -0
  60. package/.output/public/_nuxt/pages.Cc8GX9T1.css +1 -0
  61. package/.output/public/_nuxt/plugins.wIPyfPn-.css +1 -0
  62. package/.output/public/_nuxt/settings.BCm4NZIc.css +1 -0
  63. package/.output/public/_nuxt/teams.BC75EGnR.css +1 -0
  64. package/.output/server/chunks/_/binding-authz.mjs +23 -0
  65. package/.output/server/chunks/_/binding-authz.mjs.map +1 -0
  66. package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
  67. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  68. package/.output/server/chunks/_/nitro.mjs +13557 -6855
  69. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  70. package/.output/server/chunks/_/scene-layout.repo.mjs +3 -3
  71. package/.output/server/chunks/_/scene-layout.repo.mjs.map +1 -1
  72. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs +207 -0
  73. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs.map +1 -0
  74. package/.output/server/chunks/build/{OmpTerminalPanel-Cw_Vw9oO.mjs → OmpTerminalPanel-Cu_s4i0A.mjs} +2 -2
  75. package/.output/server/chunks/build/{OmpTerminalPanel-Cw_Vw9oO.mjs.map → OmpTerminalPanel-Cu_s4i0A.mjs.map} +1 -1
  76. package/.output/server/chunks/build/{alert-qJnjyRcP.mjs → PluginSlot-CcR4Ys3T.mjs} +140 -4
  77. package/.output/server/chunks/build/PluginSlot-CcR4Ys3T.mjs.map +1 -0
  78. package/.output/server/chunks/build/{TownView-ftIylqiD.mjs → TownView-BdHnAilw.mjs} +5 -5
  79. package/.output/server/chunks/build/{TownView-ftIylqiD.mjs.map → TownView-BdHnAilw.mjs.map} +1 -1
  80. package/.output/server/chunks/build/{_id_-CahfkmEt.mjs → _id_-Cb845FHR.mjs} +7 -5
  81. package/.output/server/chunks/build/_id_-Cb845FHR.mjs.map +1 -0
  82. package/.output/server/chunks/build/{_id_-3Axz2-gV.mjs → _id_-fadFPl2i.mjs} +50 -35
  83. package/.output/server/chunks/build/_id_-fadFPl2i.mjs.map +1 -0
  84. package/.output/server/chunks/build/{_wsId_-BymlQhzS.mjs → _wsId_-CTZswnm5.mjs} +181 -22
  85. package/.output/server/chunks/build/{_wsId_-BymlQhzS.mjs.map → _wsId_-CTZswnm5.mjs.map} +1 -1
  86. package/.output/server/chunks/build/{agents-DuMiSWKp.mjs → agents-Bvin73QY.mjs} +82 -32
  87. package/.output/server/chunks/build/agents-Bvin73QY.mjs.map +1 -0
  88. package/.output/server/chunks/build/aml-uBNIppIf.mjs +508 -0
  89. package/.output/server/chunks/build/aml-uBNIppIf.mjs.map +1 -0
  90. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs +81 -0
  91. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs.map +1 -0
  92. package/.output/server/chunks/build/{channel-templates-BStqJ-of.mjs → channel-templates-BTq8570n.mjs} +6 -5
  93. package/.output/server/chunks/build/channel-templates-BTq8570n.mjs.map +1 -0
  94. package/.output/server/chunks/build/{checkbox-C1gABOca.mjs → checkbox-8fB-wI-T.mjs} +2 -2
  95. package/.output/server/chunks/build/{checkbox-C1gABOca.mjs.map → checkbox-8fB-wI-T.mjs.map} +1 -1
  96. package/.output/server/chunks/build/{daq-ChYCABz1.mjs → daq-BvihjQyW.mjs} +111 -109
  97. package/.output/server/chunks/build/daq-BvihjQyW.mjs.map +1 -0
  98. package/.output/server/chunks/build/{dcw-CcQNGggh.mjs → dcw-Ks2vJ4PF.mjs} +5 -3
  99. package/.output/server/chunks/build/dcw-Ks2vJ4PF.mjs.map +1 -0
  100. package/.output/server/chunks/build/{default-95-zOTPt.mjs → default-GgHt4O2R.mjs} +164 -101
  101. package/.output/server/chunks/build/{default-95-zOTPt.mjs.map → default-GgHt4O2R.mjs.map} +1 -1
  102. package/.output/server/chunks/build/{input-number-Bd55elNN.mjs → input-number-DzpyYB99.mjs} +2 -2
  103. package/.output/server/chunks/build/{input-number-Bd55elNN.mjs.map → input-number-DzpyYB99.mjs.map} +1 -1
  104. package/.output/server/chunks/build/{logs-D-2UyGtE.mjs → logs-CYBhkQwh.mjs} +5 -3
  105. package/.output/server/chunks/build/logs-CYBhkQwh.mjs.map +1 -0
  106. package/.output/server/chunks/build/{monitor-mfG5jBtz.mjs → monitor-CyfDt4nR.mjs} +7 -6
  107. package/.output/server/chunks/build/{monitor-mfG5jBtz.mjs.map → monitor-CyfDt4nR.mjs.map} +1 -1
  108. package/.output/server/chunks/build/{pages-Dfosfchr.mjs → pages-C-6BRtv8.mjs} +57 -47
  109. package/.output/server/chunks/build/pages-C-6BRtv8.mjs.map +1 -0
  110. package/.output/server/chunks/build/{permissions-B-hhZuzm.mjs → permissions-B52oOmaO.mjs} +6 -5
  111. package/.output/server/chunks/build/permissions-B52oOmaO.mjs.map +1 -0
  112. package/.output/server/chunks/build/{plugins-DZR0T4Mh.mjs → plugins-dZRegC7m.mjs} +22 -18
  113. package/.output/server/chunks/build/plugins-dZRegC7m.mjs.map +1 -0
  114. package/.output/server/chunks/build/{segmented-LPPREMtZ.mjs → segmented-3TrWo0lS.mjs} +3 -3
  115. package/.output/server/chunks/build/{segmented-LPPREMtZ.mjs.map → segmented-3TrWo0lS.mjs.map} +1 -1
  116. package/.output/server/chunks/build/{settings-BajN9TQW.mjs → settings-CgDLkP3s.mjs} +437 -62
  117. package/.output/server/chunks/build/settings-CgDLkP3s.mjs.map +1 -0
  118. package/.output/server/chunks/build/{table-Bf1r2JjE.mjs → table-BjSWwmic.mjs} +4 -4
  119. package/.output/server/chunks/build/{table-Bf1r2JjE.mjs.map → table-BjSWwmic.mjs.map} +1 -1
  120. package/.output/server/chunks/build/{tag-NO9jEqKy.mjs → tag-DNE9vXc0.mjs} +3 -131
  121. package/.output/server/chunks/build/tag-DNE9vXc0.mjs.map +1 -0
  122. package/.output/server/chunks/build/{teams-t2SkRlJP.mjs → teams-2kz3CusY.mjs} +31 -30
  123. package/.output/server/chunks/build/teams-2kz3CusY.mjs.map +1 -0
  124. package/.output/server/chunks/build/{tokens-DiCojbN8.mjs → tokens-BbWLqtVz.mjs} +6 -5
  125. package/.output/server/chunks/build/tokens-BbWLqtVz.mjs.map +1 -0
  126. package/.output/server/chunks/build/town-BUqRobze.mjs +1 -0
  127. package/.output/server/chunks/build/town-BUqRobze.mjs.map +1 -1
  128. package/.output/server/chunks/build/{town-C7QM8DYK.mjs → town-DJ-V5G9U.mjs} +7 -5
  129. package/.output/server/chunks/build/town-DJ-V5G9U.mjs.map +1 -0
  130. package/.output/server/chunks/build/{useDaqStream-BeA2X8KR.mjs → useDaqStream-CIBaiGAl.mjs} +4 -3
  131. package/.output/server/chunks/build/useDaqStream-CIBaiGAl.mjs.map +1 -0
  132. package/.output/server/chunks/build/{useDcwStream-BJW_MitY.mjs → useDcwStream-CBbiYnWe.mjs} +4 -80
  133. package/.output/server/chunks/build/useDcwStream-CBbiYnWe.mjs.map +1 -0
  134. package/.output/server/chunks/build/{useDeviceTwins-Dwz_EY_i.mjs → useDeviceTwins-Yko6nNPF.mjs} +2 -2
  135. package/.output/server/chunks/build/{useDeviceTwins-Dwz_EY_i.mjs.map → useDeviceTwins-Yko6nNPF.mjs.map} +1 -1
  136. package/.output/server/chunks/build/{useOpsLog-Dm8QEb1I.mjs → useOpsLog-CO_VWh7t.mjs} +2 -2
  137. package/.output/server/chunks/build/{useOpsLog-Dm8QEb1I.mjs.map → useOpsLog-CO_VWh7t.mjs.map} +1 -1
  138. package/.output/server/chunks/build/{useWorkshopApi-B-L3MmIX.mjs → useWorkshopApi-NyjL0L3j.mjs} +4 -2
  139. package/.output/server/chunks/build/{useWorkshopApi-B-L3MmIX.mjs.map → useWorkshopApi-NyjL0L3j.mjs.map} +1 -1
  140. package/.output/server/chunks/build/{users-B9SAdEtH.mjs → users-4nzxTjFT.mjs} +6 -5
  141. package/.output/server/chunks/build/users-4nzxTjFT.mjs.map +1 -0
  142. package/.output/server/chunks/build/workshop-81xhz368.mjs +1 -0
  143. package/.output/server/chunks/build/workshop-81xhz368.mjs.map +1 -1
  144. package/.output/server/chunks/routes/api/health.get.mjs +1 -0
  145. package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
  146. package/.output/server/chunks/routes/api/index.get.mjs +1 -1
  147. package/.output/server/chunks/routes/api/index.post.mjs +1 -1
  148. package/.output/server/chunks/routes/api/metrics.mjs +1 -0
  149. package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
  150. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -0
  151. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
  152. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +1 -0
  153. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs.map +1 -1
  154. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs +26 -0
  155. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs.map +1 -0
  156. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +2 -1
  157. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs.map +1 -1
  158. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +32 -0
  159. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs.map +1 -0
  160. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +36 -0
  161. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs.map +1 -0
  162. package/.output/server/chunks/routes/api/system/config.get.mjs +1 -0
  163. package/.output/server/chunks/routes/api/system/config.get.mjs.map +1 -1
  164. package/.output/server/chunks/routes/api/system/index.get.mjs +7 -2
  165. package/.output/server/chunks/routes/api/system/index.get.mjs.map +1 -1
  166. package/.output/server/chunks/routes/api/system/index.patch.mjs +2 -1
  167. package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
  168. package/.output/server/chunks/routes/api/system/index.post.mjs +36 -0
  169. package/.output/server/chunks/routes/api/system/index.post.mjs.map +1 -0
  170. package/.output/server/chunks/routes/api/system/index2.get.mjs +28 -0
  171. package/.output/server/chunks/routes/api/system/index2.get.mjs.map +1 -0
  172. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +2 -1
  173. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs.map +1 -1
  174. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +2 -1
  175. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs.map +1 -1
  176. package/.output/server/chunks/routes/api/system/monitor.get.mjs +1 -0
  177. package/.output/server/chunks/routes/api/system/monitor.get.mjs.map +1 -1
  178. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +8 -5
  179. package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
  180. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +2 -1
  181. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
  182. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +2 -1
  183. package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
  184. package/.output/server/chunks/routes/api/users/_id_.get.mjs +2 -1
  185. package/.output/server/chunks/routes/api/users/_id_.get.mjs.map +1 -1
  186. package/.output/server/chunks/routes/api/users/_id_.put.mjs +1 -1
  187. package/.output/server/chunks/routes/api/users/index.get.mjs +2 -1
  188. package/.output/server/chunks/routes/api/users/index.get.mjs.map +1 -1
  189. package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
  190. package/.output/server/chunks/routes/api/users/login.post.mjs +1 -1
  191. package/.output/server/chunks/routes/api/users/logout.post.mjs +2 -1
  192. package/.output/server/chunks/routes/api/users/logout.post.mjs.map +1 -1
  193. package/.output/server/chunks/routes/api/users/me.get.mjs +2 -1
  194. package/.output/server/chunks/routes/api/users/me.get.mjs.map +1 -1
  195. package/.output/server/chunks/routes/api/users/register.post.mjs +1 -1
  196. package/.output/server/chunks/routes/api/users/setup-status.get.mjs +2 -1
  197. package/.output/server/chunks/routes/api/users/setup-status.get.mjs.map +1 -1
  198. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +2 -1
  199. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs.map +1 -1
  200. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +2 -1
  201. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs.map +1 -1
  202. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/_...path_.mjs +2 -1
  204. package/.output/server/chunks/routes/api/workshop/_...path_.mjs.map +1 -1
  205. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +2 -1
  206. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs.map +1 -1
  207. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +2 -1
  210. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs.map +1 -1
  211. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +5 -2
  212. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs.map +1 -1
  213. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +9 -3
  214. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs.map +1 -1
  215. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +2 -1
  216. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs.map +1 -1
  217. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +2 -1
  218. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
  219. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +23 -3
  220. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs.map +1 -1
  221. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +21 -3
  222. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
  223. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +2 -1
  224. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs.map +1 -1
  225. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +2 -1
  226. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs.map +1 -1
  227. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +2 -1
  228. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs.map +1 -1
  229. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
  231. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +75 -0
  232. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs.map +1 -0
  233. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +35 -0
  234. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs.map +1 -0
  235. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +35 -0
  236. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs.map +1 -0
  237. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +46 -0
  238. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs.map +1 -0
  239. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs +47 -0
  240. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs.map +1 -0
  241. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +48 -0
  242. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs.map +1 -0
  243. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +41 -0
  244. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs.map +1 -0
  245. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +62 -0
  246. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs.map +1 -0
  247. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +35 -0
  248. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs.map +1 -0
  249. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +36 -0
  250. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs.map +1 -0
  251. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +34 -0
  252. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs.map +1 -0
  253. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +38 -0
  254. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs.map +1 -0
  255. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +37 -0
  256. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs.map +1 -0
  257. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +42 -0
  258. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs.map +1 -0
  259. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +2 -1
  260. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs.map +1 -1
  261. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +2 -1
  262. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs.map +1 -1
  263. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +2 -1
  264. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs.map +1 -1
  265. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +2 -1
  266. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs.map +1 -1
  267. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +2 -1
  268. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs.map +1 -1
  269. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -0
  270. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs.map +1 -1
  271. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +2 -1
  272. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs.map +1 -1
  273. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +2 -1
  274. package/.output/server/chunks/routes/api/workshop/audit.get.mjs.map +1 -1
  275. package/.output/server/chunks/routes/api/workshop/caller.mjs +2 -1
  276. package/.output/server/chunks/routes/api/workshop/caller.mjs.map +1 -1
  277. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +2 -2
  278. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +2 -1
  279. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs.map +1 -1
  280. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +2 -1
  281. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs.map +1 -1
  282. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
  283. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
  284. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -1
  285. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs.map +1 -1
  286. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +2 -1
  287. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs.map +1 -1
  288. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
  289. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +2 -1
  290. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs.map +1 -1
  291. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
  292. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +2 -1
  293. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs.map +1 -1
  294. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +2 -1
  295. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs.map +1 -1
  296. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +2 -1
  297. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs.map +1 -1
  298. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +2 -1
  299. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs.map +1 -1
  300. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +2 -1
  301. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs.map +1 -1
  302. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +2 -1
  303. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs.map +1 -1
  304. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
  305. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +2 -1
  306. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs.map +1 -1
  307. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
  308. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +2 -1
  309. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs.map +1 -1
  310. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +2 -1
  311. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs.map +1 -1
  312. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
  313. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +1 -1
  314. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  315. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +2 -1
  316. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
  317. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  318. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -0
  319. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs.map +1 -1
  320. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +2 -1
  321. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs.map +1 -1
  322. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +2 -1
  323. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs.map +1 -1
  324. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -1
  325. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs.map +1 -1
  326. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +1 -0
  327. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs.map +1 -1
  328. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -1
  329. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs.map +1 -1
  330. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
  331. package/.output/server/chunks/routes/api/workshop/channels.get.mjs +1 -0
  332. package/.output/server/chunks/routes/api/workshop/channels.get.mjs.map +1 -1
  333. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +4 -4
  334. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +2 -1
  335. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs.map +1 -1
  336. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +2 -1
  337. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs.map +1 -1
  338. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +2 -1
  339. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs.map +1 -1
  340. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +2 -1
  341. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs.map +1 -1
  342. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +2 -1
  343. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
  344. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -1
  345. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs.map +1 -1
  346. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +3 -1
  347. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs.map +1 -1
  348. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +2 -1
  349. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
  350. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +2 -1
  351. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs.map +1 -1
  352. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -1
  353. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs.map +1 -1
  354. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +2 -1
  355. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs.map +1 -1
  356. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -1
  357. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
  358. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -1
  359. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs.map +1 -1
  360. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -1
  361. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs.map +1 -1
  362. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -1
  363. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
  364. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -1
  365. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
  366. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -1
  367. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs.map +1 -1
  368. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +2 -1
  369. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs.map +1 -1
  370. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +2 -1
  371. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs.map +1 -1
  372. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -1
  373. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs.map +1 -1
  374. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +2 -1
  375. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs.map +1 -1
  376. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +2 -1
  377. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs.map +1 -1
  378. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +2 -1
  379. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
  380. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -1
  381. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
  382. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +7 -2
  383. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs.map +1 -1
  384. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -1
  385. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs.map +1 -1
  386. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -1
  387. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs.map +1 -1
  388. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +2 -1
  389. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs.map +1 -1
  390. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +2 -1
  391. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs.map +1 -1
  392. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +2 -1
  393. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
  394. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -1
  395. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs.map +1 -1
  396. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -1
  397. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
  398. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -1
  399. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
  400. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -1
  401. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
  402. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +2 -1
  403. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
  404. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -1
  405. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs.map +1 -1
  406. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +2 -1
  407. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
  408. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +2 -1
  409. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs.map +1 -1
  410. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +2 -1
  411. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs.map +1 -1
  412. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -1
  413. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs.map +1 -1
  414. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -1
  415. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
  416. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -1
  417. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs.map +1 -1
  418. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -1
  419. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs.map +1 -1
  420. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -1
  421. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs.map +1 -1
  422. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -1
  423. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs.map +1 -1
  424. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -1
  425. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs.map +1 -1
  426. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -1
  427. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs.map +1 -1
  428. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -1
  429. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs.map +1 -1
  430. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -1
  431. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs.map +1 -1
  432. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +2 -1
  433. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs.map +1 -1
  434. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -1
  435. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs.map +1 -1
  436. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +2 -1
  437. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs.map +1 -1
  438. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -1
  439. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs.map +1 -1
  440. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +2 -1
  441. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs.map +1 -1
  442. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -1
  443. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs.map +1 -1
  444. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +2 -1
  445. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs.map +1 -1
  446. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -1
  447. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs.map +1 -1
  448. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -1
  449. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs.map +1 -1
  450. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -1
  451. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs.map +1 -1
  452. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -1
  453. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs.map +1 -1
  454. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +2 -1
  455. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs.map +1 -1
  456. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +2 -1
  457. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs.map +1 -1
  458. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -1
  459. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs.map +1 -1
  460. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -1
  461. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs.map +1 -1
  462. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +2 -1
  463. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs.map +1 -1
  464. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +32 -1
  465. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs.map +1 -1
  466. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +2 -1
  467. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs.map +1 -1
  468. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +2 -1
  469. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -1
  470. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +3 -2
  471. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -1
  472. package/.output/server/chunks/routes/api/workshop/index.get.mjs +1 -0
  473. package/.output/server/chunks/routes/api/workshop/index.get.mjs.map +1 -1
  474. package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
  475. package/.output/server/chunks/routes/api/workshop/index.put.mjs +2 -1
  476. package/.output/server/chunks/routes/api/workshop/index.put.mjs.map +1 -1
  477. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +12 -6
  478. package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
  479. package/.output/server/chunks/routes/api/workshop/index11.get.mjs +4 -2
  480. package/.output/server/chunks/routes/api/workshop/index11.get.mjs.map +1 -1
  481. package/.output/server/chunks/routes/api/workshop/index12.get.mjs +28 -0
  482. package/.output/server/chunks/routes/api/workshop/index12.get.mjs.map +1 -0
  483. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +17 -11
  484. package/.output/server/chunks/routes/api/workshop/index2.get.mjs.map +1 -1
  485. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
  486. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +11 -4
  487. package/.output/server/chunks/routes/api/workshop/index3.get.mjs.map +1 -1
  488. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +2 -1
  489. package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
  490. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +5 -27
  491. package/.output/server/chunks/routes/api/workshop/index4.get.mjs.map +1 -1
  492. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -1
  493. package/.output/server/chunks/routes/api/workshop/index4.post.mjs.map +1 -1
  494. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +24 -18
  495. package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
  496. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -1
  497. package/.output/server/chunks/routes/api/workshop/index5.post.mjs.map +1 -1
  498. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +23 -5
  499. package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
  500. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -1
  501. package/.output/server/chunks/routes/api/workshop/index6.post.mjs.map +1 -1
  502. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +4 -17
  503. package/.output/server/chunks/routes/api/workshop/index7.get.mjs.map +1 -1
  504. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +8 -3
  505. package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
  506. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +20 -21
  507. package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
  508. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
  509. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +24 -11
  510. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  511. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +1 -0
  512. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs.map +1 -1
  513. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +1 -0
  514. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs.map +1 -1
  515. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +2 -1
  516. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs.map +1 -1
  517. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +2 -1
  518. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs.map +1 -1
  519. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +2 -1
  520. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs.map +1 -1
  521. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +2 -1
  522. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs.map +1 -1
  523. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +1 -0
  524. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs.map +1 -1
  525. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +2 -1
  526. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs.map +1 -1
  527. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +2 -1
  528. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs.map +1 -1
  529. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +1 -0
  530. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs.map +1 -1
  531. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
  532. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
  533. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +2 -1
  534. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs.map +1 -1
  535. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
  536. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +2 -1
  537. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs.map +1 -1
  538. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +2 -1
  539. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs.map +1 -1
  540. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +1 -0
  541. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs.map +1 -1
  542. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
  543. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +2 -1
  544. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs.map +1 -1
  545. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
  546. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +44 -0
  547. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs.map +1 -0
  548. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +47 -0
  549. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs.map +1 -0
  550. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +2 -1
  551. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs.map +1 -1
  552. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +2 -1
  553. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs.map +1 -1
  554. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +2 -1
  555. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs.map +1 -1
  556. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
  557. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +2 -0
  558. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs.map +1 -1
  559. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +1 -1
  560. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
  561. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +1 -0
  562. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs.map +1 -1
  563. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +1 -0
  564. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs.map +1 -1
  565. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +1 -0
  566. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs.map +1 -1
  567. package/.output/server/chunks/routes/renderer.mjs +2 -2
  568. package/.output/server/chunks/virtual/entry.mjs +601 -36
  569. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  570. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  571. package/.output/server/index.mjs +1 -0
  572. package/.output/server/node_modules/@anthropic-ai/claude-agent-sdk/package.json +84 -0
  573. package/.output/server/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs +225 -0
  574. package/.output/server/package.json +2 -1
  575. package/README-zh.md +507 -478
  576. package/README.md +517 -486
  577. package/app/app.vue +17 -2
  578. package/app/assets/css/main.css +421 -30
  579. package/app/components/AppHeader.vue +17 -0
  580. package/app/components/AppSidebar.vue +162 -63
  581. package/app/components/AwChart.vue +57 -54
  582. package/app/components/workshop/ChannelSessionList.vue +802 -703
  583. package/app/components/workshop/DaqNodeRow.vue +156 -0
  584. package/app/components/workshop/PluginSlot.vue +120 -0
  585. package/app/composables/workshop/useAmlStream.ts +136 -0
  586. package/app/composables/workshop/useDaqStream.ts +8 -1
  587. package/app/composables/workshop/usePluginPanels.ts +72 -0
  588. package/app/composables/workshop/useWorkshopApi.ts +7 -0
  589. package/app/pages/aml/index.vue +1949 -0
  590. package/app/pages/daq/[id].vue +60 -2
  591. package/app/pages/daq/index.vue +7 -148
  592. package/app/pages/index.vue +235 -213
  593. package/app/pages/plugins/index.vue +280 -274
  594. package/app/pages/settings.vue +555 -78
  595. package/app/pages/workshop/agents.vue +23 -1
  596. package/app/pages/workshop/teams.vue +2 -2
  597. package/app/plugins/aw-plugins.client.ts +95 -6
  598. package/app/plugins/runtime-config.client.ts +4 -14
  599. package/app/plugins/theme.client.ts +13 -3
  600. package/app/stores/app.ts +9 -2
  601. package/app/stores/runtime-config.ts +113 -7
  602. package/cli/aw.mjs +16 -3
  603. package/cli/commands/build.mjs +8 -8
  604. package/cli/commands/dev.mjs +5 -13
  605. package/cli/commands/init.mjs +1 -1
  606. package/cli/commands/start.mjs +10 -17
  607. package/cli/core/args.mjs +85 -4
  608. package/cli/core/child-lifecycle.mjs +136 -0
  609. package/config.yml +24 -0
  610. package/docs/plugins.md +128 -220
  611. package/docs/sdk.md +1 -1
  612. package/i18n/dicts/_en.json +43 -2
  613. package/i18n/dicts/aml.json +163 -0
  614. package/i18n/dicts/channelSessionList.json +4 -1
  615. package/i18n/dicts/daqDetail.json +1 -0
  616. package/i18n/dicts/settings.json +33 -1
  617. package/i18n/dicts/teams.json +9 -1
  618. package/i18n/locales/en.ts +364 -132
  619. package/i18n/locales/zh-CN.ts +433 -201
  620. package/nuxt.config.ts +18 -3
  621. package/package.json +153 -149
  622. package/scripts/_audit/.tmp/audit-data/dcws.json +28 -0
  623. package/scripts/_audit/.tmp/dcw-writes.json +15650 -0
  624. package/scripts/_audit/.tmp/dcws.json +9033 -0
  625. package/scripts/_audit/.tmp/pollution-backup/dcw-rollback.polluted.json +470006 -0
  626. package/scripts/_audit/.tmp/pollution-backup/dcws.polluted.json +9085 -0
  627. package/scripts/_audit/.tmp/probe-cwd.txt +1 -0
  628. package/scripts/_audit/audit-harness-adapters.md +664 -0
  629. package/scripts/_audit/awhome/commands/README.md +3 -0
  630. package/scripts/_audit/awhome/commands/hello.mjs +12 -0
  631. package/scripts/_audit/dcw-controller-e2e.ts +99 -0
  632. package/scripts/_audit/dcw-flush-cost.ts +43 -0
  633. package/scripts/_audit/dcw-rollback-ledger.ts +153 -0
  634. package/scripts/_audit/dcw-unrecorded-write.ts +171 -0
  635. package/scripts/_audit/dcw-write-mutex.ts +157 -0
  636. package/scripts/_audit/diag-cwd.ts +20 -0
  637. package/scripts/_audit/diag-cwd2.ts +19 -0
  638. package/scripts/_audit/exp-cost-scaling.mjs +54 -0
  639. package/scripts/_audit/exp-envelope-and-png.mjs +77 -0
  640. package/scripts/_audit/exp-png-decode.mjs +67 -0
  641. package/scripts/_audit/exp-retention-plan.mjs +61 -0
  642. package/scripts/_audit/exp-retention-rescan.mjs +42 -0
  643. package/scripts/_audit/exp-sweep-fairness.mjs +48 -0
  644. package/scripts/_audit/hello.mjs +12 -0
  645. package/scripts/_audit/http-api-authz-audit.md +657 -0
  646. package/scripts/_audit/ndjson-partial-line-repro.mjs +77 -0
  647. package/scripts/_audit/opencode-await-ternary-repro.mjs +20 -0
  648. package/scripts/_audit/part-frag.txt +84 -0
  649. package/scripts/_audit/part-head.txt +45 -0
  650. package/scripts/_audit/probe-binding.mjs +103 -0
  651. package/scripts/_audit/probe-child.mjs +17 -0
  652. package/scripts/_audit/probe-envelope.mjs +49 -0
  653. package/scripts/_audit/probe-packlist.mjs +67 -0
  654. package/scripts/_audit/probe-routes.mjs +47 -0
  655. package/scripts/_audit/probe-routes2.mjs +38 -0
  656. package/scripts/_audit/probe.ts +9 -0
  657. package/scripts/_audit/probe2.ts +6 -0
  658. package/scripts/_audit/probe3.ts +3 -0
  659. package/scripts/_audit/probe4.ts +3 -0
  660. package/scripts/_audit/proj/.AgentWorkShop/commands/echoargs.mjs +13 -0
  661. package/scripts/_audit/proj/config.yml +1 -0
  662. package/scripts/_audit/run.mjs +30 -0
  663. package/scripts/_audit/runtime-audit.md +716 -0
  664. package/scripts/_audit/ts-resolve-hook.mjs +41 -0
  665. package/scripts/_audit/tsconfig.probe.json +24 -0
  666. package/scripts/_audit/typecheck-out.txt +466 -0
  667. package/scripts/_audit/verify-data-integrity.mjs +112 -0
  668. package/scripts/_dbg-agents-dropdown-shot.py +33 -0
  669. package/scripts/_dbg-anim-verify.mjs +1 -1
  670. package/scripts/_dbg-audit-all-pages.mjs +1 -1
  671. package/scripts/_dbg-availability-probe.ts +11 -0
  672. package/scripts/_dbg-bind-bidi-e2e.mjs +1 -1
  673. package/scripts/_dbg-cf-line-shot.mjs +18 -0
  674. package/scripts/_dbg-channel-plugin-ui.mjs +94 -0
  675. package/scripts/_dbg-configroot-audit.mjs +84 -0
  676. package/scripts/_dbg-crash-recovery.mjs +1 -1
  677. package/scripts/_dbg-crush-probe.sh +21 -0
  678. package/scripts/_dbg-crush-spawn-probe.ts +22 -0
  679. package/scripts/_dbg-daq-acc-probe.mjs +1 -1
  680. package/scripts/_dbg-daq-attrib.mjs +1 -1
  681. package/scripts/_dbg-daq-debug.mjs +1 -1
  682. package/scripts/_dbg-daq-diag.mjs +1 -1
  683. package/scripts/_dbg-daq-e2e.mjs +1 -1
  684. package/scripts/_dbg-daq-filter-e2e.mjs +1 -1
  685. package/scripts/_dbg-daq-filter-e2e2.mjs +1 -1
  686. package/scripts/_dbg-daq-final-regression.mjs +1 -1
  687. package/scripts/_dbg-daq-frame-alarm.mjs +1 -1
  688. package/scripts/_dbg-daq-frame-ui.mjs +1 -1
  689. package/scripts/_dbg-daq-frame-ws.mjs +1 -1
  690. package/scripts/_dbg-daq-frames-e2e.mjs +1 -1
  691. package/scripts/_dbg-daq-full-check.mjs +1 -1
  692. package/scripts/_dbg-daq-intervals-func.mjs +94 -0
  693. package/scripts/_dbg-daq-pages-shot.mjs +1 -1
  694. package/scripts/_dbg-daq-perf.mjs +1 -1
  695. package/scripts/_dbg-daq-probe.mjs +1 -1
  696. package/scripts/_dbg-daq-recipe-e2e.mjs +1 -1
  697. package/scripts/_dbg-daq-rows-probe.mjs +1 -1
  698. package/scripts/_dbg-daq-rowstate-e2e.mjs +1 -1
  699. package/scripts/_dbg-daq-rowstate-shot.mjs +1 -1
  700. package/scripts/_dbg-daq-rowstate-shot2.mjs +1 -1
  701. package/scripts/_dbg-daq-rowstyle-verify.mjs +112 -0
  702. package/scripts/_dbg-dash-console-check.mjs +1 -1
  703. package/scripts/_dbg-dash-deep-probe.mjs +1 -1
  704. package/scripts/_dbg-dash-hitpoint.mjs +1 -1
  705. package/scripts/_dbg-dcw-read-rest.mjs +1 -1
  706. package/scripts/_dbg-dcw-read-ui.mjs +1 -1
  707. package/scripts/_dbg-dcw-shot2.mjs +1 -1
  708. package/scripts/_dbg-diag-mock-loop.mjs +89 -0
  709. package/scripts/_dbg-diag-watch.mjs +95 -0
  710. package/scripts/_dbg-error-probe.mjs +2 -2
  711. package/scripts/_dbg-filter-light-verify.mjs +1 -1
  712. package/scripts/_dbg-final-acceptance-2.mjs +1 -1
  713. package/scripts/_dbg-final-acceptance.mjs +1 -1
  714. package/scripts/_dbg-final-full-e2e.mjs +1 -1
  715. package/scripts/_dbg-final-shots.mjs +32 -0
  716. package/scripts/_dbg-final-t6-hitl.mjs +1 -1
  717. package/scripts/_dbg-fix-unused-imports.py +41 -0
  718. package/scripts/_dbg-fresh-scene-e2e.mjs +1 -1
  719. package/scripts/_dbg-goose-probe.mjs +33 -0
  720. package/scripts/_dbg-goose-probe.sh +10 -0
  721. package/scripts/_dbg-groups-ui-verify.mjs +122 -0
  722. package/scripts/_dbg-harness-ui-shot.py +109 -0
  723. package/scripts/_dbg-hidden-check.mjs +1 -1
  724. package/scripts/_dbg-home-repro.mjs +1 -1
  725. package/scripts/_dbg-home-stack.mjs +1 -1
  726. package/scripts/_dbg-hydration-detail.mjs +1 -1
  727. package/scripts/_dbg-infra-lifecycle.mjs +1 -1
  728. package/scripts/_dbg-line-live-e2e.mjs +1 -1
  729. package/scripts/_dbg-line-repo-test.ts +10 -0
  730. package/scripts/_dbg-login-debug.py +23 -0
  731. package/scripts/_dbg-modbus-latency.mjs +22 -0
  732. package/scripts/_dbg-mqtt-chain-e2e.mjs +1 -1
  733. package/scripts/_dbg-oneshot-impl-probe.ts +67 -0
  734. package/scripts/_dbg-opt-team-e2e.mjs +1 -1
  735. package/scripts/_dbg-panesplitter-fix-check.mjs +1 -1
  736. package/scripts/_dbg-phase-e3-monitor.mjs +1 -1
  737. package/scripts/_dbg-pi-spawn-probe.ts +33 -0
  738. package/scripts/_dbg-plc-e2e.mjs +1 -1
  739. package/scripts/_dbg-plugin-config-ui.mjs +111 -0
  740. package/scripts/_dbg-plugin-panels-ui.mjs +54 -0
  741. package/scripts/_dbg-plugin-sink-rest.mjs +1 -1
  742. package/scripts/_dbg-plugin-sink-ui.mjs +1 -1
  743. package/scripts/_dbg-plugin-ui-wizard.mjs +1 -1
  744. package/scripts/_dbg-plugin-verify-e2e.mjs +1 -1
  745. package/scripts/_dbg-pop-clamp-verify.mjs +1 -1
  746. package/scripts/_dbg-preview-console.mjs +1 -1
  747. package/scripts/_dbg-preview-minrepro.mjs +1 -1
  748. package/scripts/_dbg-preview-pixels.mjs +1 -1
  749. package/scripts/_dbg-quality-pages-e2e.mjs +1 -1
  750. package/scripts/_dbg-qwen-acp-probe.mjs +30 -0
  751. package/scripts/_dbg-qwen-capture.mjs +21 -0
  752. package/scripts/_dbg-rail-tree-e2e.mjs +1 -1
  753. package/scripts/_dbg-real-driver-e2e.mjs +1 -1
  754. package/scripts/_dbg-real-scenario-timeline.log +55 -123
  755. package/scripts/_dbg-redesign-shots.mjs +1 -1
  756. package/scripts/_dbg-release-smoke.mjs +1 -1
  757. package/scripts/_dbg-resolve-probe.ts +6 -0
  758. package/scripts/_dbg-restart-persist.mjs +1 -1
  759. package/scripts/_dbg-sc001-dispatch.mjs +1 -1
  760. package/scripts/_dbg-scenario-final-shot.mjs +1 -1
  761. package/scripts/_dbg-scenario-phase-e2.mjs +1 -1
  762. package/scripts/_dbg-scenario-phase-e3.mjs +1 -1
  763. package/scripts/_dbg-scenario-phase1.mjs +1 -1
  764. package/scripts/_dbg-scenario-phase2.mjs +1 -1
  765. package/scripts/_dbg-scenario-phase3-monitor.mjs +1 -1
  766. package/scripts/_dbg-scenario-phase3.mjs +1 -1
  767. package/scripts/_dbg-settings-draft-probe.mjs +39 -0
  768. package/scripts/_dbg-settings-probe.mjs +33 -0
  769. package/scripts/_dbg-task-cancel-probe.mjs +66 -0
  770. package/scripts/_dbg-town-alarm-e2e.mjs +1 -1
  771. package/scripts/_dbg-town-daq-shot.mjs +1 -1
  772. package/scripts/_dbg-town-full-e2e.mjs +1 -1
  773. package/scripts/_dbg-town-gate.mjs +1 -1
  774. package/scripts/_dbg-town-ins-probe.mjs +1 -1
  775. package/scripts/_dbg-town-perf.mjs +1 -1
  776. package/scripts/_dbg-town-realtime.mjs +1 -1
  777. package/scripts/_dbg-town-shot.py +25 -0
  778. package/scripts/_dbg-town-shot3.mjs +1 -1
  779. package/scripts/_dbg-town-smoke.mjs +54 -0
  780. package/scripts/_dbg-town-truth.mjs +1 -1
  781. package/scripts/_dbg-town-truth2.mjs +1 -1
  782. package/scripts/_dbg-trend-expand-test.mjs +1 -1
  783. package/scripts/_dbg-twindaq-focus.mjs +1 -1
  784. package/scripts/_dbg-ui-polish-shot.mjs +1 -1
  785. package/scripts/_dbg-ui-polish-verify1.mjs +1 -1
  786. package/scripts/_dbg-ui-polish-verify2.mjs +1 -1
  787. package/scripts/_dbg-ui-polish-verify3.mjs +1 -1
  788. package/scripts/_dbg-ui-polish-verify4.mjs +1 -1
  789. package/scripts/_dbg-unify-shot.mjs +1 -1
  790. package/scripts/_dbg-uplink-probe.mjs +1 -1
  791. package/scripts/_dbg-wizard-preview-shot.mjs +1 -1
  792. package/scripts/_dbg-wizard-ui-e2e.mjs +1 -1
  793. package/scripts/_dbg-ws-probe.mjs +1 -1
  794. package/scripts/_dbg-wsdot-sanity.mjs +1 -1
  795. package/scripts/_node-state-probe.mjs +1 -1
  796. package/scripts/_tmp-args-probe.mjs +20 -0
  797. package/scripts/_tmp-cyc-entry.mjs +8 -0
  798. package/scripts/_tmp-cyc-main.mjs +5 -0
  799. package/scripts/_tmp-cyc-mod.mjs +2 -0
  800. package/scripts/_tmp-cycle-a.mjs +6 -0
  801. package/scripts/_tmp-cycle-b.mjs +2 -0
  802. package/scripts/_tmp-cycle-probe.mjs +4 -0
  803. package/scripts/_tmp-entry-variant.mjs +2 -0
  804. package/scripts/_tmp-help-probe.mjs +19 -0
  805. package/scripts/_tmp-help-probe2.mjs +2 -0
  806. package/scripts/_tmp-trace-preload.mjs +1 -0
  807. package/scripts/aml-agent-bridge.ts +230 -0
  808. package/scripts/aml-industrial-loop.ts +232 -0
  809. package/scripts/aml-ui-smoke.mjs +67 -0
  810. package/scripts/aw-start-smoke.mjs +194 -0
  811. package/scripts/design-verify-templates.mjs +1 -1
  812. package/scripts/device-line-restore.mjs +1 -1
  813. package/scripts/e2e-aml.ts +259 -0
  814. package/scripts/e2e-config-groups.mjs +238 -0
  815. package/scripts/e2e-full-closedloop.mjs +911 -0
  816. package/scripts/e2e-full-scenario.ts +321 -0
  817. package/scripts/e2e-harness-consistency.ts +204 -0
  818. package/scripts/e2e-multi-harness.ts +233 -76
  819. package/scripts/e2e-plc-plugin-closedloop.mjs +518 -0
  820. package/scripts/e2e-real-scenario.mjs +466 -452
  821. package/scripts/e2e-template-isolation.mjs +2 -2
  822. package/scripts/experiment-castfilm-closedloop.mjs +423 -0
  823. package/scripts/experiment-castfilm-finish.mjs +194 -0
  824. package/scripts/experiment-castfilm-ui-shot.mjs +52 -0
  825. package/scripts/experiment-castfilm-viz.mjs +172 -0
  826. package/scripts/production-closed-loop-e2e.mjs +74 -28
  827. package/scripts/test-aml-integration.ts +159 -0
  828. package/scripts/test-aml-job.ts +174 -0
  829. package/scripts/test-aml-unit.ts +184 -0
  830. package/scripts/test-cli-exit.mjs +235 -0
  831. package/scripts/test-daq-frame-race.mjs +310 -0
  832. package/scripts/test-data-root.mjs +208 -0
  833. package/scripts/test-log-flooding.mjs +160 -0
  834. package/scripts/test-lru.mjs +78 -0
  835. package/scripts/test-memory-month-query.mjs +62 -0
  836. package/scripts/test-plugin-hardening.mjs +45 -0
  837. package/scripts/test-rollback-index.mjs +79 -0
  838. package/scripts/test-sdk-surface.mjs +155 -0
  839. package/scripts/three-system-e2e.mjs +662 -448
  840. package/scripts/town-scene-clear.mjs +1 -1
  841. package/sdk/client.d.mts +110 -0
  842. package/sdk/client.mjs +144 -124
  843. package/sdk/context.mjs +161 -1
  844. package/sdk/index.d.mts +37 -5
  845. package/sdk/index.mjs +44 -41
  846. package/sdk/lifecycle.mjs +4 -1
  847. package/server/api/plugins/i18n.get.ts +12 -0
  848. package/server/api/system/config-groups/[id].delete.ts +21 -0
  849. package/server/api/system/config-groups/[id].patch.ts +26 -0
  850. package/server/api/system/config-groups/index.get.ts +21 -0
  851. package/server/api/system/config-groups/index.post.ts +33 -0
  852. package/server/api/system/settings/events.get.ts +8 -4
  853. package/server/api/workshop/agent-tools/bindings/[id].delete.ts +6 -1
  854. package/server/api/workshop/agent-tools/bindings/[id].patch.ts +12 -3
  855. package/server/api/workshop/agent-tools/bindings/index.get.ts +29 -2
  856. package/server/api/workshop/agent-tools/invoke.post.ts +30 -5
  857. package/server/api/workshop/aml/datasets/[id]/preview.get.ts +68 -0
  858. package/server/api/workshop/aml/datasets/[id].get.ts +24 -0
  859. package/server/api/workshop/aml/datasets/index.get.ts +20 -0
  860. package/server/api/workshop/aml/datasets/index.post.ts +27 -0
  861. package/server/api/workshop/aml/experiments/index.get.ts +35 -0
  862. package/server/api/workshop/aml/index.get.ts +24 -0
  863. package/server/api/workshop/aml/jobs/[id]/cancel.post.ts +21 -0
  864. package/server/api/workshop/aml/jobs/[id]/logs.get.ts +23 -0
  865. package/server/api/workshop/aml/jobs/[id]/retry.post.ts +20 -0
  866. package/server/api/workshop/aml/jobs/[id].get.ts +23 -0
  867. package/server/api/workshop/aml/jobs/index.get.ts +26 -0
  868. package/server/api/workshop/aml/jobs/index.post.ts +44 -0
  869. package/server/api/workshop/aml/models/[id]/predict.post.ts +24 -0
  870. package/server/api/workshop/aml/models/[id]/promote.post.ts +30 -0
  871. package/server/api/workshop/aml/models/index.get.ts +48 -0
  872. package/server/api/workshop/daq/[id].delete.ts +6 -0
  873. package/server/api/workshop/dcw/[id].patch.ts +14 -2
  874. package/server/api/workshop/hitl/respond.post.ts +3 -1
  875. package/server/api/workshop/teams/[id]/plugins/index.get.ts +36 -0
  876. package/server/api/workshop/teams/[id]/plugins/index.put.ts +42 -0
  877. package/server/api/workshop/teams/index.post.ts +13 -0
  878. package/server/api/workshop/users/me.get.ts +5 -0
  879. package/server/api/workshop/ws.ts +14 -2
  880. package/server/data/daqs.json +1648 -123
  881. package/server/data/dcw-lines.json +301 -0
  882. package/server/data/dcw-products.json +140 -0
  883. package/server/data/dcw-recipes.json +890 -0
  884. package/server/data/dcw-rollback.json +11591 -5740
  885. package/server/data/dcw-runs.json +3745 -3559
  886. package/server/data/dcw-templates.json +120 -0
  887. package/server/data/dcw-writes.json +1800 -0
  888. package/server/data/dcws.json +1576 -287
  889. package/server/data/line-runs.json +137 -27
  890. package/server/harness/pi-aw-tools.mjs +51 -0
  891. package/server/plugins/dev-stability-guard.ts +63 -63
  892. package/server/plugins/system-config.ts +10 -11
  893. package/server/plugins/workshop.ts +10 -0
  894. package/server/plugins-builtin/diag-bridge/client.mjs +84 -0
  895. package/server/plugins-builtin/diag-bridge/i18n.json +72 -0
  896. package/server/plugins-builtin/diag-bridge/index.mjs +127 -22
  897. package/server/plugins-builtin/rag-bridge/client.mjs +108 -0
  898. package/server/plugins-builtin/rag-bridge/i18n.json +60 -0
  899. package/server/plugins-builtin/rag-bridge/index.mjs +67 -20
  900. package/server/services/system-config.ts +610 -396
  901. package/server/services/workshop/agents/adapters/line-spawn.ts +15 -6
  902. package/server/services/workshop/agents/adapters/one-shot-cli-agent.ts +530 -0
  903. package/server/services/workshop/agents/base-agent.ts +210 -0
  904. package/server/services/workshop/agents/binding-authz.ts +57 -0
  905. package/server/services/workshop/agents/claude-agent.ts +546 -30
  906. package/server/services/workshop/agents/codex-agent.ts +729 -822
  907. package/server/services/workshop/agents/copilot-agent.ts +136 -0
  908. package/server/services/workshop/agents/crush-agent.ts +107 -0
  909. package/server/services/workshop/agents/cursor-agent.ts +102 -0
  910. package/server/services/workshop/agents/dsh-agent.ts +578 -670
  911. package/server/services/workshop/agents/gemini-agent.ts +121 -0
  912. package/server/services/workshop/agents/goose-agent.ts +98 -0
  913. package/server/services/workshop/agents/harness-models.ts +305 -270
  914. package/server/services/workshop/agents/hermes-agent.ts +528 -0
  915. package/server/services/workshop/agents/host-tool-bridge.ts +53 -2
  916. package/server/services/workshop/agents/industrial-tools.ts +659 -7
  917. package/server/services/workshop/agents/omp-agent.ts +74 -59
  918. package/server/services/workshop/agents/opencode-agent.ts +936 -987
  919. package/server/services/workshop/agents/pi-agent.ts +108 -0
  920. package/server/services/workshop/agents/qwen-agent.ts +540 -0
  921. package/server/services/workshop/agents/registry.ts +117 -5
  922. package/server/services/workshop/agents/tool-approvals.ts +3 -3
  923. package/server/services/workshop/aml/aml.repo.ts +368 -0
  924. package/server/services/workshop/aml/clean.ts +120 -0
  925. package/server/services/workshop/aml/dataset-builder.ts +491 -0
  926. package/server/services/workshop/aml/gates.ts +121 -0
  927. package/server/services/workshop/aml/job-orchestrator.ts +650 -0
  928. package/server/services/workshop/aml/model-registry.ts +169 -0
  929. package/server/services/workshop/aml/predictor.ts +262 -0
  930. package/server/services/workshop/aml/python/aml_eval.py +171 -0
  931. package/server/services/workshop/aml/python/amlkit.py +120 -0
  932. package/server/services/workshop/aml/python/requirements.txt +7 -0
  933. package/server/services/workshop/aml/python/train-example.py +92 -0
  934. package/server/services/workshop/aml/python-runtime.ts +217 -0
  935. package/server/services/workshop/aml/retention.ts +98 -0
  936. package/server/services/workshop/aml/runtime.ts +45 -0
  937. package/server/services/workshop/aml/spec.ts +63 -0
  938. package/server/services/workshop/aml/stats.ts +140 -0
  939. package/server/services/workshop/daq/bus/mqtt.adapter.ts +8 -1
  940. package/server/services/workshop/daq/daq-controller.ts +147 -19
  941. package/server/services/workshop/daq/daq-node.repo.ts +13 -11
  942. package/server/services/workshop/daq/daq-runtime.ts +11 -0
  943. package/server/services/workshop/daq/drivers.ts +89 -8
  944. package/server/services/workshop/db/aml-team-seeds.ts +118 -0
  945. package/server/services/workshop/db/channel-plugins.repo.ts +27 -1
  946. package/server/services/workshop/db/database.ts +89 -1
  947. package/server/services/workshop/db/memory.repo.ts +31 -0
  948. package/server/services/workshop/db/user.repo.ts +9 -0
  949. package/server/services/workshop/dcw/dcw-controller.ts +33 -7
  950. package/server/services/workshop/dcw/dcw-line.repo.ts +5 -3
  951. package/server/services/workshop/dcw/dcw-node.repo.ts +4 -4
  952. package/server/services/workshop/dcw/dcw-product.repo.ts +8 -8
  953. package/server/services/workshop/dcw/dcw-recipe.repo.ts +6 -7
  954. package/server/services/workshop/dcw/dcw-runtime.ts +16 -2
  955. package/server/services/workshop/dcw/dcw-templates.ts +4 -4
  956. package/server/services/workshop/dcw/line-run.ts +5 -5
  957. package/server/services/workshop/dcw/recipe-rollback-manager.ts +3 -1
  958. package/server/services/workshop/dcw/recipe-rollback.repo.ts +155 -52
  959. package/server/services/workshop/logger.ts +145 -3
  960. package/server/services/workshop/plugins/host.mjs +857 -566
  961. package/server/services/workshop/prompts/loader.ts +32 -6
  962. package/server/services/workshop/runtime/manager.ts +53 -13
  963. package/server/services/workshop/runtime/scheduler-loop.ts +18 -1
  964. package/server/services/workshop/scene/scene-layout.repo.ts +5 -5
  965. package/server/services/workshop/settings.ts +64 -0
  966. package/shared/config/engine.mjs +5 -0
  967. package/shared/config/groups.mjs +220 -0
  968. package/shared/config/home.mjs +11 -2
  969. package/shared/config/schema.json +31 -6
  970. package/shared/daq-protocol.ts +6 -0
  971. package/shared/lru.mjs +94 -0
  972. package/shared/workshop-protocol.ts +2 -2
  973. package/.output/public/_nuxt/2jaJHWIJ.js +0 -1
  974. package/.output/public/_nuxt/B8kt898d.js +0 -1
  975. package/.output/public/_nuxt/BFGpEo8S.js +0 -1
  976. package/.output/public/_nuxt/BG4zduPf.js +0 -14
  977. package/.output/public/_nuxt/BHcpzI2n.js +0 -19
  978. package/.output/public/_nuxt/BWyR3awA.js +0 -1
  979. package/.output/public/_nuxt/Bc89zKq2.js +0 -1
  980. package/.output/public/_nuxt/BetmGSO4.js +0 -1
  981. package/.output/public/_nuxt/BowTbasd.js +0 -1
  982. package/.output/public/_nuxt/BvtknqSC2.js +0 -1
  983. package/.output/public/_nuxt/BytVi9VX2.js +0 -4
  984. package/.output/public/_nuxt/CJviSvm-.js +0 -1
  985. package/.output/public/_nuxt/CTfqWGdy.js +0 -1
  986. package/.output/public/_nuxt/Cb3SnTM8.js +0 -1
  987. package/.output/public/_nuxt/Chc5pfAA.js +0 -1
  988. package/.output/public/_nuxt/CobSUzQv.js +0 -2
  989. package/.output/public/_nuxt/D95h62Jn.js +0 -1
  990. package/.output/public/_nuxt/DGAOugLt.js +0 -1
  991. package/.output/public/_nuxt/DHbTyoAV.js +0 -1
  992. package/.output/public/_nuxt/DfLUN8kY.js +0 -1
  993. package/.output/public/_nuxt/DnziMlcX.js +0 -1
  994. package/.output/public/_nuxt/DvgKXPgu2.js +0 -13
  995. package/.output/public/_nuxt/Q_SJDSgx.js +0 -1
  996. package/.output/public/_nuxt/_id_.DdbYeLqn.css +0 -1
  997. package/.output/public/_nuxt/_wsId_.BqWBlY7X.css +0 -1
  998. package/.output/public/_nuxt/agents.CB9Ck7VQ.css +0 -1
  999. package/.output/public/_nuxt/bFnZa2yd.js +0 -1
  1000. package/.output/public/_nuxt/builds/meta/f7a8e33d-5422-45ac-895d-27168f97e3ad.json +0 -1
  1001. package/.output/public/_nuxt/daq.DGV9QS8d.css +0 -1
  1002. package/.output/public/_nuxt/default.BbgdTDCk.css +0 -1
  1003. package/.output/public/_nuxt/entry.BN02X8iR.css +0 -1
  1004. package/.output/public/_nuxt/pages.CG8UJ2TK.css +0 -1
  1005. package/.output/public/_nuxt/plugins.DpCuwaJt.css +0 -1
  1006. package/.output/public/_nuxt/rkVgzg62.js +0 -1
  1007. package/.output/public/_nuxt/settings.W6qrYAui.css +0 -1
  1008. package/.output/public/_nuxt/teams.BBXVkyKq.css +0 -1
  1009. package/.output/server/chunks/build/_id_-3Axz2-gV.mjs.map +0 -1
  1010. package/.output/server/chunks/build/_id_-CahfkmEt.mjs.map +0 -1
  1011. package/.output/server/chunks/build/agents-DuMiSWKp.mjs.map +0 -1
  1012. package/.output/server/chunks/build/alert-qJnjyRcP.mjs.map +0 -1
  1013. package/.output/server/chunks/build/channel-templates-BStqJ-of.mjs.map +0 -1
  1014. package/.output/server/chunks/build/daq-ChYCABz1.mjs.map +0 -1
  1015. package/.output/server/chunks/build/dcw-CcQNGggh.mjs.map +0 -1
  1016. package/.output/server/chunks/build/logs-D-2UyGtE.mjs.map +0 -1
  1017. package/.output/server/chunks/build/pages-Dfosfchr.mjs.map +0 -1
  1018. package/.output/server/chunks/build/permissions-B-hhZuzm.mjs.map +0 -1
  1019. package/.output/server/chunks/build/plugins-DZR0T4Mh.mjs.map +0 -1
  1020. package/.output/server/chunks/build/responsiveObserve-CS0UB6wQ.mjs +0 -78
  1021. package/.output/server/chunks/build/responsiveObserve-CS0UB6wQ.mjs.map +0 -1
  1022. package/.output/server/chunks/build/settings-BajN9TQW.mjs.map +0 -1
  1023. package/.output/server/chunks/build/tag-NO9jEqKy.mjs.map +0 -1
  1024. package/.output/server/chunks/build/teams-t2SkRlJP.mjs.map +0 -1
  1025. package/.output/server/chunks/build/tokens-DiCojbN8.mjs.map +0 -1
  1026. package/.output/server/chunks/build/town-C7QM8DYK.mjs.map +0 -1
  1027. package/.output/server/chunks/build/useDaqStream-BeA2X8KR.mjs.map +0 -1
  1028. package/.output/server/chunks/build/useDcwStream-BJW_MitY.mjs.map +0 -1
  1029. package/.output/server/chunks/build/users-B9SAdEtH.mjs.map +0 -1
  1030. /package/.output/public/_nuxt/{ORt9oDIy.js → ORt9oDIy2.js} +0 -0
@@ -1,987 +1,936 @@
1
- /**
2
- * OpenCodeAgentImpl — opencode harness 的 AgentInterface 实现。
3
- *
4
- * 进程模型:每 Agent 一个 `opencode serve --port <free>` 子进程(lazy spawn,跨消息复用),
5
- * 经 HTTP API(prompt_async / abort / permissions / summarize)与全局 SSE 事件流(/event)
6
- * 交互 —— 官方机器面,协议参考 opencode OpenAPI(1.18.x)。
7
- *
8
- * - prompt 组装与工具面与 omp 全引擎同源(prompt-builder / host-tool-bridge);
9
- * 工具经 stdio MCP 桥(server/harness/aw-mcp-bridge.mjs)以 POST /mcp 运行时注册注入
10
- * - opencode 事件 → AgentEvent 五变体映射(适配器职责,本文件统一收口)
11
- * - 权限/提问(permission.asked / question.asked)→ hitl-registry(程序化应答)
12
- * - steer:回合运行中再投 prompt(引擎 steer/queue admission),内容不丢 → 'steer'
13
- * - 上下文治理:message.tokens 被动跟踪;越阈值 → POST /session/{id}/summarize
14
- *
15
- * 协议权威:https://opencode.ai/docs/server(v1.18.28 实测)。
16
- */
17
- import { createLogger } from '../logger'
18
- import { randomUUID } from 'node:crypto'
19
- import { createServer } from 'node:net'
20
- import type {
21
- AgentEvent,
22
- AgentInterface,
23
- AgentInfo,
24
- AgentRunContext,
25
- AgentRunRequest,
26
- SupervisionDecision,
27
- SupervisionSnapshot,
28
- } from './agent-interface'
29
- import type { AgentContextStats } from '../types/task'
30
- import { registerHarnessProcess, bindHarnessProcess, markHarnessProcessExit, killHarnessProcess, isProcessAlive } from './harness-process'
31
- import { createSessionState, dispatchHostTool } from './host-tool-bridge'
32
- import {
33
- contextPrefix as buildContextPrefix,
34
- createRosterCache,
35
- extractJsonArray,
36
- peerPrompt,
37
- supervisePrompt,
38
- systemManual,
39
- toolArgsPreview,
40
- workerPrompt,
41
- } from './prompt-builder'
42
- import { getHitlRegistry } from './hitl-registry'
43
- import { harnessSettings } from '../settings'
44
- import { spawnLineProcess } from './adapters/line-spawn'
45
- import { resolveBridgePath, resolvePlatformBaseUrl } from './harness-env'
46
-
47
- const log = createLogger('workshop.opencode')
48
-
49
- export interface OpenCodeAgentConfig {
50
- /** opencode 可执行文件(默认取 harness.opencode_command 设置) */
51
- command?: string
52
- cwd?: string
53
- /** 模型(provider/model,如 anthropic/claude-sonnet-4-5) */
54
- model?: string
55
- /** opencode agent 名(默认 build) */
56
- agent?: string
57
- /** provider 推理档位(variant;effort 为统一注入入口的别名) */
58
- variant?: string
59
- /** 思考 effort(统一注入面;等价 variant) */
60
- effort?: string
61
- /** 权限策略(session 级;缺省 edit/bash/webfetch 全 ask → HITL) */
62
- permission?: unknown
63
- /** 数据目录覆盖(XDG_DATA_HOME;实例隔离/绕开损坏的全局库) */
64
- dataDir?: string
65
- /** 配置目录覆盖(XDG_CONFIG_HOME;空目录 = 不加载用户全局 opencode 插件/配置) */
66
- configDir?: string
67
- /** 上下文窗口(usage 百分比计算;未知则 percent=null) */
68
- contextWindow?: number
69
- /** 压缩阈值(0-1,默认 0.7) */
70
- compactThreshold?: number
71
- /** 回合停滞超时(ms,默认 600000) */
72
- promptTimeoutMs?: number
73
- /** supervise 超时(ms,默认 150000) */
74
- superviseTimeoutMs?: number
75
- systemPromptPrefix?: string
76
- scenarioPrompt?: string
77
- agentId?: string
78
- name?: string
79
- role?: 'lead' | 'worker'
80
- channelId?: string
81
- /** 平台自证 token(MCP 桥回程鉴权;factory 注入) */
82
- token?: string
83
- /** 平台 HTTP 基址(桥回程;默认 AW_BASE_URL 或 127.0.0.1:PORT) */
84
- baseUrl?: string
85
- /** MCP 桥脚本路径(默认 <packageRoot>/server/harness/aw-mcp-bridge.mjs) */
86
- mcpBridgePath?: string
87
- }
88
-
89
- const sleep = (ms: number): Promise<void> => new Promise(r => setTimeout(r, ms))
90
-
91
- const DEFAULT_PERMISSION = [
92
- { permission: 'edit', pattern: '*', action: 'ask' },
93
- { permission: 'bash', pattern: '*', action: 'ask' },
94
- { permission: 'webfetch', pattern: '*', action: 'ask' },
95
- ]
96
-
97
- /** 取一个空闲 TCP 端口(绑定即弃,竞态窗口小;opencode serve 自身再绑定) */
98
- async function freePort(): Promise<number> {
99
- return new Promise((resolve, reject) => {
100
- const srv = createServer()
101
- srv.unref()
102
- srv.on('error', reject)
103
- srv.listen(0, '127.0.0.1', () => {
104
- const addr = srv.address()
105
- const port = typeof addr === 'object' && addr ? addr.port : 0
106
- srv.close(() => (port ? resolve(port) : reject(new Error('无可用端口'))))
107
- })
108
- })
109
- }
110
-
111
- interface PendingHitl {
112
- kind: 'opencode-permission'
113
- id: string
114
- type: 'permission' | 'question'
115
- sessionId: string
116
- timer: ReturnType<typeof setTimeout> | null
117
- }
118
-
119
- export class OpenCodeAgentImpl implements AgentInterface {
120
- private readonly config: OpenCodeAgentConfig
121
- private workspace: AgentRunContext['workspace'] | null = null
122
- private agentInfo: AgentInfo | null = null
123
- private readonly toolState = createSessionState()
124
- private readonly bridgeCtx = {
125
- identity: { agentId: '', channelId: '', role: 'worker' as 'lead' | 'worker', name: 'agent' },
126
- state: this.toolState,
127
- getWorkspace: () => this.workspace,
128
- }
129
-
130
- private roster = createRosterCache({ selfAgentId: '', listAgents: async () => [] })
131
-
132
- private selfAgentId = ''
133
- private agentName = 'agent'
134
- private agentRole: 'lead' | 'worker' = 'worker'
135
- private channelId = ''
136
-
137
- // 服务进程与 API 面
138
- private child: ReturnType<typeof spawnLineProcess> | null = null
139
- private baseUrl = ''
140
- private basicAuth = ''
141
- private sessionId: string | null = null
142
- private serverStarting: Promise<void> | null = null
143
- private exited = false
144
- private stderrTail = ''
145
- private sseAbort: AbortController | null = null
146
-
147
- // 回合状态
148
- private turnActive = false
149
- private aborted = false
150
- /** 助手正文(partId → 全文;message.part.updated 携带全量文本) */
151
- private partTexts = new Map<string, string>()
152
- private partOrder: string[] = []
153
- private lastUsage: { input: number, at: number } | null = null
154
- private compacting = false
155
- private lastCompactAt = 0
156
- /** 待应答 HITL(id → 定位信息) */
157
- private pendingHitl = new Map<string, PendingHitl>()
158
-
159
- constructor(config: Record<string, unknown> = {}) {
160
- this.config = config as OpenCodeAgentConfig
161
- this.selfAgentId = this.config.agentId ?? ''
162
- this.agentName = this.config.name ?? 'agent'
163
- this.agentRole = this.config.role ?? 'worker'
164
- this.channelId = this.config.channelId ?? ''
165
- this.refreshIdentity()
166
- }
167
-
168
- private refreshIdentity(): void {
169
- this.bridgeCtx.identity = { agentId: this.selfAgentId, channelId: this.channelId, role: this.agentRole, name: this.agentName }
170
- this.roster = createRosterCache({
171
- selfAgentId: this.selfAgentId,
172
- listAgents: async () => this.workspace?.listAgents() ?? [],
173
- })
174
- }
175
-
176
- async init(input: { agent: AgentInfo, channelId: string }): Promise<void> {
177
- this.agentInfo = input.agent
178
- this.channelId = input.channelId
179
- this.agentName = input.agent.name
180
- this.agentRole = input.agent.role
181
- this.selfAgentId = input.agent.id
182
- this.refreshIdentity()
183
- }
184
-
185
- // ===== 生命周期 / 进程面 =====
186
-
187
- getProcessInfo(): { pid: number, alive: boolean, command: string } | null {
188
- const pid = this.child?.pid
189
- if (!pid || !this.child) return null
190
- return { pid, alive: !this.exited, command: 'opencode serve' }
191
- }
192
-
193
- killProcess(): void {
194
- const pid = this.child?.pid
195
- if (pid) killHarnessProcess(pid)
196
- this.child = null
197
- }
198
-
199
- reconcileProcess(): void {
200
- const pid = this.child?.pid
201
- if (!pid || this.exited) return
202
- if (!isProcessAlive(pid)) this.handleServerExit(null)
203
- }
204
-
205
- async dispose(): Promise<void> {
206
- this.sseAbort?.abort()
207
- const pid = this.child?.pid
208
- if (pid) {
209
- killHarnessProcess(pid)
210
- markHarnessProcessExit(pid, null)
211
- }
212
- this.child = null
213
- this.exited = true
214
- this.serverStarting = null
215
- for (const [id, p] of this.pendingHitl) {
216
- if (p.timer) clearTimeout(p.timer)
217
- this.pendingHitl.delete(id)
218
- }
219
- }
220
-
221
- // ===== 引擎无关面 =====
222
-
223
- dispatchHostTool(toolName: string, args: Record<string, unknown>): Promise<{ text: string, isError?: boolean }> {
224
- return dispatchHostTool(this.bridgeCtx, { toolName, arguments: args })
225
- }
226
-
227
- getContextStats(): AgentContextStats | null {
228
- if (!this.lastUsage) return null
229
- const window = this.config.contextWindow ?? null
230
- return {
231
- usedTokens: this.lastUsage.input,
232
- contextWindow: window,
233
- percent: window && window > 0 ? Math.min(1, this.lastUsage.input / window) : null,
234
- compacting: this.compacting,
235
- }
236
- }
237
-
238
- /**
239
- * 实时注入:回合运行中再投一条 prompt(opencode 引擎 admit 为 steer/queue,
240
- * 内容必然到达模型)→ 'steer';空闲 → 'deferred'(消费循环起回合处理)。
241
- */
242
- async steer(text: string): Promise<'steer' | 'deferred'> {
243
- if (!this.sessionId || !this.turnActive) return 'deferred'
244
- try {
245
- await this.promptAsync(text)
246
- return 'steer'
247
- }
248
- catch (err) {
249
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] steer 投递失败(消息保持 pending):`, err instanceof Error ? err.message : err)
250
- return 'deferred'
251
- }
252
- }
253
-
254
- /** HITL 应答(codex/opencode/dsh 统一入口;本 impl 处理 opencode-permission) */
255
- async respondHitl(kind: string, id: string, outcome: {
256
- confirmed?: boolean
257
- cancelled?: boolean
258
- value?: string
259
- response?: string
260
- comment?: string
261
- }): Promise<void> {
262
- if (kind !== 'opencode-permission') return
263
- const pending = this.pendingHitl.get(id)
264
- if (!pending) throw new Error(`待办不存在或已处理: ${id}`)
265
- // 应答映射:显式 response > confirmed/cancelled 布尔(缺省拒绝,fail-closed)
266
- const cancelled = outcome.cancelled === true || (outcome.confirmed !== true && !outcome.response)
267
- if (pending.type === 'permission') {
268
- const response = cancelled ? 'reject' : (outcome.response === 'always' || outcome.response === 'once' ? outcome.response : 'once')
269
- await this.api('POST', `/session/${pending.sessionId}/permissions/${encodeURIComponent(id)}`, { response })
270
- }
271
- else {
272
- // question:取消走 reject 端点;回答携带 value
273
- if (cancelled) {
274
- await this.api('POST', `/question/${encodeURIComponent(id)}/reject`, {})
275
- }
276
- else {
277
- await this.api('POST', `/question/${encodeURIComponent(id)}/reply`, { answer: outcome.value ?? outcome.comment ?? '' })
278
- }
279
- }
280
- if (pending.timer) clearTimeout(p.timer)
281
- this.pendingHitl.delete(id)
282
- getHitlRegistry().resolve(kind, id, cancelled ? 'cancelled' : 'answered')
283
- }
284
-
285
- /** 上下文治理(post-settle 钩子):越阈值 → summarize;异常不抛出 */
286
- async onTurnSettled(): Promise<void> {
287
- if (this.compacting || !this.sessionId) return
288
- const stats = this.getContextStats()
289
- const threshold = this.config.compactThreshold ?? 0.7
290
- if (!stats?.percent || stats.percent < threshold) return
291
- if (Date.now() - this.lastCompactAt < 5 * 60_000) return
292
- this.compacting = true
293
- this.lastCompactAt = Date.now()
294
- try {
295
- await this.api('POST', `/session/${this.sessionId}/summarize`, {})
296
- log.info(`[OpenCodeAgent:${this.selfAgentId}] 上下文压缩已触发(percent=${(stats.percent * 100).toFixed(0)}%)`)
297
- }
298
- catch (err) {
299
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] summarize 失败(放行):`, err instanceof Error ? err.message : err)
300
- }
301
- finally {
302
- this.compacting = false
303
- }
304
- }
305
-
306
- // ===== run / supervise =====
307
-
308
- async* run(request: AgentRunRequest, ctx: AgentRunContext): AsyncIterable<AgentEvent> {
309
- const kind = request.message.metadata?.['x-aw-task-kind']
310
- if (kind === 'assign' && ctx.role === 'worker') {
311
- yield* this.workerRun(request, ctx)
312
- return
313
- }
314
- if (!kind && (request.fromAgentId || request.message.metadata?.['x-aw-from-label'])) {
315
- yield* this.peerMessageRun(request, ctx)
316
- return
317
- }
318
- }
319
-
320
- private supervising = false
321
-
322
- async supervise(snapshot: SupervisionSnapshot, ctx: AgentRunContext, opts?: { signal?: AbortSignal }): Promise<SupervisionDecision[]> {
323
- // 引擎/会话不可用 → 本轮监督降级为空(调度器回退规则引擎);绝不让引擎故障
324
- // 以 unhandledRejection 形态逃逸(dev-stability-guard 会据此杀掉整个服务端)
325
- try {
326
- await this.ensureServer(ctx)
327
- }
328
- catch (err) {
329
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] supervise 引擎不可用,跳过本轮:`, err instanceof Error ? err.message : err)
330
- return []
331
- }
332
- if (!this.sessionId) return []
333
- if (this.supervising) return []
334
- const prompt = supervisePrompt({
335
- snapshot,
336
- agentName: this.agentName,
337
- channelId: this.channelId,
338
- ctxPrefix: await this.contextPrefix(),
339
- manual: systemManual(),
340
- memory: ctx.memory,
341
- })
342
- const timeoutMs = this.config.superviseTimeoutMs ?? 150_000
343
- return await this.runTurn(prompt, undefined, {
344
- timeoutMs,
345
- signal: opts?.signal,
346
- onDone: async () => {
347
- this.supervising = false
348
- },
349
- beforeStart: () => {
350
- this.supervising = true
351
- },
352
- }).then((events) => {
353
- // 从事件流提取最终文本 → JSON 决策兜底(工具直执行路径返回空)
354
- let text = ''
355
- for (const e of events) {
356
- if (e.kind === 'artifact') {
357
- text += e.artifact.parts.map(p => 'text' in p ? p.text : '').join('')
358
- }
359
- }
360
- const parsed = extractJsonArray(text)
361
- return parsed && parsed.length > 0 ? parsed as SupervisionDecision[] : []
362
- }).catch(() => {
363
- this.supervising = false
364
- return []
365
- })
366
- }
367
-
368
- private async* workerRun(request: AgentRunRequest, ctx: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown> {
369
- const taskId = request.taskId ?? (request.message.metadata?.['x-aw-task-id'] as string | undefined)
370
- if (!taskId) return
371
- this.toolState.currentTaskId = taskId
372
- try {
373
- await this.ensureServer(ctx)
374
- const taskText = request.message.parts.map((p) => {
375
- if ('text' in p) return p.text
376
- if ('data' in p) return JSON.stringify(p.data)
377
- if ('url' in p) return p.url
378
- if ('raw' in p) return p.raw
379
- return ''
380
- }).join('\n')
381
- const prompt = workerPrompt({
382
- agentName: this.agentName,
383
- channelId: this.channelId,
384
- taskId,
385
- taskText,
386
- memory: request.memory,
387
- ctxPrefix: await this.contextPrefix(),
388
- manual: systemManual(),
389
- })
390
- yield* this.runTurn(prompt, taskId, {
391
- timeoutMs: this.config.promptTimeoutMs ?? 600_000,
392
- signal: ctx.signal,
393
- })
394
- }
395
- finally {
396
- this.toolState.currentTaskId = null
397
- }
398
- }
399
-
400
- private async* peerMessageRun(request: AgentRunRequest, ctx: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown> {
401
- await this.ensureServer(ctx)
402
- const msg = request.message
403
- const fromId = request.fromAgentId
404
- ?? (typeof msg.metadata?.['x-aw-from-label'] === 'string' ? msg.metadata['x-aw-from-label'] : undefined)
405
- ?? 'unknown'
406
- const requireReply = msg.metadata?.['x-aw-require-reply'] === 'true'
407
- const crossChannel = msg.metadata?.['x-aw-cross-channel'] === 'true'
408
- this.toolState.replyContext = requireReply && request.fromAgentId && !crossChannel
409
- ? { fromId: request.fromAgentId, messageId: msg.messageId }
410
- : null
411
- const msgText = msg.parts.map((p) => {
412
- if ('text' in p) return p.text
413
- if ('data' in p) return JSON.stringify(p.data)
414
- if ('url' in p) return p.url
415
- if ('raw' in p) return p.raw
416
- return ''
417
- }).join('\n')
418
- const prompt = peerPrompt({
419
- agentName: this.agentName,
420
- role: this.agentRole,
421
- channelId: this.channelId,
422
- ctxPrefix: await this.contextPrefix(),
423
- manual: systemManual(),
424
- memory: request.memory,
425
- fromId,
426
- messageId: msg.messageId,
427
- requireReply,
428
- isReply: typeof msg.metadata?.['x-aw-in-reply-to'] === 'string',
429
- crossChannel,
430
- fromChannel: typeof msg.metadata?.['x-aw-from-channel'] === 'string' ? String(msg.metadata['x-aw-from-channel']) : '',
431
- msgText,
432
- })
433
- yield* this.runTurn(prompt, undefined, { timeoutMs: this.config.promptTimeoutMs ?? 600_000, signal: ctx.signal })
434
- }
435
-
436
- private async contextPrefix(): Promise<string> {
437
- return buildContextPrefix({
438
- scenarioPrompt: this.config.scenarioPrompt,
439
- systemPromptPrefix: this.config.systemPromptPrefix,
440
- agentId: this.selfAgentId,
441
- roster: await this.roster.roster(),
442
- })
443
- }
444
-
445
- // ===== 回合执行(prompt → SSE 事件 → AgentEvent)=====
446
-
447
- private runTurn(
448
- prompt: string,
449
- taskId: string | undefined,
450
- opts: { timeoutMs: number, signal?: AbortSignal, beforeStart?: () => void, onDone?: () => void },
451
- ): AsyncGenerator<AgentEvent, void, unknown> {
452
- return this._runTurn(prompt, taskId, opts)
453
- }
454
-
455
- private async* _runTurn(
456
- prompt: string,
457
- taskId: string | undefined,
458
- opts: { timeoutMs: number, signal?: AbortSignal, beforeStart?: () => void, onDone?: () => void },
459
- ): AsyncGenerator<AgentEvent, void, unknown> {
460
- if (!this.sessionId) {
461
- yield { kind: 'error', error: { code: 'OPENCODE_NOT_READY', message: 'opencode 会话未就绪' } }
462
- return
463
- }
464
- opts.beforeStart?.()
465
- const queue: AgentEvent[] = []
466
- let isDone = false
467
- let resolveWait: (() => void) | null = null
468
- let lastActivity = Date.now()
469
- this.turnActive = true
470
- this.aborted = false
471
- this.partTexts = new Map()
472
- this.partOrder = []
473
-
474
- const enqueue = (e: AgentEvent): void => {
475
- // done 事件前先收口 artifact(助手正文聚合),保证事件序 artifact → done
476
- if (e.kind === 'done' && !isDone) {
477
- const text = this.partOrder.map(id => this.partTexts.get(id) ?? '').join('').trim()
478
- if (text) {
479
- queue.push({
480
- kind: 'artifact',
481
- artifact: { artifactId: randomUUID(), name: 'output', parts: [{ text }] },
482
- lastChunk: true,
483
- totalChunks: 1,
484
- })
485
- }
486
- this.turnActive = false
487
- opts.onDone?.()
488
- }
489
- if (e.kind === 'done' || e.kind === 'error') {
490
- isDone = true
491
- this.turnActive = false
492
- }
493
- queue.push(e)
494
- lastActivity = Date.now()
495
- resolveWait?.()
496
- resolveWait = null
497
- }
498
-
499
- // 事件订阅(SSE → 队列)
500
- const unsub = this.onEngineEvent((ev) => {
501
- for (const mapped of this.mapEngineEvent(ev, taskId)) enqueue(mapped)
502
- })
503
-
504
- // 停滞看门狗
505
- let stallTimer: ReturnType<typeof setTimeout> | null = null
506
-
507
- const finishTurn = (): void => {
508
- if (isDone) return
509
- const text = this.partOrder.map(id => this.partTexts.get(id) ?? '').join('').trim()
510
- if (text) {
511
- enqueue({
512
- kind: 'artifact',
513
- artifact: { artifactId: randomUUID(), name: 'output', parts: [{ text }] },
514
- lastChunk: true,
515
- totalChunks: 1,
516
- })
517
- }
518
- enqueue({ kind: 'done', final: taskId ? { taskId } : undefined })
519
- this.turnActive = false
520
- opts.onDone?.()
521
- }
522
-
523
- const onAbort = (): void => {
524
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] run 被 abort → POST abort,taskId=${taskId ?? '-'}`)
525
- this.aborted = true
526
- void this.api('POST', `/session/${this.sessionId}/abort`, {}).catch(() => {})
527
- // 引擎将回 session.idle → finishTurn;兜底 5s 后强制收口
528
- setTimeout(() => finishTurn(), 5000)
529
- }
530
- if (opts.signal?.aborted) onAbort()
531
- else opts.signal?.addEventListener('abort', onAbort, { once: true })
532
-
533
- // 投递 prompt
534
- try {
535
- await this.promptAsync(prompt)
536
- enqueue({ kind: 'status', status: { state: 'WORKING', timestamp: new Date().toISOString() } })
537
- }
538
- catch (err) {
539
- unsub()
540
- opts.signal?.removeEventListener('abort', onAbort)
541
- this.turnActive = false
542
- yield {
543
- kind: 'error',
544
- error: {
545
- code: 'OPENCODE_PROMPT_FAILED',
546
- message: `opencode prompt 失败: ${err instanceof Error ? err.message : String(err)}`,
547
- },
548
- }
549
- return
550
- }
551
-
552
- try {
553
- while (!isDone || queue.length > 0) {
554
- if (queue.length === 0 && !isDone) {
555
- const remaining = opts.timeoutMs - (Date.now() - lastActivity)
556
- if (remaining <= 0) {
557
- this.aborted = true
558
- void this.api('POST', `/session/${this.sessionId}/abort`, {}).catch(() => {})
559
- enqueue({
560
- kind: 'error',
561
- error: {
562
- code: 'OPENCODE_TURN_STALLED',
563
- message: `回合停滞 ${Math.round(opts.timeoutMs / 1000)}s 无事件,已中止(消息按已处理落账)`,
564
- },
565
- })
566
- this.turnActive = false
567
- continue
568
- }
569
- await new Promise<void>((r) => {
570
- resolveWait = r
571
- stallTimer = setTimeout(() => {
572
- resolveWait = null
573
- r()
574
- }, remaining + 100)
575
- })
576
- if (stallTimer) {
577
- clearTimeout(stallTimer)
578
- stallTimer = null
579
- }
580
- }
581
- while (queue.length > 0) {
582
- yield queue.shift()!
583
- }
584
- }
585
- }
586
- finally {
587
- if (stallTimer) clearTimeout(stallTimer)
588
- unsub()
589
- opts.signal?.removeEventListener('abort', onAbort)
590
- this.turnActive = false
591
- }
592
- }
593
-
594
- /** 引擎事件 → AgentEvent(适配器核心) */
595
- private mapEngineEvent(ev: Record<string, unknown>, taskId: string | undefined): AgentEvent[] {
596
- const type = String(ev.type ?? '')
597
- const props = (ev.properties ?? {}) as Record<string, unknown>
598
- const sid = props.sessionID ?? props.sessionId
599
- if (sid && sid !== this.sessionId) return [] // 多会话实例隔离(本 impl 一会话,防御)
600
-
601
- const now = new Date().toISOString()
602
- const statusEvent = (text: string): AgentEvent => ({
603
- kind: 'status',
604
- status: {
605
- state: 'WORKING',
606
- message: { messageId: randomUUID(), contextId: this.channelId, role: 'ROLE_AGENT', parts: [{ text }] },
607
- timestamp: now,
608
- },
609
- })
610
-
611
- switch (type) {
612
- case 'message.part.delta': {
613
- if (props.field === 'text' && typeof props.delta === 'string' && props.delta) {
614
- return [{ kind: 'delta', delta: { text: props.delta } }]
615
- }
616
- return []
617
- }
618
- case 'message.part.updated': {
619
- const part = props.part as Record<string, unknown> | undefined
620
- if (!part) return []
621
- const partId = String(part.id ?? '')
622
- const partType = String(part.type ?? '')
623
- if (partType === 'text' && typeof part.text === 'string' && partId) {
624
- if (!this.partOrder.includes(partId)) this.partOrder.push(partId)
625
- this.partTexts.set(partId, part.text)
626
- }
627
- else if (partType === 'tool') {
628
- const state = (part.state ?? {}) as Record<string, unknown>
629
- const tool = String(part.tool ?? 'tool')
630
- const statusStr = String(state.status ?? '')
631
- if (statusStr === 'pending' || statusStr === 'running') {
632
- const input = state.input ?? part.input
633
- return [statusEvent(`🔧 ${tool}${toolArgsPreview(input)}`)]
634
- }
635
- if (statusStr === 'error') {
636
- return [statusEvent(`🔧 ${tool} 失败: ${String(state.error ?? '未知错误').slice(0, 200)}`)]
637
- }
638
- }
639
- else if (partType === 'compaction') {
640
- this.lastCompactAt = Date.now()
641
- }
642
- return []
643
- }
644
- case 'message.updated': {
645
- const info = props.info as Record<string, unknown> | undefined
646
- if (info?.role === 'assistant') {
647
- const tokens = info.tokens as Record<string, unknown> | undefined
648
- const input = Number(tokens?.input)
649
- if (Number.isFinite(input) && input > 0) this.lastUsage = { input, at: Date.now() }
650
- const err = info.error as Record<string, unknown> | undefined
651
- if (err && this.turnActive) {
652
- const code = String(err.name ?? 'UnknownError')
653
- return [{
654
- kind: 'error',
655
- error: { code: `OPENCODE_LLM_${code}`, message: String(err.message ?? 'opencode 回合错误') },
656
- }]
657
- }
658
- }
659
- return []
660
- }
661
- case 'session.error': {
662
- const err = props.error as Record<string, unknown> | undefined
663
- if (!this.turnActive) return []
664
- const data = (err?.data ?? {}) as Record<string, unknown>
665
- const detail = String(data.message ?? err?.message ?? 'opencode 会话错误')
666
- return [{
667
- kind: 'error',
668
- error: {
669
- code: `OPENCODE_ERROR_${String(err?.name ?? 'UNKNOWN')}`,
670
- message: `${detail}${data.statusCode != null ? ` (HTTP ${data.statusCode})` : ''}`,
671
- },
672
- }]
673
- }
674
- case 'session.status': {
675
- const status = props.status as Record<string, unknown> | undefined
676
- if (String(status?.type ?? '') === 'idle' && this.turnActive) {
677
- return [{ kind: 'done', final: taskId ? { taskId } : undefined }]
678
- }
679
- return []
680
- }
681
- case 'session.idle': {
682
- if (this.turnActive) {
683
- return [{ kind: 'done', final: taskId ? { taskId } : undefined }]
684
- }
685
- return []
686
- }
687
- // ===== HITL =====
688
- case 'permission.asked':
689
- case 'permission.v2.asked': {
690
- this.registerPermissionHitl(type === 'permission.v2.asked', props)
691
- return []
692
- }
693
- case 'question.asked': {
694
- this.registerQuestionHitl(props)
695
- return []
696
- }
697
- case 'permission.replied':
698
- case 'permission.v2.replied':
699
- case 'question.replied':
700
- case 'question.rejected': {
701
- const id = String(props.id ?? '')
702
- if (id && this.pendingHitl.has(id)) {
703
- const p = this.pendingHitl.get(id)!
704
- if (p.timer) clearTimeout(p.timer)
705
- this.pendingHitl.delete(id)
706
- }
707
- return []
708
- }
709
- default:
710
- return []
711
- }
712
- }
713
-
714
- private registerPermissionHitl(v2: boolean, props: Record<string, unknown>): void {
715
- const id = String(props.id ?? '')
716
- if (!id) return
717
- if (this.pendingHitl.has(id)) return
718
- const sessionId = String(props.sessionID ?? this.sessionId ?? '')
719
- const permission = String(props.permission ?? props.action ?? 'action')
720
- const patterns = Array.isArray(props.patterns) ? props.patterns.map(String).join(', ') : ''
721
- const v2res = Array.isArray(props.resources) ? props.resources.map(String).join(', ') : ''
722
- const detail = patterns || v2res
723
- const title = `opencode 权限请求:${permission}${detail ? `(${detail})` : ''}`
724
- this.registerHitl(id, 'permission', sessionId, title, `引擎将执行 ${permission}${detail ? ` → ${detail}` : ''};批准放行一次,拒绝则引擎收到 reject。`)
725
- }
726
-
727
- private registerQuestionHitl(props: Record<string, unknown>): void {
728
- const id = String(props.id ?? '')
729
- if (!id || this.pendingHitl.has(id)) return
730
- const sessionId = String(props.sessionID ?? this.sessionId ?? '')
731
- const questions = Array.isArray(props.questions) ? props.questions : []
732
- const first = (questions[0] ?? {}) as Record<string, unknown>
733
- const title = String(first.question ?? first.header ?? 'opencode 提问')
734
- this.registerHitl(id, 'question', sessionId, title, String(first.question ?? ''), 'input')
735
- }
736
-
737
- private registerHitl(id: string, type: 'permission' | 'question', sessionId: string, title: string, detail: string, method: 'confirm' | 'input' = 'confirm'): void {
738
- const registry = getHitlRegistry()
739
- registry.register({
740
- kind: 'opencode-permission',
741
- id,
742
- agentId: this.selfAgentId,
743
- agentName: this.agentName,
744
- channelId: this.channelId,
745
- pid: this.child?.pid,
746
- method,
747
- title,
748
- detail,
749
- createdAt: new Date().toISOString(),
750
- expiresAt: null,
751
- })
752
- // 无人应答超时(fail-closed:到时自动拒绝),0 = 无限等待
753
- const timeoutMs = harnessSettings().hitl_timeout_ms
754
- const timer = timeoutMs > 0
755
- ? setTimeout(() => {
756
- void this.respondHitl('opencode-permission', id, { cancelled: true }).catch(() => {})
757
- registry.resolve('opencode-permission', id, 'expired')
758
- }, timeoutMs)
759
- : null
760
- this.pendingHitl.set(id, { kind: 'opencode-permission', id, type, sessionId, timer })
761
- }
762
-
763
- // ===== opencode 服务进程与 HTTP 客户端 =====
764
-
765
- private async ensureServer(ctx: AgentRunContext): Promise<void> {
766
- if (!this.workspace) this.workspace = ctx.workspace
767
- if (!this.agentInfo) {
768
- this.channelId = ctx.channelId
769
- this.agentRole = ctx.role
770
- this.refreshIdentity()
771
- }
772
- if (this.sessionId && this.child && !this.exited) return
773
- this.serverStarting ??= this.startServer().finally(() => {
774
- this.serverStarting = null
775
- })
776
- await this.serverStarting
777
- }
778
-
779
- private async startServer(): Promise<void> {
780
- const command = this.config.command ?? harnessSettings().opencode_command
781
- const port = await freePort()
782
- const password = randomUUID()
783
- const cwd = this.config.cwd ?? process.cwd()
784
- this.exited = false
785
- const child = spawnLineProcess(command, ['serve', '--port', String(port), '--hostname', '127.0.0.1'], {
786
- cwd,
787
- env: {
788
- OPENCODE_SERVER_PASSWORD: password,
789
- ...(this.config.dataDir ? { XDG_DATA_HOME: this.config.dataDir } : {}),
790
- ...(this.config.configDir ? { XDG_CONFIG_HOME: this.config.configDir } : {}),
791
- },
792
- })
793
- this.child = child
794
- this.baseUrl = `http://127.0.0.1:${port}`
795
- this.basicAuth = `Basic ${Buffer.from(`opencode:${password}`).toString('base64')}`
796
- child.stderr?.setEncoding('utf-8')
797
- child.stderr?.on('data', (d: string) => {
798
- this.stderrTail = (this.stderrTail + d).slice(-8000)
799
- })
800
- const pid = child.pid
801
- if (pid) {
802
- registerHarnessProcess(pid, { harness: 'opencode', command, args: ['serve', '--port', String(port)] })
803
- bindHarnessProcess(pid, { agentId: this.selfAgentId, channelId: this.channelId, name: this.agentName, role: this.agentRole })
804
- }
805
- child.on('exit', code => this.handleServerExit(code))
806
-
807
- // 健康探测(serve 冷启动含 provider registry,预算 60s;/global/health 需 Basic 认证)
808
- const deadline = Date.now() + 60_000
809
- let healthy = false
810
- while (Date.now() < deadline) {
811
- if (this.exited) {
812
- throw new Error(`opencode serve 启动失败(进程退出)${this.stderrTail ? `\nstderr: ${this.stderrTail.slice(-400)}` : ''}`)
813
- }
814
- try {
815
- const res = await fetch(`${this.baseUrl}/global/health`, {
816
- headers: { authorization: this.basicAuth },
817
- signal: AbortSignal.timeout(2000),
818
- })
819
- if (res.ok) {
820
- healthy = true
821
- break
822
- }
823
- }
824
- catch { /* 未就绪,重试 */ }
825
- await new Promise(r => setTimeout(r, 500))
826
- }
827
- if (!healthy) throw new Error(`opencode serve 健康探测超时(60s)${this.stderrTail ? `\nstderr: ${this.stderrTail.slice(-400)}` : ''}`)
828
-
829
- // 注册 MCP 桥(全量 host tools 注入;幂等;command 为 [可执行, 参数...] 数组形态)
830
- try {
831
- await this.api('POST', '/mcp', {
832
- name: 'aw-host-tools',
833
- config: {
834
- type: 'local',
835
- command: [process.execPath, resolveBridgePath(this.config.mcpBridgePath)],
836
- environment: {
837
- AW_BASE_URL: resolvePlatformBaseUrl(this.config.baseUrl),
838
- AW_AGENT_ID: this.selfAgentId,
839
- AW_AGENT_TOKEN: this.config.token ?? '',
840
- AW_MCP_TOOL_TIMEOUT_MS: String(200_000),
841
- },
842
- },
843
- })
844
- }
845
- catch (err) {
846
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] MCP 桥注册失败(host tools 不可用):`, err instanceof Error ? err.message : err)
847
- }
848
-
849
- // 建会话(权限策略缺省全 ask;部分版本不认 permission/model 字段时降级重试;
850
- // model 按回合在 prompt_async 里传 —— session 创建面不接受它)
851
- const body: Record<string, unknown> = {
852
- title: `${this.agentName}@${this.channelId || 'channel'}`,
853
- }
854
- const createWith = async (extra: Record<string, unknown> | undefined): Promise<Record<string, unknown>> =>
855
- this.api('POST', '/session', { ...body, ...(extra ?? {}) })
856
- const created = await (this.config.permission ?? DEFAULT_PERMISSION)
857
- ? createWith({ permission: this.config.permission ?? DEFAULT_PERMISSION }).catch(() => createWith(undefined))
858
- : createWith(undefined)
859
- this.sessionId = String(created?.id ?? '')
860
- if (!this.sessionId) {
861
- // 瞬态失败(实例刚起/内部分配竞态/权限规则不兼容)→ 无附加字段重试,最多 3 次
862
- for (let i = 0; i < 3 && !this.sessionId; i++) {
863
- await sleep(2500)
864
- const retry = await createWith(undefined).catch(() => null)
865
- this.sessionId = String(retry?.id ?? '')
866
- }
867
- }
868
- if (!this.sessionId) {
869
- // 会话建不出来(版本/参数不兼容):回收 serve 子进程与句柄后抛错,防泄漏
870
- const detail = this.stderrTail ? ` stderr: ${this.stderrTail.slice(-300)}` : ''
871
- killHarnessProcess(this.child?.pid ?? -1)
872
- this.child = null
873
- this.exited = true
874
- throw new Error(`opencode 会话创建失败(无 session id)${detail}`)
875
- }
876
-
877
- // 订阅全局事件流
878
- this.openEventStream()
879
- }
880
-
881
- private modelRef(): Record<string, string> | undefined {
882
- const model = this.config.model
883
- if (!model) return undefined
884
- if (model.includes('/')) {
885
- const [providerID, modelID] = model.split('/', 2)
886
- return { providerID: providerID ?? '', modelID: modelID ?? '' }
887
- }
888
- return { providerID: 'opencode', modelID: model }
889
- }
890
-
891
- private handleServerExit(code: number | null): void {
892
- if (this.exited) return
893
- this.exited = true
894
- this.sseAbort?.abort()
895
- const pid = this.child?.pid
896
- if (pid) markHarnessProcessExit(pid, code)
897
- // 在途回合经引擎错误归位:下一回合 ensureServer 重生
898
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] opencode serve 退出(code=${code});下回合自动重生`)
899
- }
900
-
901
- /** 全局 SSE 订阅(断线重连;帧解析 data: 行) */
902
- private openEventStream(): void {
903
- this.sseAbort?.abort()
904
- const ctrl = new AbortController()
905
- this.sseAbort = ctrl
906
- const connect = async (): Promise<void> => {
907
- while (!ctrl.signal.aborted && !this.exited) {
908
- try {
909
- const res = await fetch(`${this.baseUrl}/event`, {
910
- headers: { authorization: this.basicAuth, accept: 'text/event-stream' },
911
- signal: ctrl.signal,
912
- })
913
- if (!res.ok || !res.body) throw new Error(`SSE HTTP ${res.status}`)
914
- const reader = res.body.getReader()
915
- const decoder = new TextDecoder()
916
- let buf = ''
917
- for (;;) {
918
- const { done, value } = await reader.read()
919
- if (done) break
920
- buf += decoder.decode(value, { stream: true })
921
- const chunks = buf.split('\n\n')
922
- buf = chunks.pop() ?? ''
923
- for (const chunk of chunks) {
924
- for (const line of chunk.split('\n')) {
925
- if (!line.startsWith('data:')) continue
926
- const payload = line.slice(5).trim()
927
- if (!payload) continue
928
- try {
929
- this.dispatchEngineEvent(JSON.parse(payload))
930
- }
931
- catch { /* 非 JSON data 行忽略 */ }
932
- }
933
- }
934
- }
935
- }
936
- catch (err) {
937
- if (ctrl.signal.aborted || this.exited) return
938
- log.warn(`[OpenCodeAgent:${this.selfAgentId}] SSE 断开(1s 后重连):`, err instanceof Error ? err.message : err)
939
- await new Promise(r => setTimeout(r, 1000))
940
- }
941
- }
942
- }
943
- void connect()
944
- }
945
-
946
- /** SSE 事件缓冲(回合未激活时事件即到即弃,激活后由 mapEngineEvent 消费) */
947
- private engineListeners = new Set<(ev: Record<string, unknown>) => void>()
948
-
949
- private dispatchEngineEvent(ev: Record<string, unknown>): void {
950
- for (const fn of this.engineListeners) fn(ev)
951
- }
952
-
953
- private onEngineEvent(fn: (ev: Record<string, unknown>) => void): () => void {
954
- this.engineListeners.add(fn)
955
- return () => this.engineListeners.delete(fn)
956
- }
957
-
958
- private async api(method: string, path: string, body?: unknown): Promise<Record<string, unknown>> {
959
- const res = await fetch(`${this.baseUrl}${path}`, {
960
- method,
961
- headers: { authorization: this.basicAuth, ...(body !== undefined ? { 'content-type': 'application/json' } : {}) },
962
- ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
963
- signal: AbortSignal.timeout(60_000),
964
- })
965
- if (res.status === 204) return {}
966
- const text = await res.text()
967
- let json: Record<string, unknown> = {}
968
- try {
969
- json = text ? JSON.parse(text) as Record<string, unknown> : {}
970
- }
971
- catch { /* 非 JSON 响应体 */ }
972
- if (!res.ok) {
973
- throw new Error(`opencode API ${method} ${path} → HTTP ${res.status}: ${String((json as { message?: string }).message ?? text.slice(0, 200))}`)
974
- }
975
- return json
976
- }
977
-
978
- private async promptAsync(text: string): Promise<void> {
979
- if (!this.sessionId) throw new Error('会话未就绪')
980
- await this.api('POST', `/session/${this.sessionId}/prompt_async`, {
981
- parts: [{ type: 'text', text }],
982
- ...(this.config.agent ? { agent: this.config.agent } : {}),
983
- ...(this.config.model ? { model: this.modelRef() } : {}),
984
- ...(this.config.variant ? { variant: this.config.variant } : (this.config.effort ? { variant: this.config.effort } : {})),
985
- })
986
- }
987
- }
1
+ /**
2
+ * OpenCodeAgentImpl — opencode harness 的 AgentInterface 实现。
3
+ *
4
+ * 进程模型:每 Agent 一个 `opencode serve --port <free>` 子进程(lazy spawn,跨消息复用),
5
+ * 经 HTTP API(prompt_async / abort / permissions / summarize)与全局 SSE 事件流(/event)
6
+ * 交互 —— 官方机器面,协议参考 opencode OpenAPI(1.18.x)。
7
+ *
8
+ * - prompt 组装与工具面与 omp 全引擎同源(prompt-builder / host-tool-bridge);
9
+ * 工具经 stdio MCP 桥(server/harness/aw-mcp-bridge.mjs)以 POST /mcp 运行时注册注入
10
+ * - opencode 事件 → AgentEvent 五变体映射(适配器职责,本文件统一收口)
11
+ * - 权限/提问(permission.asked / question.asked)→ hitl-registry(程序化应答)
12
+ * - steer:回合运行中再投 prompt(引擎 steer/queue admission),内容不丢 → 'steer'
13
+ * - 上下文治理:message.tokens 被动跟踪;越阈值 → POST /session/{id}/summarize
14
+ *
15
+ * 协议权威:https://opencode.ai/docs/server(v1.18.28 实测)。
16
+ */
17
+ import { createLogger } from '../logger'
18
+ import { randomUUID } from 'node:crypto'
19
+ import { createServer } from 'node:net'
20
+ import type {
21
+ AgentEvent,
22
+ AgentInterface,
23
+ AgentInfo,
24
+ AgentRunContext,
25
+ AgentRunRequest,
26
+ SupervisionDecision,
27
+ SupervisionSnapshot,
28
+ } from './agent-interface'
29
+ import type { AgentContextStats } from '../types/task'
30
+ import { registerHarnessProcess, bindHarnessProcess, markHarnessProcessExit, killHarnessProcess, isProcessAlive } from './harness-process'
31
+ import { extractJsonArray, peerPrompt, supervisePrompt, systemManual, toolArgsPreview, workerPrompt } from './prompt-builder'
32
+ import { getHitlRegistry } from './hitl-registry'
33
+ import { harnessSettings } from '../settings'
34
+ import { spawnLineProcess } from './adapters/line-spawn'
35
+ import { BaseAgentImpl } from './base-agent'
36
+ import { resolveBridgePath, resolvePlatformBaseUrl } from './harness-env'
37
+
38
+ const log = createLogger('workshop.opencode')
39
+
40
+ export interface OpenCodeAgentConfig {
41
+ /** opencode 可执行文件(默认取 harness.opencode_command 设置) */
42
+ command?: string
43
+ cwd?: string
44
+ /** 模型(provider/model,如 anthropic/claude-sonnet-4-5) */
45
+ model?: string
46
+ /** opencode agent 名(默认 build) */
47
+ agent?: string
48
+ /** provider 推理档位(variant;effort 为统一注入入口的别名) */
49
+ variant?: string
50
+ /** 思考 effort(统一注入面;等价 variant) */
51
+ effort?: string
52
+ /** 权限策略(session 级;缺省 edit/bash/webfetch 全 ask → HITL) */
53
+ permission?: unknown
54
+ /** 数据目录覆盖(XDG_DATA_HOME;实例隔离/绕开损坏的全局库) */
55
+ dataDir?: string
56
+ /** 配置目录覆盖(XDG_CONFIG_HOME;空目录 = 不加载用户全局 opencode 插件/配置) */
57
+ configDir?: string
58
+ /** 上下文窗口(usage 百分比计算;未知则 percent=null) */
59
+ contextWindow?: number
60
+ /** 压缩阈值(0-1,默认 0.7) */
61
+ compactThreshold?: number
62
+ /** 回合停滞超时(ms,默认 600000) */
63
+ promptTimeoutMs?: number
64
+ /** supervise 超时(ms,默认 150000) */
65
+ superviseTimeoutMs?: number
66
+ systemPromptPrefix?: string
67
+ scenarioPrompt?: string
68
+ agentId?: string
69
+ name?: string
70
+ role?: 'lead' | 'worker'
71
+ channelId?: string
72
+ /** 平台自证 token(MCP 桥回程鉴权;factory 注入) */
73
+ token?: string
74
+ /** 平台 HTTP 基址(桥回程;默认 AW_BASE_URL 或 127.0.0.1:PORT) */
75
+ baseUrl?: string
76
+ /** MCP 桥脚本路径(默认 <packageRoot>/server/harness/aw-mcp-bridge.mjs) */
77
+ mcpBridgePath?: string
78
+ }
79
+
80
+ const sleep = (ms: number): Promise<void> => new Promise(r => setTimeout(r, ms))
81
+
82
+ const DEFAULT_PERMISSION = [
83
+ { permission: 'edit', pattern: '*', action: 'ask' },
84
+ { permission: 'bash', pattern: '*', action: 'ask' },
85
+ { permission: 'webfetch', pattern: '*', action: 'ask' },
86
+ ]
87
+
88
+ /** 取一个空闲 TCP 端口(绑定即弃,竞态窗口小;opencode serve 自身再绑定) */
89
+ async function freePort(): Promise<number> {
90
+ return new Promise((resolve, reject) => {
91
+ const srv = createServer()
92
+ srv.unref()
93
+ srv.on('error', reject)
94
+ srv.listen(0, '127.0.0.1', () => {
95
+ const addr = srv.address()
96
+ const port = typeof addr === 'object' && addr ? addr.port : 0
97
+ srv.close(() => (port ? resolve(port) : reject(new Error('无可用端口'))))
98
+ })
99
+ })
100
+ }
101
+
102
+ interface PendingHitl {
103
+ kind: 'opencode-permission'
104
+ id: string
105
+ type: 'permission' | 'question'
106
+ sessionId: string
107
+ timer: ReturnType<typeof setTimeout> | null
108
+ }
109
+
110
+ export class OpenCodeAgentImpl extends BaseAgentImpl implements AgentInterface {
111
+ private readonly config: OpenCodeAgentConfig
112
+ private agentInfo: AgentInfo | null = null
113
+ private readonly bridgeCtx = {
114
+ identity: { agentId: '', channelId: '', role: 'worker' as 'lead' | 'worker', name: 'agent' },
115
+ state: this.toolState,
116
+ getWorkspace: () => this.workspace,
117
+ }
118
+
119
+ private agentRole: 'lead' | 'worker' = 'worker'
120
+
121
+ // 服务进程与 API 面
122
+ private child: ReturnType<typeof spawnLineProcess> | null = null
123
+ private baseUrl = ''
124
+ private basicAuth = ''
125
+ private sessionId: string | null = null
126
+ private serverStarting: Promise<void> | null = null
127
+ private exited = false
128
+ private stderrTail = ''
129
+ private sseAbort: AbortController | null = null
130
+
131
+ // 回合状态
132
+ private turnActive = false
133
+ private aborted = false
134
+ /** 助手正文(partId → 全文;message.part.updated 携带全量文本) */
135
+ private partTexts = new Map<string, string>()
136
+ private partOrder: string[] = []
137
+ private lastUsage: { input: number, at: number } | null = null
138
+ private compacting = false
139
+ private lastCompactAt = 0
140
+ /** 待应答 HITL(id → 定位信息) */
141
+ private pendingHitl = new Map<string, PendingHitl>()
142
+
143
+ constructor(config: Record<string, unknown> = {}) {
144
+ super({
145
+ agentId: typeof config.agentId === 'string' ? config.agentId : '',
146
+ name: typeof config.name === 'string' ? config.name : undefined,
147
+ role: config.role === 'lead' ? 'lead' : 'worker',
148
+ channelId: typeof config.channelId === 'string' ? config.channelId : '',
149
+ })
150
+ this.config = config as OpenCodeAgentConfig
151
+ }
152
+
153
+ protected get harnessId(): string {
154
+ return 'opencode'
155
+ }
156
+
157
+ protected configRecord(): Record<string, unknown> {
158
+ return this.config
159
+ }
160
+
161
+ // ===== 生命周期 / 进程面 =====
162
+
163
+ getProcessInfo(): { pid: number, alive: boolean, command: string } | null {
164
+ const pid = this.child?.pid
165
+ if (!pid || !this.child) return null
166
+ return { pid, alive: !this.exited, command: 'opencode serve' }
167
+ }
168
+
169
+ killProcess(): void {
170
+ const pid = this.child?.pid
171
+ if (pid) killHarnessProcess(pid)
172
+ this.child = null
173
+ }
174
+
175
+ reconcileProcess(): void {
176
+ const pid = this.child?.pid
177
+ if (!pid || this.exited) return
178
+ if (!isProcessAlive(pid)) this.handleServerExit(null)
179
+ }
180
+
181
+ async dispose(): Promise<void> {
182
+ this.sseAbort?.abort()
183
+ const pid = this.child?.pid
184
+ if (pid) {
185
+ killHarnessProcess(pid)
186
+ markHarnessProcessExit(pid, null)
187
+ }
188
+ this.child = null
189
+ this.exited = true
190
+ this.serverStarting = null
191
+ for (const [id, p] of this.pendingHitl) {
192
+ if (p.timer) clearTimeout(p.timer)
193
+ this.pendingHitl.delete(id)
194
+ }
195
+ }
196
+
197
+ // ===== 引擎无关面 =====
198
+
199
+ getContextStats(): AgentContextStats | null {
200
+ if (!this.lastUsage) return null
201
+ const window = this.config.contextWindow ?? null
202
+ return {
203
+ usedTokens: this.lastUsage.input,
204
+ contextWindow: window,
205
+ percent: window && window > 0 ? Math.min(1, this.lastUsage.input / window) : null,
206
+ compacting: this.compacting,
207
+ }
208
+ }
209
+
210
+ /**
211
+ * 实时注入:回合运行中再投一条 prompt(opencode 引擎 admit 为 steer/queue,
212
+ * 内容必然到达模型)→ 'steer';空闲 → 'deferred'(消费循环起回合处理)。
213
+ */
214
+ async steer(text: string): Promise<'steer' | 'deferred'> {
215
+ if (!this.sessionId || !this.turnActive) return 'deferred'
216
+ try {
217
+ await this.promptAsync(text)
218
+ return 'steer'
219
+ }
220
+ catch (err) {
221
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] steer 投递失败(消息保持 pending):`, err instanceof Error ? err.message : err)
222
+ return 'deferred'
223
+ }
224
+ }
225
+
226
+ /** HITL 应答(codex/opencode/dsh 统一入口;本 impl 处理 opencode-permission) */
227
+ async respondHitl(kind: string, id: string, outcome: {
228
+ confirmed?: boolean
229
+ cancelled?: boolean
230
+ value?: string
231
+ response?: string
232
+ comment?: string
233
+ }): Promise<void> {
234
+ if (kind !== 'opencode-permission') return
235
+ const pending = this.pendingHitl.get(id)
236
+ if (!pending) throw new Error(`待办不存在或已处理: ${id}`)
237
+ // 应答映射:显式 response > confirmed/cancelled 布尔(缺省拒绝,fail-closed)
238
+ const cancelled = outcome.cancelled === true || (outcome.confirmed !== true && !outcome.response)
239
+ if (pending.type === 'permission') {
240
+ const response = cancelled ? 'reject' : (outcome.response === 'always' || outcome.response === 'once' ? outcome.response : 'once')
241
+ await this.api('POST', `/session/${pending.sessionId}/permissions/${encodeURIComponent(id)}`, { response })
242
+ }
243
+ else {
244
+ // question:取消走 reject 端点;回答携带 value
245
+ if (cancelled) {
246
+ await this.api('POST', `/question/${encodeURIComponent(id)}/reject`, {})
247
+ }
248
+ else {
249
+ await this.api('POST', `/question/${encodeURIComponent(id)}/reply`, { answer: outcome.value ?? outcome.comment ?? '' })
250
+ }
251
+ }
252
+ if (pending.timer) clearTimeout(p.timer)
253
+ this.pendingHitl.delete(id)
254
+ getHitlRegistry().resolve(kind, id, cancelled ? 'cancelled' : 'answered')
255
+ }
256
+
257
+ /** 上下文治理(post-settle 钩子):越阈值 → summarize;异常不抛出 */
258
+ async onTurnSettled(): Promise<void> {
259
+ if (this.compacting || !this.sessionId) return
260
+ const stats = this.getContextStats()
261
+ const threshold = this.config.compactThreshold ?? 0.7
262
+ if (!stats?.percent || stats.percent < threshold) return
263
+ if (Date.now() - this.lastCompactAt < 5 * 60_000) return
264
+ this.compacting = true
265
+ this.lastCompactAt = Date.now()
266
+ try {
267
+ await this.api('POST', `/session/${this.sessionId}/summarize`, {})
268
+ log.info(`[OpenCodeAgent:${this.selfAgentId}] 上下文压缩已触发(percent=${(stats.percent * 100).toFixed(0)}%)`)
269
+ }
270
+ catch (err) {
271
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] summarize 失败(放行):`, err instanceof Error ? err.message : err)
272
+ }
273
+ finally {
274
+ this.compacting = false
275
+ }
276
+ }
277
+
278
+ private supervising = false
279
+
280
+ async supervise(snapshot: SupervisionSnapshot, ctx: AgentRunContext, opts?: { signal?: AbortSignal }): Promise<SupervisionDecision[]> {
281
+ // 引擎/会话不可用 → 本轮监督降级为空(调度器回退规则引擎);绝不让引擎故障
282
+ // 以 unhandledRejection 形态逃逸(dev-stability-guard 会据此杀掉整个服务端)
283
+ try {
284
+ await this.ensureServer(ctx)
285
+ }
286
+ catch (err) {
287
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] supervise 引擎不可用,跳过本轮:`, err instanceof Error ? err.message : err)
288
+ return []
289
+ }
290
+ if (!this.sessionId) return []
291
+ if (this.supervising) return []
292
+ const prompt = supervisePrompt({
293
+ snapshot,
294
+ agentName: this.agentName,
295
+ channelId: this.channelId,
296
+ ctxPrefix: await this.contextPrefix(),
297
+ manual: systemManual(),
298
+ memory: ctx.memory,
299
+ })
300
+ const timeoutMs = this.config.superviseTimeoutMs ?? 150_000
301
+ return await this.runTurn(prompt, undefined, {
302
+ timeoutMs,
303
+ signal: opts?.signal,
304
+ onDone: async () => {
305
+ this.supervising = false
306
+ },
307
+ beforeStart: () => {
308
+ this.supervising = true
309
+ },
310
+ }).then((events) => {
311
+ // 从事件流提取最终文本 → JSON 决策兜底(工具直执行路径返回空)
312
+ let text = ''
313
+ for (const e of events) {
314
+ if (e.kind === 'artifact') {
315
+ text += e.artifact.parts.map(p => 'text' in p ? p.text : '').join('')
316
+ }
317
+ }
318
+ const parsed = extractJsonArray(text)
319
+ return parsed && parsed.length > 0 ? parsed as SupervisionDecision[] : []
320
+ }).catch(() => {
321
+ this.supervising = false
322
+ return []
323
+ })
324
+ }
325
+
326
+ protected async* workerTurn(request: AgentRunRequest, ctx: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown> {
327
+ const taskId = request.taskId ?? (request.message.metadata?.['x-aw-task-id'] as string | undefined)
328
+ if (!taskId) return
329
+ this.toolState.currentTaskId = taskId
330
+ try {
331
+ await this.ensureServer(ctx)
332
+ const taskText = request.message.parts.map((p) => {
333
+ if ('text' in p) return p.text
334
+ if ('data' in p) return JSON.stringify(p.data)
335
+ if ('url' in p) return p.url
336
+ if ('raw' in p) return p.raw
337
+ return ''
338
+ }).join('\n')
339
+ const prompt = workerPrompt({
340
+ agentName: this.agentName,
341
+ channelId: this.channelId,
342
+ taskId,
343
+ taskText,
344
+ memory: request.memory,
345
+ ctxPrefix: await this.contextPrefix(),
346
+ manual: systemManual(),
347
+ })
348
+ yield* this.runTurn(prompt, taskId, {
349
+ timeoutMs: this.config.promptTimeoutMs ?? 600_000,
350
+ signal: ctx.signal,
351
+ })
352
+ }
353
+ finally {
354
+ this.toolState.currentTaskId = null
355
+ }
356
+ }
357
+
358
+ protected async* peerTurn(request: AgentRunRequest, ctx: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown> {
359
+ await this.ensureServer(ctx)
360
+ const msg = request.message
361
+ const fromId = request.fromAgentId
362
+ ?? (typeof msg.metadata?.['x-aw-from-label'] === 'string' ? msg.metadata['x-aw-from-label'] : undefined)
363
+ ?? 'unknown'
364
+ const requireReply = msg.metadata?.['x-aw-require-reply'] === 'true'
365
+ const crossChannel = msg.metadata?.['x-aw-cross-channel'] === 'true'
366
+ this.toolState.replyContext = requireReply && request.fromAgentId && !crossChannel
367
+ ? { fromId: request.fromAgentId, messageId: msg.messageId }
368
+ : null
369
+ const msgText = msg.parts.map((p) => {
370
+ if ('text' in p) return p.text
371
+ if ('data' in p) return JSON.stringify(p.data)
372
+ if ('url' in p) return p.url
373
+ if ('raw' in p) return p.raw
374
+ return ''
375
+ }).join('\n')
376
+ const prompt = peerPrompt({
377
+ agentName: this.agentName,
378
+ role: this.agentRole,
379
+ channelId: this.channelId,
380
+ ctxPrefix: await this.contextPrefix(),
381
+ manual: systemManual(),
382
+ memory: request.memory,
383
+ fromId,
384
+ messageId: msg.messageId,
385
+ requireReply,
386
+ isReply: typeof msg.metadata?.['x-aw-in-reply-to'] === 'string',
387
+ crossChannel,
388
+ fromChannel: typeof msg.metadata?.['x-aw-from-channel'] === 'string' ? String(msg.metadata['x-aw-from-channel']) : '',
389
+ msgText,
390
+ })
391
+ yield* this.runTurn(prompt, undefined, { timeoutMs: this.config.promptTimeoutMs ?? 600_000, signal: ctx.signal })
392
+ }
393
+
394
+ // ===== 回合执行(prompt → SSE 事件 → AgentEvent)=====
395
+
396
+ private runTurn(
397
+ prompt: string,
398
+ taskId: string | undefined,
399
+ opts: { timeoutMs: number, signal?: AbortSignal, beforeStart?: () => void, onDone?: () => void },
400
+ ): AsyncGenerator<AgentEvent, void, unknown> {
401
+ return this._runTurn(prompt, taskId, opts)
402
+ }
403
+
404
+ private async* _runTurn(
405
+ prompt: string,
406
+ taskId: string | undefined,
407
+ opts: { timeoutMs: number, signal?: AbortSignal, beforeStart?: () => void, onDone?: () => void },
408
+ ): AsyncGenerator<AgentEvent, void, unknown> {
409
+ if (!this.sessionId) {
410
+ yield { kind: 'error', error: { code: 'OPENCODE_NOT_READY', message: 'opencode 会话未就绪' } }
411
+ return
412
+ }
413
+ opts.beforeStart?.()
414
+ const queue: AgentEvent[] = []
415
+ let isDone = false
416
+ let resolveWait: (() => void) | null = null
417
+ let lastActivity = Date.now()
418
+ this.turnActive = true
419
+ this.aborted = false
420
+ this.partTexts = new Map()
421
+ this.partOrder = []
422
+
423
+ const enqueue = (e: AgentEvent): void => {
424
+ // done 事件前先收口 artifact(助手正文聚合),保证事件序 artifact → done
425
+ if (e.kind === 'done' && !isDone) {
426
+ const text = this.partOrder.map(id => this.partTexts.get(id) ?? '').join('').trim()
427
+ if (text) {
428
+ queue.push({
429
+ kind: 'artifact',
430
+ artifact: { artifactId: randomUUID(), name: 'output', parts: [{ text }] },
431
+ lastChunk: true,
432
+ totalChunks: 1,
433
+ })
434
+ }
435
+ this.turnActive = false
436
+ opts.onDone?.()
437
+ }
438
+ if (e.kind === 'done' || e.kind === 'error') {
439
+ isDone = true
440
+ this.turnActive = false
441
+ }
442
+ queue.push(e)
443
+ lastActivity = Date.now()
444
+ resolveWait?.()
445
+ resolveWait = null
446
+ }
447
+
448
+ // 事件订阅(SSE → 队列)
449
+ const unsub = this.onEngineEvent((ev) => {
450
+ for (const mapped of this.mapEngineEvent(ev, taskId)) enqueue(mapped)
451
+ })
452
+
453
+ // 停滞看门狗
454
+ let stallTimer: ReturnType<typeof setTimeout> | null = null
455
+
456
+ const finishTurn = (): void => {
457
+ if (isDone) return
458
+ const text = this.partOrder.map(id => this.partTexts.get(id) ?? '').join('').trim()
459
+ if (text) {
460
+ enqueue({
461
+ kind: 'artifact',
462
+ artifact: { artifactId: randomUUID(), name: 'output', parts: [{ text }] },
463
+ lastChunk: true,
464
+ totalChunks: 1,
465
+ })
466
+ }
467
+ enqueue({ kind: 'done', final: taskId ? { taskId } : undefined })
468
+ this.turnActive = false
469
+ opts.onDone?.()
470
+ }
471
+
472
+ const onAbort = (): void => {
473
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] run 被 abort → POST abort,taskId=${taskId ?? '-'}`)
474
+ this.aborted = true
475
+ void this.api('POST', `/session/${this.sessionId}/abort`, {}).catch(() => {})
476
+ // 引擎将回 session.idle → finishTurn;兜底 5s 后强制收口
477
+ setTimeout(() => finishTurn(), 5000)
478
+ }
479
+ if (opts.signal?.aborted) onAbort()
480
+ else opts.signal?.addEventListener('abort', onAbort, { once: true })
481
+
482
+ // 投递 prompt
483
+ try {
484
+ await this.promptAsync(prompt)
485
+ enqueue({ kind: 'status', status: { state: 'WORKING', timestamp: new Date().toISOString() } })
486
+ }
487
+ catch (err) {
488
+ unsub()
489
+ opts.signal?.removeEventListener('abort', onAbort)
490
+ this.turnActive = false
491
+ yield {
492
+ kind: 'error',
493
+ error: {
494
+ code: 'OPENCODE_PROMPT_FAILED',
495
+ message: `opencode prompt 失败: ${err instanceof Error ? err.message : String(err)}`,
496
+ },
497
+ }
498
+ return
499
+ }
500
+
501
+ try {
502
+ while (!isDone || queue.length > 0) {
503
+ if (queue.length === 0 && !isDone) {
504
+ const remaining = opts.timeoutMs - (Date.now() - lastActivity)
505
+ if (remaining <= 0) {
506
+ this.aborted = true
507
+ void this.api('POST', `/session/${this.sessionId}/abort`, {}).catch(() => {})
508
+ enqueue({
509
+ kind: 'error',
510
+ error: {
511
+ code: 'OPENCODE_TURN_STALLED',
512
+ message: `回合停滞 ${Math.round(opts.timeoutMs / 1000)}s 无事件,已中止(消息按已处理落账)`,
513
+ },
514
+ })
515
+ this.turnActive = false
516
+ continue
517
+ }
518
+ await new Promise<void>((r) => {
519
+ resolveWait = r
520
+ stallTimer = setTimeout(() => {
521
+ resolveWait = null
522
+ r()
523
+ }, remaining + 100)
524
+ })
525
+ if (stallTimer) {
526
+ clearTimeout(stallTimer)
527
+ stallTimer = null
528
+ }
529
+ }
530
+ while (queue.length > 0) {
531
+ yield queue.shift()!
532
+ }
533
+ }
534
+ }
535
+ finally {
536
+ if (stallTimer) clearTimeout(stallTimer)
537
+ unsub()
538
+ opts.signal?.removeEventListener('abort', onAbort)
539
+ this.turnActive = false
540
+ }
541
+ }
542
+
543
+ /** 引擎事件 → AgentEvent(适配器核心) */
544
+ private mapEngineEvent(ev: Record<string, unknown>, taskId: string | undefined): AgentEvent[] {
545
+ const type = String(ev.type ?? '')
546
+ const props = (ev.properties ?? {}) as Record<string, unknown>
547
+ const sid = props.sessionID ?? props.sessionId
548
+ if (sid && sid !== this.sessionId) return [] // 多会话实例隔离(本 impl 一会话,防御)
549
+
550
+ const now = new Date().toISOString()
551
+ const statusEvent = (text: string): AgentEvent => ({
552
+ kind: 'status',
553
+ status: {
554
+ state: 'WORKING',
555
+ message: { messageId: randomUUID(), contextId: this.channelId, role: 'ROLE_AGENT', parts: [{ text }] },
556
+ timestamp: now,
557
+ },
558
+ })
559
+
560
+ switch (type) {
561
+ case 'message.part.delta': {
562
+ if (props.field === 'text' && typeof props.delta === 'string' && props.delta) {
563
+ return [{ kind: 'delta', delta: { text: props.delta } }]
564
+ }
565
+ return []
566
+ }
567
+ case 'message.part.updated': {
568
+ const part = props.part as Record<string, unknown> | undefined
569
+ if (!part) return []
570
+ const partId = String(part.id ?? '')
571
+ const partType = String(part.type ?? '')
572
+ if (partType === 'text' && typeof part.text === 'string' && partId) {
573
+ if (!this.partOrder.includes(partId)) this.partOrder.push(partId)
574
+ this.partTexts.set(partId, part.text)
575
+ }
576
+ else if (partType === 'tool') {
577
+ const state = (part.state ?? {}) as Record<string, unknown>
578
+ const tool = String(part.tool ?? 'tool')
579
+ const statusStr = String(state.status ?? '')
580
+ if (statusStr === 'pending' || statusStr === 'running') {
581
+ const input = state.input ?? part.input
582
+ return [statusEvent(`🔧 ${tool}${toolArgsPreview(input)}`)]
583
+ }
584
+ if (statusStr === 'error') {
585
+ return [statusEvent(`🔧 ${tool} 失败: ${String(state.error ?? '未知错误').slice(0, 200)}`)]
586
+ }
587
+ }
588
+ else if (partType === 'compaction') {
589
+ this.lastCompactAt = Date.now()
590
+ }
591
+ return []
592
+ }
593
+ case 'message.updated': {
594
+ const info = props.info as Record<string, unknown> | undefined
595
+ if (info?.role === 'assistant') {
596
+ const tokens = info.tokens as Record<string, unknown> | undefined
597
+ const input = Number(tokens?.input)
598
+ if (Number.isFinite(input) && input > 0) this.lastUsage = { input, at: Date.now() }
599
+ const err = info.error as Record<string, unknown> | undefined
600
+ if (err && this.turnActive) {
601
+ const code = String(err.name ?? 'UnknownError')
602
+ return [{
603
+ kind: 'error',
604
+ error: { code: `OPENCODE_LLM_${code}`, message: String(err.message ?? 'opencode 回合错误') },
605
+ }]
606
+ }
607
+ }
608
+ return []
609
+ }
610
+ case 'session.error': {
611
+ const err = props.error as Record<string, unknown> | undefined
612
+ if (!this.turnActive) return []
613
+ const data = (err?.data ?? {}) as Record<string, unknown>
614
+ const detail = String(data.message ?? err?.message ?? 'opencode 会话错误')
615
+ return [{
616
+ kind: 'error',
617
+ error: {
618
+ code: `OPENCODE_ERROR_${String(err?.name ?? 'UNKNOWN')}`,
619
+ message: `${detail}${data.statusCode != null ? ` (HTTP ${data.statusCode})` : ''}`,
620
+ },
621
+ }]
622
+ }
623
+ case 'session.status': {
624
+ const status = props.status as Record<string, unknown> | undefined
625
+ if (String(status?.type ?? '') === 'idle' && this.turnActive) {
626
+ return [{ kind: 'done', final: taskId ? { taskId } : undefined }]
627
+ }
628
+ return []
629
+ }
630
+ case 'session.idle': {
631
+ if (this.turnActive) {
632
+ return [{ kind: 'done', final: taskId ? { taskId } : undefined }]
633
+ }
634
+ return []
635
+ }
636
+ // ===== HITL =====
637
+ case 'permission.asked':
638
+ case 'permission.v2.asked': {
639
+ this.registerPermissionHitl(type === 'permission.v2.asked', props)
640
+ return []
641
+ }
642
+ case 'question.asked': {
643
+ this.registerQuestionHitl(props)
644
+ return []
645
+ }
646
+ case 'permission.replied':
647
+ case 'permission.v2.replied':
648
+ case 'question.replied':
649
+ case 'question.rejected': {
650
+ const id = String(props.id ?? '')
651
+ if (id && this.pendingHitl.has(id)) {
652
+ const p = this.pendingHitl.get(id)!
653
+ if (p.timer) clearTimeout(p.timer)
654
+ this.pendingHitl.delete(id)
655
+ }
656
+ return []
657
+ }
658
+ default:
659
+ return []
660
+ }
661
+ }
662
+
663
+ private registerPermissionHitl(v2: boolean, props: Record<string, unknown>): void {
664
+ const id = String(props.id ?? '')
665
+ if (!id) return
666
+ if (this.pendingHitl.has(id)) return
667
+ const sessionId = String(props.sessionID ?? this.sessionId ?? '')
668
+ const permission = String(props.permission ?? props.action ?? 'action')
669
+ const patterns = Array.isArray(props.patterns) ? props.patterns.map(String).join(', ') : ''
670
+ const v2res = Array.isArray(props.resources) ? props.resources.map(String).join(', ') : ''
671
+ const detail = patterns || v2res
672
+ const title = `opencode 权限请求:${permission}${detail ? `(${detail})` : ''}`
673
+ this.registerHitl(id, 'permission', sessionId, title, `引擎将执行 ${permission}${detail ? ` → ${detail}` : ''};批准放行一次,拒绝则引擎收到 reject。`)
674
+ }
675
+
676
+ private registerQuestionHitl(props: Record<string, unknown>): void {
677
+ const id = String(props.id ?? '')
678
+ if (!id || this.pendingHitl.has(id)) return
679
+ const sessionId = String(props.sessionID ?? this.sessionId ?? '')
680
+ const questions = Array.isArray(props.questions) ? props.questions : []
681
+ const first = (questions[0] ?? {}) as Record<string, unknown>
682
+ const title = String(first.question ?? first.header ?? 'opencode 提问')
683
+ this.registerHitl(id, 'question', sessionId, title, String(first.question ?? ''), 'input')
684
+ }
685
+
686
+ private registerHitl(id: string, type: 'permission' | 'question', sessionId: string, title: string, detail: string, method: 'confirm' | 'input' = 'confirm'): void {
687
+ const registry = getHitlRegistry()
688
+ registry.register({
689
+ kind: 'opencode-permission',
690
+ id,
691
+ agentId: this.selfAgentId,
692
+ agentName: this.agentName,
693
+ channelId: this.channelId,
694
+ pid: this.child?.pid,
695
+ method,
696
+ title,
697
+ detail,
698
+ createdAt: new Date().toISOString(),
699
+ expiresAt: null,
700
+ })
701
+ // 无人应答超时(fail-closed:到时自动拒绝),0 = 无限等待
702
+ const timeoutMs = harnessSettings().hitl_timeout_ms
703
+ const timer = timeoutMs > 0
704
+ ? setTimeout(() => {
705
+ void this.respondHitl('opencode-permission', id, { cancelled: true }).catch(() => {})
706
+ registry.resolve('opencode-permission', id, 'expired')
707
+ }, timeoutMs)
708
+ : null
709
+ this.pendingHitl.set(id, { kind: 'opencode-permission', id, type, sessionId, timer })
710
+ }
711
+
712
+ // ===== opencode 服务进程与 HTTP 客户端 =====
713
+
714
+ private async ensureServer(ctx: AgentRunContext): Promise<void> {
715
+ if (!this.workspace) this.workspace = ctx.workspace
716
+ if (!this.agentInfo) {
717
+ this.channelId = ctx.channelId
718
+ this.agentRole = ctx.role
719
+ this.refreshIdentity()
720
+ }
721
+ if (this.sessionId && this.child && !this.exited) return
722
+ this.serverStarting ??= this.startServer().finally(() => {
723
+ this.serverStarting = null
724
+ })
725
+ await this.serverStarting
726
+ }
727
+
728
+ private async startServer(): Promise<void> {
729
+ const command = this.config.command ?? harnessSettings().opencode_command
730
+ const port = await freePort()
731
+ const password = randomUUID()
732
+ const cwd = this.config.cwd ?? process.cwd()
733
+ this.exited = false
734
+ const child = spawnLineProcess(command, ['serve', '--port', String(port), '--hostname', '127.0.0.1'], {
735
+ cwd,
736
+ env: {
737
+ OPENCODE_SERVER_PASSWORD: password,
738
+ ...(this.config.dataDir ? { XDG_DATA_HOME: this.config.dataDir } : {}),
739
+ ...(this.config.configDir ? { XDG_CONFIG_HOME: this.config.configDir } : {}),
740
+ },
741
+ })
742
+ this.child = child
743
+ this.baseUrl = `http://127.0.0.1:${port}`
744
+ this.basicAuth = `Basic ${Buffer.from(`opencode:${password}`).toString('base64')}`
745
+ child.stderr?.setEncoding('utf-8')
746
+ child.stderr?.on('data', (d: string) => {
747
+ this.stderrTail = (this.stderrTail + d).slice(-8000)
748
+ })
749
+ const pid = child.pid
750
+ if (pid) {
751
+ registerHarnessProcess(pid, { harness: 'opencode', command, args: ['serve', '--port', String(port)] })
752
+ bindHarnessProcess(pid, { agentId: this.selfAgentId, channelId: this.channelId, name: this.agentName, role: this.agentRole })
753
+ }
754
+ child.on('exit', code => this.handleServerExit(code))
755
+
756
+ // 健康探测(serve 冷启动含 provider registry,预算 60s;/global/health 需 Basic 认证)
757
+ const deadline = Date.now() + 60_000
758
+ let healthy = false
759
+ while (Date.now() < deadline) {
760
+ if (this.exited) {
761
+ throw new Error(`opencode serve 启动失败(进程退出)${this.stderrTail ? `\nstderr: ${this.stderrTail.slice(-400)}` : ''}`)
762
+ }
763
+ try {
764
+ const res = await fetch(`${this.baseUrl}/global/health`, {
765
+ headers: { authorization: this.basicAuth },
766
+ signal: AbortSignal.timeout(2000),
767
+ })
768
+ if (res.ok) {
769
+ healthy = true
770
+ break
771
+ }
772
+ }
773
+ catch { /* 未就绪,重试 */ }
774
+ await new Promise(r => setTimeout(r, 500))
775
+ }
776
+ if (!healthy) throw new Error(`opencode serve 健康探测超时(60s)${this.stderrTail ? `\nstderr: ${this.stderrTail.slice(-400)}` : ''}`)
777
+
778
+ // 注册 MCP 桥(全量 host tools 注入;幂等;command 为 [可执行, 参数...] 数组形态)
779
+ try {
780
+ await this.api('POST', '/mcp', {
781
+ name: 'aw-host-tools',
782
+ config: {
783
+ type: 'local',
784
+ command: [process.execPath, resolveBridgePath(this.config.mcpBridgePath)],
785
+ environment: {
786
+ AW_BASE_URL: resolvePlatformBaseUrl(this.config.baseUrl),
787
+ AW_AGENT_ID: this.selfAgentId,
788
+ AW_AGENT_TOKEN: this.config.token ?? '',
789
+ AW_MCP_TOOL_TIMEOUT_MS: String(200_000),
790
+ },
791
+ },
792
+ })
793
+ }
794
+ catch (err) {
795
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] MCP 桥注册失败(host tools 不可用):`, err instanceof Error ? err.message : err)
796
+ }
797
+
798
+ // 建会话(权限策略缺省全 ask;部分版本不认 permission/model 字段时降级重试;
799
+ // model 按回合在 prompt_async 里传 —— session 创建面不接受它)
800
+ const body: Record<string, unknown> = {
801
+ title: `${this.agentName}@${this.channelId || 'channel'}`,
802
+ }
803
+ const createWith = async (extra: Record<string, unknown> | undefined): Promise<Record<string, unknown>> =>
804
+ this.api('POST', '/session', { ...body, ...(extra ?? {}) })
805
+ const created = await (this.config.permission ?? DEFAULT_PERMISSION)
806
+ ? createWith({ permission: this.config.permission ?? DEFAULT_PERMISSION }).catch(() => createWith(undefined))
807
+ : createWith(undefined)
808
+ this.sessionId = String(created?.id ?? '')
809
+ if (!this.sessionId) {
810
+ // 瞬态失败(实例刚起/内部分配竞态/权限规则不兼容)→ 无附加字段重试,最多 3 次
811
+ for (let i = 0; i < 3 && !this.sessionId; i++) {
812
+ await sleep(2500)
813
+ const retry = await createWith(undefined).catch(() => null)
814
+ this.sessionId = String(retry?.id ?? '')
815
+ }
816
+ }
817
+ if (!this.sessionId) {
818
+ // 会话建不出来(版本/参数不兼容):回收 serve 子进程与句柄后抛错,防泄漏
819
+ const detail = this.stderrTail ? ` stderr: ${this.stderrTail.slice(-300)}` : ''
820
+ killHarnessProcess(this.child?.pid ?? -1)
821
+ this.child = null
822
+ this.exited = true
823
+ throw new Error(`opencode 会话创建失败(无 session id)${detail}`)
824
+ }
825
+
826
+ // 订阅全局事件流
827
+ this.openEventStream()
828
+ }
829
+
830
+ private modelRef(): Record<string, string> | undefined {
831
+ const model = this.config.model
832
+ if (!model) return undefined
833
+ if (model.includes('/')) {
834
+ const [providerID, modelID] = model.split('/', 2)
835
+ return { providerID: providerID ?? '', modelID: modelID ?? '' }
836
+ }
837
+ return { providerID: 'opencode', modelID: model }
838
+ }
839
+
840
+ private handleServerExit(code: number | null): void {
841
+ if (this.exited) return
842
+ this.exited = true
843
+ this.sseAbort?.abort()
844
+ const pid = this.child?.pid
845
+ if (pid) markHarnessProcessExit(pid, code)
846
+ // 在途回合经引擎错误归位:下一回合 ensureServer 重生
847
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] opencode serve 退出(code=${code});下回合自动重生`)
848
+ }
849
+
850
+ /** 全局 SSE 订阅(断线重连;帧解析 data: 行) */
851
+ private openEventStream(): void {
852
+ this.sseAbort?.abort()
853
+ const ctrl = new AbortController()
854
+ this.sseAbort = ctrl
855
+ const connect = async (): Promise<void> => {
856
+ while (!ctrl.signal.aborted && !this.exited) {
857
+ try {
858
+ const res = await fetch(`${this.baseUrl}/event`, {
859
+ headers: { authorization: this.basicAuth, accept: 'text/event-stream' },
860
+ signal: ctrl.signal,
861
+ })
862
+ if (!res.ok || !res.body) throw new Error(`SSE HTTP ${res.status}`)
863
+ const reader = res.body.getReader()
864
+ const decoder = new TextDecoder()
865
+ let buf = ''
866
+ for (;;) {
867
+ const { done, value } = await reader.read()
868
+ if (done) break
869
+ buf += decoder.decode(value, { stream: true })
870
+ const chunks = buf.split('\n\n')
871
+ buf = chunks.pop() ?? ''
872
+ for (const chunk of chunks) {
873
+ for (const line of chunk.split('\n')) {
874
+ if (!line.startsWith('data:')) continue
875
+ const payload = line.slice(5).trim()
876
+ if (!payload) continue
877
+ try {
878
+ this.dispatchEngineEvent(JSON.parse(payload))
879
+ }
880
+ catch { /* 非 JSON data 行忽略 */ }
881
+ }
882
+ }
883
+ }
884
+ }
885
+ catch (err) {
886
+ if (ctrl.signal.aborted || this.exited) return
887
+ log.warn(`[OpenCodeAgent:${this.selfAgentId}] SSE 断开(1s 后重连):`, err instanceof Error ? err.message : err)
888
+ await new Promise(r => setTimeout(r, 1000))
889
+ }
890
+ }
891
+ }
892
+ void connect()
893
+ }
894
+
895
+ /** SSE 事件缓冲(回合未激活时事件即到即弃,激活后由 mapEngineEvent 消费) */
896
+ private engineListeners = new Set<(ev: Record<string, unknown>) => void>()
897
+
898
+ private dispatchEngineEvent(ev: Record<string, unknown>): void {
899
+ for (const fn of this.engineListeners) fn(ev)
900
+ }
901
+
902
+ private onEngineEvent(fn: (ev: Record<string, unknown>) => void): () => void {
903
+ this.engineListeners.add(fn)
904
+ return () => this.engineListeners.delete(fn)
905
+ }
906
+
907
+ private async api(method: string, path: string, body?: unknown): Promise<Record<string, unknown>> {
908
+ const res = await fetch(`${this.baseUrl}${path}`, {
909
+ method,
910
+ headers: { authorization: this.basicAuth, ...(body !== undefined ? { 'content-type': 'application/json' } : {}) },
911
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
912
+ signal: AbortSignal.timeout(60_000),
913
+ })
914
+ if (res.status === 204) return {}
915
+ const text = await res.text()
916
+ let json: Record<string, unknown> = {}
917
+ try {
918
+ json = text ? JSON.parse(text) as Record<string, unknown> : {}
919
+ }
920
+ catch { /* 非 JSON 响应体 */ }
921
+ if (!res.ok) {
922
+ throw new Error(`opencode API ${method} ${path} → HTTP ${res.status}: ${String((json as { message?: string }).message ?? text.slice(0, 200))}`)
923
+ }
924
+ return json
925
+ }
926
+
927
+ private async promptAsync(text: string): Promise<void> {
928
+ if (!this.sessionId) throw new Error('会话未就绪')
929
+ await this.api('POST', `/session/${this.sessionId}/prompt_async`, {
930
+ parts: [{ type: 'text', text }],
931
+ ...(this.config.agent ? { agent: this.config.agent } : {}),
932
+ ...(this.config.model ? { model: this.modelRef() } : {}),
933
+ ...(this.config.variant ? { variant: this.config.variant } : (this.config.effort ? { variant: this.config.effort } : {})),
934
+ })
935
+ }
936
+ }