happy2 0.0.11 → 0.0.13

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 (443) hide show
  1. package/README.md +10 -0
  2. package/package.json +2 -2
  3. package/packages/happy2-server/PLUGINS.md +205 -45
  4. package/packages/happy2-server/README.md +19 -7
  5. package/packages/happy2-server/dist/daemon.d.ts +39 -0
  6. package/packages/happy2-server/dist/daemon.d.ts.map +1 -0
  7. package/packages/happy2-server/dist/daemon.js +302 -0
  8. package/packages/happy2-server/dist/daemon.js.map +1 -0
  9. package/packages/happy2-server/dist/daemon.test.d.ts +2 -0
  10. package/packages/happy2-server/dist/daemon.test.d.ts.map +1 -0
  11. package/packages/happy2-server/dist/daemon.test.js +245 -0
  12. package/packages/happy2-server/dist/daemon.test.js.map +1 -0
  13. package/packages/happy2-server/dist/index.d.ts +3 -2
  14. package/packages/happy2-server/dist/index.d.ts.map +1 -1
  15. package/packages/happy2-server/dist/index.js +2 -1
  16. package/packages/happy2-server/dist/index.js.map +1 -1
  17. package/packages/happy2-server/dist/modules/agent/agentChatBind.d.ts +1 -0
  18. package/packages/happy2-server/dist/modules/agent/agentChatBind.d.ts.map +1 -1
  19. package/packages/happy2-server/dist/modules/agent/agentChatBind.js +4 -0
  20. package/packages/happy2-server/dist/modules/agent/agentChatBind.js.map +1 -1
  21. package/packages/happy2-server/dist/modules/agent/agentChatGetContext.d.ts.map +1 -1
  22. package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js +3 -1
  23. package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js.map +1 -1
  24. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts +7 -0
  25. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts.map +1 -0
  26. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js +15 -0
  27. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js.map +1 -0
  28. package/packages/happy2-server/dist/modules/agent/agentCreate.d.ts.map +1 -1
  29. package/packages/happy2-server/dist/modules/agent/agentCreate.js +1 -0
  30. package/packages/happy2-server/dist/modules/agent/agentCreate.js.map +1 -1
  31. package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.d.ts +4 -2
  32. package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.d.ts.map +1 -1
  33. package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.js +8 -8
  34. package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.js.map +1 -1
  35. package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.d.ts +3 -3
  36. package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.d.ts.map +1 -1
  37. package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.js +4 -4
  38. package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.js.map +1 -1
  39. package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.d.ts +4 -4
  40. package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.d.ts.map +1 -1
  41. package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.js +57 -41
  42. package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.js.map +1 -1
  43. package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.d.ts +1 -1
  44. package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js +3 -3
  45. package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js.map +1 -1
  46. package/packages/happy2-server/dist/modules/agent/agentImageCreate.d.ts +1 -1
  47. package/packages/happy2-server/dist/modules/agent/agentImageCreate.js +3 -3
  48. package/packages/happy2-server/dist/modules/agent/agentImageCreate.js.map +1 -1
  49. package/packages/happy2-server/dist/modules/agent/agentImageGet.d.ts +1 -1
  50. package/packages/happy2-server/dist/modules/agent/agentImageGet.js +3 -3
  51. package/packages/happy2-server/dist/modules/agent/agentImageGet.js.map +1 -1
  52. package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.d.ts +2 -1
  53. package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.d.ts.map +1 -1
  54. package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js +11 -4
  55. package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js.map +1 -1
  56. package/packages/happy2-server/dist/modules/agent/agentImageList.d.ts +2 -2
  57. package/packages/happy2-server/dist/modules/agent/agentImageList.d.ts.map +1 -1
  58. package/packages/happy2-server/dist/modules/agent/agentImageList.js +8 -4
  59. package/packages/happy2-server/dist/modules/agent/agentImageList.js.map +1 -1
  60. package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.d.ts +1 -1
  61. package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js +3 -3
  62. package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js.map +1 -1
  63. package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.d.ts +1 -1
  64. package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js +3 -3
  65. package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js.map +1 -1
  66. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.d.ts +1 -1
  67. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.js +3 -3
  68. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.js.map +1 -1
  69. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.d.ts +1 -1
  70. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.js +3 -3
  71. package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.js.map +1 -1
  72. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.d.ts +1 -1
  73. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.js +3 -3
  74. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.js.map +1 -1
  75. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.d.ts +1 -1
  76. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.js +3 -3
  77. package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.js.map +1 -1
  78. package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.d.ts +4 -3
  79. package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.d.ts.map +1 -1
  80. package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.js +5 -5
  81. package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.js.map +1 -1
  82. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.d.ts +1 -1
  83. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.js +3 -3
  84. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.js.map +1 -1
  85. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.d.ts +2 -2
  86. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.js +4 -4
  87. package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.js.map +1 -1
  88. package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.d.ts +1 -1
  89. package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.js +3 -3
  90. package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.js.map +1 -1
  91. package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.d.ts +4 -0
  92. package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.d.ts.map +1 -1
  93. package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.js +207 -9
  94. package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.js.map +1 -1
  95. package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.d.ts +8 -0
  96. package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.d.ts.map +1 -0
  97. package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.js +86 -0
  98. package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.js.map +1 -0
  99. package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.d.ts +19 -0
  100. package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.d.ts.map +1 -0
  101. package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.js +87 -0
  102. package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.js.map +1 -0
  103. package/packages/happy2-server/dist/modules/agent/impl/agentChatContext.d.ts +2 -1
  104. package/packages/happy2-server/dist/modules/agent/impl/agentChatContext.d.ts.map +1 -1
  105. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContext.d.ts +4 -1
  106. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContext.d.ts.map +1 -1
  107. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.d.ts +3 -3
  108. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.d.ts.map +1 -1
  109. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.js +26 -40
  110. package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.js.map +1 -1
  111. package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.d.ts.map +1 -1
  112. package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.js +63 -2
  113. package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.js.map +1 -1
  114. package/packages/happy2-server/dist/modules/agent/types.d.ts +53 -0
  115. package/packages/happy2-server/dist/modules/agent/types.d.ts.map +1 -1
  116. package/packages/happy2-server/dist/modules/agents/daemon.d.ts +31 -2
  117. package/packages/happy2-server/dist/modules/agents/daemon.d.ts.map +1 -1
  118. package/packages/happy2-server/dist/modules/agents/daemon.js +12 -2
  119. package/packages/happy2-server/dist/modules/agents/daemon.js.map +1 -1
  120. package/packages/happy2-server/dist/modules/agents/service.d.ts +13 -6
  121. package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -1
  122. package/packages/happy2-server/dist/modules/agents/service.js +497 -49
  123. package/packages/happy2-server/dist/modules/agents/service.js.map +1 -1
  124. package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.d.ts +12 -0
  125. package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.d.ts.map +1 -0
  126. package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.js +27 -0
  127. package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.js.map +1 -0
  128. package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.d.ts +8 -0
  129. package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.d.ts.map +1 -0
  130. package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.js +22 -0
  131. package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.js.map +1 -0
  132. package/packages/happy2-server/dist/modules/auth/methods.d.ts +1 -0
  133. package/packages/happy2-server/dist/modules/auth/methods.d.ts.map +1 -1
  134. package/packages/happy2-server/dist/modules/auth/methods.js +10 -6
  135. package/packages/happy2-server/dist/modules/auth/methods.js.map +1 -1
  136. package/packages/happy2-server/dist/modules/auth/service.d.ts +2 -0
  137. package/packages/happy2-server/dist/modules/auth/service.d.ts.map +1 -1
  138. package/packages/happy2-server/dist/modules/auth/service.js +26 -0
  139. package/packages/happy2-server/dist/modules/auth/service.js.map +1 -1
  140. package/packages/happy2-server/dist/modules/auth/tokens.d.ts +13 -0
  141. package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -1
  142. package/packages/happy2-server/dist/modules/auth/tokens.js +59 -0
  143. package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -1
  144. package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts +2 -0
  145. package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts.map +1 -0
  146. package/packages/happy2-server/dist/modules/auth/tokens.test.js +48 -0
  147. package/packages/happy2-server/dist/modules/auth/tokens.test.js.map +1 -0
  148. package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.d.ts +17 -0
  149. package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.d.ts.map +1 -0
  150. package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.js +98 -0
  151. package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.js.map +1 -0
  152. package/packages/happy2-server/dist/modules/chat/asServiceMessage.d.ts.map +1 -1
  153. package/packages/happy2-server/dist/modules/chat/asServiceMessage.js +13 -5
  154. package/packages/happy2-server/dist/modules/chat/asServiceMessage.js.map +1 -1
  155. package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.d.ts +20 -0
  156. package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.d.ts.map +1 -0
  157. package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.js +38 -0
  158. package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.js.map +1 -0
  159. package/packages/happy2-server/dist/modules/chat/types.d.ts +6 -0
  160. package/packages/happy2-server/dist/modules/chat/types.d.ts.map +1 -1
  161. package/packages/happy2-server/dist/modules/chat/types.js.map +1 -1
  162. package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.d.ts +7 -0
  163. package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.d.ts.map +1 -0
  164. package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.js +19 -0
  165. package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.js.map +1 -0
  166. package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.d.ts +2 -2
  167. package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.d.ts.map +1 -1
  168. package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.js +8 -5
  169. package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.js.map +1 -1
  170. package/packages/happy2-server/dist/modules/config/defaults.d.ts.map +1 -1
  171. package/packages/happy2-server/dist/modules/config/defaults.js +3 -0
  172. package/packages/happy2-server/dist/modules/config/defaults.js.map +1 -1
  173. package/packages/happy2-server/dist/modules/config/defaults.test.js +1 -0
  174. package/packages/happy2-server/dist/modules/config/defaults.test.js.map +1 -1
  175. package/packages/happy2-server/dist/modules/config/loader.d.ts.map +1 -1
  176. package/packages/happy2-server/dist/modules/config/loader.js +9 -0
  177. package/packages/happy2-server/dist/modules/config/loader.js.map +1 -1
  178. package/packages/happy2-server/dist/modules/config/loader.test.js +27 -0
  179. package/packages/happy2-server/dist/modules/config/loader.test.js.map +1 -1
  180. package/packages/happy2-server/dist/modules/config/type.d.ts +5 -0
  181. package/packages/happy2-server/dist/modules/config/type.d.ts.map +1 -1
  182. package/packages/happy2-server/dist/modules/message/messageGetProjection.d.ts.map +1 -1
  183. package/packages/happy2-server/dist/modules/message/messageGetProjection.js +28 -0
  184. package/packages/happy2-server/dist/modules/message/messageGetProjection.js.map +1 -1
  185. package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.d.ts +4 -0
  186. package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.d.ts.map +1 -0
  187. package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.js +39 -0
  188. package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.js.map +1 -0
  189. package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.d.ts +10 -0
  190. package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.d.ts.map +1 -0
  191. package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.js +31 -0
  192. package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.js.map +1 -0
  193. package/packages/happy2-server/dist/modules/permission/permissionGetEffective.d.ts +8 -0
  194. package/packages/happy2-server/dist/modules/permission/permissionGetEffective.d.ts.map +1 -0
  195. package/packages/happy2-server/dist/modules/permission/permissionGetEffective.js +13 -0
  196. package/packages/happy2-server/dist/modules/permission/permissionGetEffective.js.map +1 -0
  197. package/packages/happy2-server/dist/modules/permission/roleCreate.d.ts +16 -0
  198. package/packages/happy2-server/dist/modules/permission/roleCreate.d.ts.map +1 -0
  199. package/packages/happy2-server/dist/modules/permission/roleCreate.js +70 -0
  200. package/packages/happy2-server/dist/modules/permission/roleCreate.js.map +1 -0
  201. package/packages/happy2-server/dist/modules/permission/roleDelete.d.ts +11 -0
  202. package/packages/happy2-server/dist/modules/permission/roleDelete.d.ts.map +1 -0
  203. package/packages/happy2-server/dist/modules/permission/roleDelete.js +41 -0
  204. package/packages/happy2-server/dist/modules/permission/roleDelete.js.map +1 -0
  205. package/packages/happy2-server/dist/modules/permission/roleList.d.ts +8 -0
  206. package/packages/happy2-server/dist/modules/permission/roleList.d.ts.map +1 -0
  207. package/packages/happy2-server/dist/modules/permission/roleList.js +36 -0
  208. package/packages/happy2-server/dist/modules/permission/roleList.js.map +1 -0
  209. package/packages/happy2-server/dist/modules/permission/roleUpdate.d.ts +14 -0
  210. package/packages/happy2-server/dist/modules/permission/roleUpdate.d.ts.map +1 -0
  211. package/packages/happy2-server/dist/modules/permission/roleUpdate.js +78 -0
  212. package/packages/happy2-server/dist/modules/permission/roleUpdate.js.map +1 -0
  213. package/packages/happy2-server/dist/modules/permission/types.d.ts +24 -0
  214. package/packages/happy2-server/dist/modules/permission/types.d.ts.map +1 -0
  215. package/packages/happy2-server/dist/modules/permission/types.js +10 -0
  216. package/packages/happy2-server/dist/modules/permission/types.js.map +1 -0
  217. package/packages/happy2-server/dist/modules/permission/userPermissionGet.d.ts +16 -0
  218. package/packages/happy2-server/dist/modules/permission/userPermissionGet.d.ts.map +1 -0
  219. package/packages/happy2-server/dist/modules/permission/userPermissionGet.js +33 -0
  220. package/packages/happy2-server/dist/modules/permission/userPermissionGet.js.map +1 -0
  221. package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.d.ts +12 -0
  222. package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.d.ts.map +1 -0
  223. package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.js +44 -0
  224. package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.js.map +1 -0
  225. package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.d.ts +8 -0
  226. package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.d.ts.map +1 -0
  227. package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.js +12 -0
  228. package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.js.map +1 -0
  229. package/packages/happy2-server/dist/modules/permission/userRequirePermission.d.ts +8 -0
  230. package/packages/happy2-server/dist/modules/permission/userRequirePermission.d.ts.map +1 -0
  231. package/packages/happy2-server/dist/modules/permission/userRequirePermission.js +12 -0
  232. package/packages/happy2-server/dist/modules/permission/userRequirePermission.js.map +1 -0
  233. package/packages/happy2-server/dist/modules/permission/userRoleAssign.d.ts +12 -0
  234. package/packages/happy2-server/dist/modules/permission/userRoleAssign.d.ts.map +1 -0
  235. package/packages/happy2-server/dist/modules/permission/userRoleAssign.js +46 -0
  236. package/packages/happy2-server/dist/modules/permission/userRoleAssign.js.map +1 -0
  237. package/packages/happy2-server/dist/modules/permission/userRoleUnassign.d.ts +12 -0
  238. package/packages/happy2-server/dist/modules/permission/userRoleUnassign.d.ts.map +1 -0
  239. package/packages/happy2-server/dist/modules/permission/userRoleUnassign.js +53 -0
  240. package/packages/happy2-server/dist/modules/permission/userRoleUnassign.js.map +1 -0
  241. package/packages/happy2-server/dist/modules/plugin/archive.d.ts +7 -0
  242. package/packages/happy2-server/dist/modules/plugin/archive.d.ts.map +1 -0
  243. package/packages/happy2-server/dist/modules/plugin/archive.js +222 -0
  244. package/packages/happy2-server/dist/modules/plugin/archive.js.map +1 -0
  245. package/packages/happy2-server/dist/modules/plugin/catalog.d.ts +5 -1
  246. package/packages/happy2-server/dist/modules/plugin/catalog.d.ts.map +1 -1
  247. package/packages/happy2-server/dist/modules/plugin/catalog.js +75 -15
  248. package/packages/happy2-server/dist/modules/plugin/catalog.js.map +1 -1
  249. package/packages/happy2-server/dist/modules/plugin/catalog.test.js +37 -0
  250. package/packages/happy2-server/dist/modules/plugin/catalog.test.js.map +1 -1
  251. package/packages/happy2-server/dist/modules/plugin/httpBridge.d.ts +1 -0
  252. package/packages/happy2-server/dist/modules/plugin/httpBridge.d.ts.map +1 -1
  253. package/packages/happy2-server/dist/modules/plugin/httpBridge.js +7 -0
  254. package/packages/happy2-server/dist/modules/plugin/httpBridge.js.map +1 -1
  255. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.d.ts.map +1 -1
  256. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js +3 -2
  257. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js.map +1 -1
  258. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.d.ts.map +1 -1
  259. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js +17 -3
  260. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js.map +1 -1
  261. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts +3 -0
  262. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts.map +1 -0
  263. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js +12 -0
  264. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js.map +1 -0
  265. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.d.ts.map +1 -1
  266. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js +11 -0
  267. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js.map +1 -1
  268. package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.d.ts +11 -0
  269. package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.d.ts.map +1 -0
  270. package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.js +2 -0
  271. package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.js.map +1 -0
  272. package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts +13 -0
  273. package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts.map +1 -1
  274. package/packages/happy2-server/dist/modules/plugin/packageStore.js +122 -14
  275. package/packages/happy2-server/dist/modules/plugin/packageStore.js.map +1 -1
  276. package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.d.ts +1 -1
  277. package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.js +3 -3
  278. package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.js.map +1 -1
  279. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.d.ts.map +1 -1
  280. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js +15 -1
  281. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js.map +1 -1
  282. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts +10 -0
  283. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts.map +1 -0
  284. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js +20 -0
  285. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js.map +1 -0
  286. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts +12 -0
  287. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts.map +1 -0
  288. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js +44 -0
  289. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js.map +1 -0
  290. package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.d.ts +3 -1
  291. package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.d.ts.map +1 -1
  292. package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.js +1 -1
  293. package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.js.map +1 -1
  294. package/packages/happy2-server/dist/modules/plugin/pluginGetImage.d.ts +1 -1
  295. package/packages/happy2-server/dist/modules/plugin/pluginGetImage.js +3 -3
  296. package/packages/happy2-server/dist/modules/plugin/pluginGetImage.js.map +1 -1
  297. package/packages/happy2-server/dist/modules/plugin/pluginGetSource.d.ts +13 -0
  298. package/packages/happy2-server/dist/modules/plugin/pluginGetSource.d.ts.map +1 -0
  299. package/packages/happy2-server/dist/modules/plugin/pluginGetSource.js +37 -0
  300. package/packages/happy2-server/dist/modules/plugin/pluginGetSource.js.map +1 -0
  301. package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts.map +1 -1
  302. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js +28 -9
  303. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js.map +1 -1
  304. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.d.ts.map +1 -1
  305. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js +18 -7
  306. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js.map +1 -1
  307. package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.d.ts +1 -1
  308. package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.js +3 -3
  309. package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.js.map +1 -1
  310. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts +14 -0
  311. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts.map +1 -0
  312. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js +20 -0
  313. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js.map +1 -0
  314. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts +1 -0
  315. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts.map +1 -1
  316. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js +1 -0
  317. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js.map +1 -1
  318. package/packages/happy2-server/dist/modules/plugin/pluginList.d.ts +1 -1
  319. package/packages/happy2-server/dist/modules/plugin/pluginList.js +3 -3
  320. package/packages/happy2-server/dist/modules/plugin/pluginList.js.map +1 -1
  321. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts +11 -0
  322. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts.map +1 -0
  323. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js +43 -0
  324. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js.map +1 -0
  325. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts +15 -0
  326. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts.map +1 -0
  327. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js +37 -0
  328. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js.map +1 -0
  329. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts +16 -0
  330. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts.map +1 -0
  331. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js +71 -0
  332. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js.map +1 -0
  333. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.d.ts +8 -0
  334. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.d.ts.map +1 -0
  335. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.js +24 -0
  336. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.js.map +1 -0
  337. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.d.ts +8 -0
  338. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.d.ts.map +1 -0
  339. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.js +25 -0
  340. package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.js.map +1 -0
  341. package/packages/happy2-server/dist/modules/plugin/pluginUninstall.d.ts +13 -0
  342. package/packages/happy2-server/dist/modules/plugin/pluginUninstall.d.ts.map +1 -0
  343. package/packages/happy2-server/dist/modules/plugin/pluginUninstall.js +63 -0
  344. package/packages/happy2-server/dist/modules/plugin/pluginUninstall.js.map +1 -0
  345. package/packages/happy2-server/dist/modules/plugin/runtime.d.ts +20 -0
  346. package/packages/happy2-server/dist/modules/plugin/runtime.d.ts.map +1 -1
  347. package/packages/happy2-server/dist/modules/plugin/runtime.js +88 -2
  348. package/packages/happy2-server/dist/modules/plugin/runtime.js.map +1 -1
  349. package/packages/happy2-server/dist/modules/plugin/service.d.ts +64 -5
  350. package/packages/happy2-server/dist/modules/plugin/service.d.ts.map +1 -1
  351. package/packages/happy2-server/dist/modules/plugin/service.js +552 -173
  352. package/packages/happy2-server/dist/modules/plugin/service.js.map +1 -1
  353. package/packages/happy2-server/dist/modules/plugin/source.d.ts +35 -0
  354. package/packages/happy2-server/dist/modules/plugin/source.d.ts.map +1 -0
  355. package/packages/happy2-server/dist/modules/plugin/source.js +189 -0
  356. package/packages/happy2-server/dist/modules/plugin/source.js.map +1 -0
  357. package/packages/happy2-server/dist/modules/plugin/types.d.ts +87 -11
  358. package/packages/happy2-server/dist/modules/plugin/types.d.ts.map +1 -1
  359. package/packages/happy2-server/dist/modules/plugin/types.js +1 -0
  360. package/packages/happy2-server/dist/modules/plugin/types.js.map +1 -1
  361. package/packages/happy2-server/dist/modules/realtime/events.d.ts +3 -0
  362. package/packages/happy2-server/dist/modules/realtime/events.d.ts.map +1 -1
  363. package/packages/happy2-server/dist/modules/realtime/events.js +37 -5
  364. package/packages/happy2-server/dist/modules/realtime/events.js.map +1 -1
  365. package/packages/happy2-server/dist/modules/realtime/local.test.js +2 -0
  366. package/packages/happy2-server/dist/modules/realtime/local.test.js.map +1 -1
  367. package/packages/happy2-server/dist/modules/sandbox/index.d.ts +1 -1
  368. package/packages/happy2-server/dist/modules/sandbox/index.d.ts.map +1 -1
  369. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts +8 -1
  370. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts.map +1 -1
  371. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js +105 -3
  372. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js.map +1 -1
  373. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js +82 -3
  374. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js.map +1 -1
  375. package/packages/happy2-server/dist/modules/sandbox/types.d.ts +17 -0
  376. package/packages/happy2-server/dist/modules/sandbox/types.d.ts.map +1 -1
  377. package/packages/happy2-server/dist/modules/schema.d.ts +2245 -233
  378. package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -1
  379. package/packages/happy2-server/dist/modules/schema.js +120 -0
  380. package/packages/happy2-server/dist/modules/schema.js.map +1 -1
  381. package/packages/happy2-server/dist/modules/sync/syncGetDifference.d.ts.map +1 -1
  382. package/packages/happy2-server/dist/modules/sync/syncGetDifference.js +2 -0
  383. package/packages/happy2-server/dist/modules/sync/syncGetDifference.js.map +1 -1
  384. package/packages/happy2-server/dist/modules/user/userAdministrationList.js +2 -2
  385. package/packages/happy2-server/dist/modules/user/userAdministrationList.js.map +1 -1
  386. package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.d.ts.map +1 -1
  387. package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.js +49 -6
  388. package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.js.map +1 -1
  389. package/packages/happy2-server/dist/modules/user/userCreateProfile.d.ts.map +1 -1
  390. package/packages/happy2-server/dist/modules/user/userCreateProfile.js +17 -2
  391. package/packages/happy2-server/dist/modules/user/userCreateProfile.js.map +1 -1
  392. package/packages/happy2-server/dist/routes/agents.d.ts.map +1 -1
  393. package/packages/happy2-server/dist/routes/agents.js +4 -2
  394. package/packages/happy2-server/dist/routes/agents.js.map +1 -1
  395. package/packages/happy2-server/dist/routes/auth.d.ts.map +1 -1
  396. package/packages/happy2-server/dist/routes/auth.js +12 -0
  397. package/packages/happy2-server/dist/routes/auth.js.map +1 -1
  398. package/packages/happy2-server/dist/routes/collaboration.d.ts.map +1 -1
  399. package/packages/happy2-server/dist/routes/collaboration.js +7 -0
  400. package/packages/happy2-server/dist/routes/collaboration.js.map +1 -1
  401. package/packages/happy2-server/dist/routes/files.d.ts.map +1 -1
  402. package/packages/happy2-server/dist/routes/files.js +2 -0
  403. package/packages/happy2-server/dist/routes/files.js.map +1 -1
  404. package/packages/happy2-server/dist/routes/permissions.d.ts +6 -0
  405. package/packages/happy2-server/dist/routes/permissions.d.ts.map +1 -0
  406. package/packages/happy2-server/dist/routes/permissions.js +207 -0
  407. package/packages/happy2-server/dist/routes/permissions.js.map +1 -0
  408. package/packages/happy2-server/dist/routes/pluginHost.d.ts +6 -0
  409. package/packages/happy2-server/dist/routes/pluginHost.d.ts.map +1 -0
  410. package/packages/happy2-server/dist/routes/pluginHost.js +106 -0
  411. package/packages/happy2-server/dist/routes/pluginHost.js.map +1 -0
  412. package/packages/happy2-server/dist/routes/plugins.d.ts.map +1 -1
  413. package/packages/happy2-server/dist/routes/plugins.js +159 -5
  414. package/packages/happy2-server/dist/routes/plugins.js.map +1 -1
  415. package/packages/happy2-server/dist/runner.js +20 -1
  416. package/packages/happy2-server/dist/runner.js.map +1 -1
  417. package/packages/happy2-server/dist/server.d.ts +4 -0
  418. package/packages/happy2-server/dist/server.d.ts.map +1 -1
  419. package/packages/happy2-server/dist/server.js +23 -1
  420. package/packages/happy2-server/dist/server.js.map +1 -1
  421. package/packages/happy2-server/dist/systemService.d.ts.map +1 -1
  422. package/packages/happy2-server/dist/systemService.js +16 -1
  423. package/packages/happy2-server/dist/systemService.js.map +1 -1
  424. package/packages/happy2-server/dist/systemService.test.js +15 -1
  425. package/packages/happy2-server/dist/systemService.test.js.map +1 -1
  426. package/packages/happy2-server/dist/web/assets/index-BaPUPGPe.css +2 -0
  427. package/packages/happy2-server/dist/web/assets/index-BnhFxR3U.js +39 -0
  428. package/packages/happy2-server/dist/web/index.html +2 -2
  429. package/packages/happy2-server/drizzle/0022_plugin_container_runtime_tools.sql +16 -0
  430. package/packages/happy2-server/drizzle/0023_roles_and_permissions.sql +82 -0
  431. package/packages/happy2-server/drizzle/0024_session_bound_dev_tokens.sql +11 -0
  432. package/packages/happy2-server/drizzle/0025_plugin_skills.sql +8 -0
  433. package/packages/happy2-server/drizzle/0026_agent_turn_traces.sql +35 -0
  434. package/packages/happy2-server/drizzle/0027_chat_agent_effort.sql +9 -0
  435. package/packages/happy2-server/drizzle/meta/_journal.json +42 -0
  436. package/packages/happy2-server/happy2.example.toml +14 -0
  437. package/packages/happy2-server/plugins/README.md +3 -1
  438. package/packages/happy2-server/plugins/chat-management/container/Dockerfile +6 -0
  439. package/packages/happy2-server/plugins/chat-management/plugin.json +17 -0
  440. package/packages/happy2-server/plugins/chat-management/plugin.png +0 -0
  441. package/packages/happy2-server/plugins/chat-management/server.mjs +113 -0
  442. package/packages/happy2-server/dist/web/assets/index-9SGCQLg7.js +0 -46
  443. package/packages/happy2-server/dist/web/assets/index-DWXBQDJB.css +0 -2
@@ -1,12 +1,13 @@
1
- import { createHash } from "node:crypto";
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
2
  import { createId } from "@paralleldrive/cuid2";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
- import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js";
7
6
  import { realtimeTopics } from "../realtime/index.js";
7
+ import { chatUpdateMetadata } from "../chat/chatUpdateMetadata.js";
8
8
  import { pluginInstall } from "./pluginInstall.js";
9
9
  import { pluginFindBySource } from "./pluginFindBySource.js";
10
+ import { pluginGetSource } from "./pluginGetSource.js";
10
11
  import { pluginGetImage } from "./pluginGetImage.js";
11
12
  import { pluginAuthorizeManagement } from "./pluginAuthorizeManagement.js";
12
13
  import { pluginInstallationGetRuntimeConfiguration } from "./pluginInstallationGetRuntimeConfiguration.js";
@@ -14,12 +15,25 @@ import { pluginInstallationListIds } from "./pluginInstallationListIds.js";
14
15
  import { pluginInstallationListReadyMcpIds } from "./pluginInstallationListReadyMcpIds.js";
15
16
  import { pluginInstallationUpdateStatus } from "./pluginInstallationUpdateStatus.js";
16
17
  import { pluginRemoveMissingBuiltins } from "./pluginRemoveMissingBuiltins.js";
18
+ import { pluginMcpToolsReplace } from "./pluginMcpToolsReplace.js";
19
+ import { pluginMcpToolsListReady } from "./pluginMcpToolsListReady.js";
20
+ import { pluginSkillsListReady } from "./pluginSkillsListReady.js";
21
+ import { pluginSkillsListInstalled } from "./pluginSkillsListInstalled.js";
22
+ import { pluginContainerInstanceAuthorize } from "./pluginContainerInstanceAuthorize.js";
23
+ import { pluginContainerInstanceInvalidate } from "./pluginContainerInstanceInvalidate.js";
24
+ import { pluginUninstall } from "./pluginUninstall.js";
25
+ import { pluginArchiveExtract } from "./archive.js";
26
+ import { pluginPackageLoadSource } from "./catalog.js";
17
27
  import { RemotePluginMcpTransport } from "./utils/remoteMcpTransport.js";
18
- import { PluginError, } from "./types.js";
28
+ import { downloadedPluginSource, remotePluginSource, remotePluginSourceFromInstalled, uploadedPluginSource, } from "./source.js";
29
+ import { PluginError, MAX_PLUGIN_MCP_TOOLS, } from "./types.js";
19
30
  const HEALTH_TIMEOUT_MS = 15_000;
20
- const FUNCTION_DISCOVERY_TIMEOUT_MS = 15_000;
31
+ const COMMAND_STARTUP_GRACE_MS = 250;
21
32
  const FUNCTION_EXECUTION_TIMEOUT_MS = 30_000;
22
33
  const MAX_RIG_PLUGIN_FUNCTIONS = 128;
34
+ const MAX_RIG_PLUGIN_SKILLS = 128;
35
+ const PREPARATION_TTL_MS = 15 * 60_000;
36
+ const PLUGIN_CHAT_META_KEY = "happy2/chat";
23
37
  /** Coordinates durable plugin installs with asynchronous container preparation, MCP health probes, restart recovery, and local connection creation. */
24
38
  export class PluginService {
25
39
  executor;
@@ -28,24 +42,32 @@ export class PluginService {
28
42
  packages;
29
43
  secrets;
30
44
  runtime;
45
+ tokens;
31
46
  urlPolicy;
32
47
  remoteTransport;
48
+ hostApiUrl;
49
+ archiveDownloader;
33
50
  onError;
34
51
  activations = new Map();
35
- localContainers = new Set();
52
+ commandHandles = new Map();
53
+ preparations = new Map();
36
54
  closed = false;
37
- constructor(executor, pubsub, catalog, packages, secrets, runtime, urlPolicy, remoteTransport, onError) {
55
+ constructor(executor, pubsub, catalog, packages, secrets, runtime, tokens, urlPolicy, remoteTransport, hostApiUrl, archiveDownloader, onError) {
38
56
  this.executor = executor;
39
57
  this.pubsub = pubsub;
40
58
  this.catalog = catalog;
41
59
  this.packages = packages;
42
60
  this.secrets = secrets;
43
61
  this.runtime = runtime;
62
+ this.tokens = tokens;
44
63
  this.urlPolicy = urlPolicy;
45
64
  this.remoteTransport = remoteTransport;
65
+ this.hostApiUrl = hostApiUrl;
66
+ this.archiveDownloader = archiveDownloader;
46
67
  this.onError = onError;
47
68
  }
48
69
  async start() {
70
+ await this.packages.cleanupTemporary();
49
71
  const removed = await pluginRemoveMissingBuiltins(this.executor, this.catalog.list().map(({ source }) => source.reference));
50
72
  await Promise.all([
51
73
  ...removed.plugins.map(({ pluginId }) => this.packages.remove(pluginId).catch(this.onError)),
@@ -85,11 +107,141 @@ export class PluginService {
85
107
  }
86
108
  if (candidateId && !result.pluginCreated)
87
109
  await this.packages.remove(candidateId);
110
+ await this.packages.workspaceDirectory(result.pluginId, installationId);
88
111
  await this.publish(result.hint).catch(this.onError);
89
112
  if (result.installation.status === "preparing")
90
113
  this.activate(installationId);
91
114
  return result.installation;
92
115
  }
116
+ async prepareUpload(actorUserId, archive, onProgress) {
117
+ await pluginAuthorizeManagement(this.executor, actorUserId);
118
+ onProgress("verifying", "Inspecting uploaded ZIP package.");
119
+ const prepared = await this.prepareArchive(actorUserId, archive, "zip", undefined, onProgress);
120
+ return { selectionRequired: false, candidates: prepared };
121
+ }
122
+ async prepareRemote(actorUserId, input, onProgress, signal) {
123
+ await pluginAuthorizeManagement(this.executor, actorUserId);
124
+ const remote = remotePluginSource(input.kind, input.url);
125
+ onProgress("downloading", "Downloading plugin ZIP from its remote source.");
126
+ const downloaded = await this.archiveDownloader.download(remote.archiveUrl, {
127
+ signal,
128
+ onProgress: (bytes) => onProgress("downloading", "Downloading plugin ZIP.", bytes),
129
+ });
130
+ onProgress("verifying", "Verifying archive structure and plugin metadata.");
131
+ const candidates = await this.prepareArchive(actorUserId, downloaded.body, input.kind === "github" ? "github" : "zip", remote, onProgress);
132
+ return { selectionRequired: candidates.length > 1, candidates };
133
+ }
134
+ async installPrepared(input) {
135
+ await pluginAuthorizeManagement(this.executor, input.actorUserId);
136
+ const prepared = await this.preparationTake(input.actorUserId, input.preparedToken);
137
+ try {
138
+ const existing = await pluginFindBySource(this.executor, prepared.plugin.source.kind, prepared.plugin.source.reference);
139
+ if (existing && existing.packageDigest !== prepared.plugin.packageDigest)
140
+ throw new PluginError("conflict", "This remote plugin has changed since its installed snapshot; update it before adding another installation");
141
+ const installationId = createId();
142
+ const candidateId = existing ? undefined : createId();
143
+ const candidate = candidateId
144
+ ? {
145
+ pluginId: candidateId,
146
+ ...(await this.packages.install(prepared.plugin, candidateId)),
147
+ }
148
+ : undefined;
149
+ let result;
150
+ try {
151
+ result = await pluginInstall(this.executor, this.secrets, {
152
+ actorUserId: input.actorUserId,
153
+ installationId,
154
+ plugin: prepared.plugin,
155
+ candidate,
156
+ variables: input.variables,
157
+ containerImageId: input.containerImageId,
158
+ });
159
+ }
160
+ catch (error) {
161
+ if (candidateId)
162
+ await this.packages.remove(candidateId);
163
+ throw error;
164
+ }
165
+ if (candidateId && !result.pluginCreated)
166
+ await this.packages.remove(candidateId);
167
+ await this.packages.workspaceDirectory(result.pluginId, installationId);
168
+ await this.publish(result.hint).catch(this.onError);
169
+ if (result.installation.status === "preparing")
170
+ this.activate(installationId);
171
+ return result.installation;
172
+ }
173
+ finally {
174
+ await this.packages.removePreparation(prepared.id).catch(this.onError);
175
+ }
176
+ }
177
+ async uninstall(actorUserId, pluginId) {
178
+ const result = await pluginUninstall(this.executor, actorUserId, pluginId);
179
+ for (const installationId of result.installationIds) {
180
+ const activation = this.activations.get(installationId);
181
+ activation?.controller.abort();
182
+ this.closeCommand(installationId);
183
+ }
184
+ await Promise.allSettled(result.installationIds.flatMap((installationId) => {
185
+ const activation = this.activations.get(installationId);
186
+ return activation ? [activation.promise] : [];
187
+ }));
188
+ await this.publish(result.hint).catch(this.onError);
189
+ await Promise.allSettled([
190
+ ...result.containerNames.map((containerName) => {
191
+ return this.runtime.removeLocal(containerName);
192
+ }),
193
+ this.packages.remove(pluginId),
194
+ ]).then((settled) => {
195
+ for (const item of settled)
196
+ if (item.status === "rejected")
197
+ this.onError(item.reason);
198
+ });
199
+ return { installationIds: result.installationIds, pluginId };
200
+ }
201
+ async checkForUpdate(actorUserId, pluginId, onProgress, signal) {
202
+ const installed = await pluginGetSource(this.executor, actorUserId, pluginId);
203
+ let remotePackage;
204
+ if (installed.source.kind === "builtin") {
205
+ const catalogPackage = this.catalog.get(installed.source.reference);
206
+ if (!catalogPackage)
207
+ throw new PluginError("not_found", "Built-in plugin is no longer in the catalog");
208
+ remotePackage = catalogPackage;
209
+ }
210
+ else {
211
+ const remote = remotePluginSourceFromInstalled(installed.source);
212
+ onProgress("downloading", "Downloading the current remote plugin package.");
213
+ const downloaded = await this.archiveDownloader.download(remote.archiveUrl, {
214
+ signal,
215
+ onProgress: (bytes) => onProgress("downloading", "Downloading remote package.", bytes),
216
+ });
217
+ const directory = await this.packages.createDownloadDirectory();
218
+ try {
219
+ onProgress("verifying", "Verifying the current remote plugin package.");
220
+ const candidates = await pluginArchiveExtract(downloaded.body, directory, remote.kind === "github" ? "github" : "zip");
221
+ const candidate = remote.packagePath === undefined
222
+ ? candidates[0]
223
+ : candidates.find(({ packagePath }) => packagePath === remote.packagePath);
224
+ if (!candidate)
225
+ throw new PluginError("invalid_package", "The installed plugin path no longer exists remotely");
226
+ remotePackage = await pluginPackageLoadSource(candidate.directory, installed.source);
227
+ }
228
+ finally {
229
+ await this.packages.removeDownloadDirectory(directory);
230
+ }
231
+ }
232
+ if (remotePackage.manifest.shortName !== installed.shortName)
233
+ throw new PluginError("invalid_package", "Remote plugin shortName changed");
234
+ return {
235
+ pluginId,
236
+ checkedAt: new Date().toISOString(),
237
+ updateAvailable: remotePackage.packageDigest !== installed.packageDigest,
238
+ installed: { version: installed.sourceVersion, packageDigest: installed.packageDigest },
239
+ remote: {
240
+ version: remotePackage.manifest.version,
241
+ packageDigest: remotePackage.packageDigest,
242
+ },
243
+ };
244
+ }
93
245
  async image(actorUserId, pluginId) {
94
246
  const image = await pluginGetImage(this.executor, actorUserId, pluginId);
95
247
  const body = await this.packages.readImage(image.pluginId, image.packageDirectory, image.storageKey, image.shortName, image.packageDigest);
@@ -104,71 +256,66 @@ export class PluginService {
104
256
  }
105
257
  async openLocal(installationId) {
106
258
  const configuration = await pluginInstallationGetRuntimeConfiguration(this.executor, this.secrets, installationId);
107
- if (configuration.type !== "stdio")
259
+ if (configuration.type !== "local" || !configuration.mcp)
108
260
  throw new PluginError("not_found", "Plugin does not expose a local stdio MCP server");
261
+ const environment = this.runtimeEnvironment(configuration, await this.pluginRuntimeToken(configuration));
109
262
  return this.runtime.openLocal({
110
263
  containerName: configuration.containerName,
111
- command: configuration.command,
112
- args: configuration.args,
113
- environment: configuration.environment,
264
+ command: configuration.mcp.command,
265
+ args: configuration.mcp.args,
266
+ environment,
114
267
  });
115
268
  }
116
269
  async listFunctions(signal) {
117
- return withOperationTimeout(FUNCTION_DISCOVERY_TIMEOUT_MS, "Plugin MCP function discovery", signal, (operationSignal) => this.listFunctionsWithSignal(operationSignal));
270
+ signal?.throwIfAborted();
271
+ const tools = await pluginMcpToolsListReady(this.executor);
272
+ if (tools.length > MAX_RIG_PLUGIN_FUNCTIONS)
273
+ throw new PluginFunctionCatalogError(`Installed plugins expose ${tools.length} MCP tools, exceeding Rig's ${MAX_RIG_PLUGIN_FUNCTIONS}-function limit`);
274
+ return tools.map((tool) => ({
275
+ description: tool.description ?? `Runs ${tool.name} from the ${tool.shortName} plugin.`,
276
+ label: `${tool.shortName}: ${tool.title ?? tool.name}`,
277
+ name: pluginFunctionName(tool.installationId, tool.name),
278
+ parameters: tool.inputSchema,
279
+ }));
118
280
  }
119
- async listFunctionsWithSignal(signal) {
120
- const installationIds = await pluginInstallationListReadyMcpIds(this.executor);
121
- const functions = [];
122
- for (const installationId of installationIds) {
123
- try {
124
- const discovered = await this.withClient(installationId, signal, async (client, configuration) => {
125
- const definitions = [];
126
- const seenCursors = new Set();
127
- const remaining = MAX_RIG_PLUGIN_FUNCTIONS - functions.length;
128
- let pages = 0;
129
- let cursor;
130
- do {
131
- pages += 1;
132
- if (pages > MAX_RIG_PLUGIN_FUNCTIONS)
133
- throw new PluginFunctionCatalogError("Plugin MCP tool pagination exceeded the page limit");
134
- const page = await client.listTools(cursor === undefined ? undefined : { cursor });
135
- for (const tool of page.tools) {
136
- if (definitions.length >= remaining)
137
- throw new PluginFunctionCatalogError(`Installed plugins expose more than Rig's ${MAX_RIG_PLUGIN_FUNCTIONS}-function limit`);
138
- definitions.push({
139
- description: tool.description ??
140
- `Runs ${tool.name} from the ${configuration.shortName} plugin.`,
141
- label: `${configuration.shortName}: ${tool.title ?? tool.name}`,
142
- name: pluginFunctionName(installationId, tool.name),
143
- parameters: tool.inputSchema,
144
- });
145
- }
146
- if (page.nextCursor && seenCursors.has(page.nextCursor))
147
- throw new Error("Plugin MCP tool pagination repeated a cursor");
148
- if (page.nextCursor)
149
- seenCursors.add(page.nextCursor);
150
- cursor = page.nextCursor;
151
- } while (cursor !== undefined);
152
- return definitions;
153
- });
154
- if (discovered)
155
- functions.push(...discovered);
156
- }
157
- catch (error) {
158
- if (signal.aborted)
159
- throw error;
160
- if (error instanceof PluginFunctionCatalogError)
161
- throw error;
162
- this.onError(error);
163
- }
281
+ async listSkills(signal) {
282
+ const skills = this.skillSources(await pluginSkillsListReady(this.executor), signal);
283
+ if (skills.length > MAX_RIG_PLUGIN_SKILLS)
284
+ throw new PluginSkillCatalogError(`Installed plugins expose ${skills.length} skills, exceeding Rig's ${MAX_RIG_PLUGIN_SKILLS}-skill limit`);
285
+ return skills.map(({ name, description }) => ({
286
+ name,
287
+ description,
288
+ location: "durable",
289
+ }));
290
+ }
291
+ async readSkill(skill, signal) {
292
+ try {
293
+ return await withOperationTimeout(FUNCTION_EXECUTION_TIMEOUT_MS, "Plugin skill read", signal, async (operationSignal) => {
294
+ const sources = this.skillSources(await pluginSkillsListInstalled(this.executor), operationSignal);
295
+ const source = sources.find(({ name }) => name === skill.name);
296
+ if (!source || source.description !== skill.description)
297
+ throw new Error("The plugin no longer provides this durable skill");
298
+ const loaded = await this.packages.readSkill(source.pluginId, source.packageDirectory, source.shortName, source.packageDigest, source.name, source.directory, operationSignal);
299
+ if (loaded.description !== skill.description)
300
+ throw new Error("Installed plugin skill metadata no longer matches");
301
+ return { status: "completed", output: loaded.source };
302
+ });
303
+ }
304
+ catch (error) {
305
+ if (signal?.aborted)
306
+ throw error;
307
+ return {
308
+ status: "failed",
309
+ error: {
310
+ code: "plugin_skill_failed",
311
+ message: errorMessage(error),
312
+ },
313
+ };
164
314
  }
165
- if (functions.length > MAX_RIG_PLUGIN_FUNCTIONS)
166
- throw new Error(`Installed plugins expose ${functions.length} MCP tools, exceeding Rig's ${MAX_RIG_PLUGIN_FUNCTIONS}-function limit`);
167
- return functions;
168
315
  }
169
- async callFunction(functionName, args, signal) {
316
+ async callFunction(functionName, args, context, signal) {
170
317
  try {
171
- return await withOperationTimeout(FUNCTION_EXECUTION_TIMEOUT_MS, "Plugin MCP function execution", signal, (operationSignal) => this.callFunctionWithSignal(functionName, args, operationSignal));
318
+ return await withOperationTimeout(FUNCTION_EXECUTION_TIMEOUT_MS, "Plugin MCP function execution", signal, (operationSignal) => this.callFunctionWithSignal(functionName, args, context, operationSignal));
172
319
  }
173
320
  catch (error) {
174
321
  if (signal?.aborted)
@@ -182,7 +329,7 @@ export class PluginService {
182
329
  };
183
330
  }
184
331
  }
185
- async callFunctionWithSignal(functionName, args, signal) {
332
+ async callFunctionWithSignal(functionName, args, context, signal) {
186
333
  const installationId = pluginFunctionInstallationId(functionName);
187
334
  if (!installationId)
188
335
  throw new Error(`Unknown plugin function ${JSON.stringify(functionName)}`);
@@ -193,28 +340,24 @@ export class PluginService {
193
340
  const ready = await pluginInstallationListReadyMcpIds(this.executor);
194
341
  if (!ready.includes(installationId))
195
342
  throw new Error("The plugin installation is not ready");
196
- const result = await this.withClient(installationId, signal, async (client, configuration) => {
197
- const seenCursors = new Set();
198
- let pages = 0;
199
- let cursor;
200
- let toolName;
201
- do {
202
- pages += 1;
203
- if (pages > MAX_RIG_PLUGIN_FUNCTIONS)
204
- throw new Error("Plugin MCP tool pagination exceeded the page limit");
205
- const page = await client.listTools(cursor === undefined ? undefined : { cursor });
206
- toolName = page.tools.find((tool) => pluginFunctionName(installationId, tool.name) === functionName)?.name;
207
- if (page.nextCursor && seenCursors.has(page.nextCursor))
208
- throw new Error("Plugin MCP tool pagination repeated a cursor");
209
- if (page.nextCursor)
210
- seenCursors.add(page.nextCursor);
211
- cursor = page.nextCursor;
212
- } while (!toolName && cursor !== undefined);
213
- if (!toolName)
214
- throw new Error(`The ${configuration.shortName} plugin no longer exposes this function`);
343
+ const cached = (await pluginMcpToolsListReady(this.executor)).find((tool) => tool.installationId === installationId &&
344
+ pluginFunctionName(installationId, tool.name) === functionName);
345
+ if (!cached)
346
+ throw new Error("The plugin no longer exposes this cached function");
347
+ const chatToken = await this.tokens.issuePluginChatToken({
348
+ installationId,
349
+ chatId: context.chatId,
350
+ });
351
+ const result = await this.withClient(installationId, signal, async (client) => {
215
352
  const result = await client.callTool({
216
- name: toolName,
353
+ name: cached.name,
217
354
  arguments: jsonArguments(args),
355
+ _meta: {
356
+ [PLUGIN_CHAT_META_KEY]: {
357
+ id: context.chatId,
358
+ token: chatToken,
359
+ },
360
+ },
218
361
  });
219
362
  if (result.isError)
220
363
  return {
@@ -231,13 +374,144 @@ export class PluginService {
231
374
  throw new Error("The plugin does not expose MCP tools");
232
375
  return result;
233
376
  }
377
+ skillSources(records, signal) {
378
+ const names = new Map();
379
+ for (const record of records) {
380
+ signal?.throwIfAborted();
381
+ const existing = names.get(record.name);
382
+ if (existing)
383
+ throw new PluginSkillCatalogError(`Installed plugins ${existing} and ${record.shortName} both provide skill ${record.name}`);
384
+ names.set(record.name, record.shortName);
385
+ }
386
+ return [...records];
387
+ }
388
+ async authorizeHost(token, permission) {
389
+ let claims;
390
+ try {
391
+ claims = await this.tokens.verifyPluginRuntimeToken(token);
392
+ }
393
+ catch {
394
+ throw new PluginError("forbidden", "Plugin runtime token is invalid");
395
+ }
396
+ if (!claims.permissions.includes(permission))
397
+ throw new PluginError("forbidden", `Plugin runtime lacks ${permission} permission`);
398
+ const authorized = await pluginContainerInstanceAuthorize(this.executor, claims.installationId, claims.containerInstanceId);
399
+ if (!authorized)
400
+ throw new PluginError("forbidden", "Plugin container incarnation is not authorized");
401
+ if (!this.runtime.isLocalRunning ||
402
+ !(await this.runtime.isLocalRunning(authorized.containerName, claims.installationId, claims.containerInstanceId))) {
403
+ const hint = await pluginContainerInstanceInvalidate(this.executor, {
404
+ installationId: claims.installationId,
405
+ containerInstanceId: claims.containerInstanceId,
406
+ detail: "Plugin container is missing or stopped.",
407
+ });
408
+ if (hint)
409
+ await this.publish(hint).catch(this.onError);
410
+ throw new PluginError("forbidden", "Plugin container incarnation is not running");
411
+ }
412
+ return claims.installationId;
413
+ }
414
+ async chatUpdate(runtimeToken, chatToken, input) {
415
+ const installationId = await this.authorizeHost(runtimeToken, "chats:update");
416
+ let claims;
417
+ try {
418
+ claims = await this.tokens.verifyPluginChatToken(chatToken);
419
+ }
420
+ catch {
421
+ throw new PluginError("forbidden", "Plugin chat token is invalid");
422
+ }
423
+ if (claims.installationId !== installationId)
424
+ throw new PluginError("forbidden", "Plugin chat token belongs to another installation");
425
+ const result = await chatUpdateMetadata(this.executor, {
426
+ chatId: claims.chatId,
427
+ ...input,
428
+ });
429
+ const event = { type: "sync", ...result.hint };
430
+ await Promise.allSettled([
431
+ this.pubsub.publish(realtimeTopics.chat(claims.chatId), event),
432
+ this.pubsub.publish(realtimeTopics.server, event),
433
+ ]).then((publications) => {
434
+ for (const publication of publications)
435
+ if (publication.status === "rejected")
436
+ this.onError(publication.reason);
437
+ });
438
+ return { chat: result.chat, sync: result.hint };
439
+ }
234
440
  async close() {
235
441
  this.closed = true;
236
442
  for (const { controller } of this.activations.values())
237
443
  controller.abort();
238
444
  await Promise.allSettled([...this.activations.values()].map(({ promise }) => promise));
239
- await Promise.allSettled([...this.localContainers].map((containerName) => this.runtime.removeLocal(containerName)));
240
- this.localContainers.clear();
445
+ for (const handle of this.commandHandles.values())
446
+ handle.close();
447
+ this.commandHandles.clear();
448
+ await Promise.allSettled([...this.preparations.values()].map(({ id }) => this.packages.removePreparation(id)));
449
+ this.preparations.clear();
450
+ }
451
+ async prepareArchive(actorUserId, archive, kind, remote, onProgress) {
452
+ this.preparationsExpire();
453
+ const directory = await this.packages.createDownloadDirectory();
454
+ try {
455
+ const candidates = await pluginArchiveExtract(archive, directory, kind);
456
+ const prepared = [];
457
+ for (const candidate of candidates) {
458
+ const provisionalSource = remote
459
+ ? downloadedPluginSource(remote, candidate.packagePath)
460
+ : { kind: "upload", reference: "upload:pending" };
461
+ let plugin = await pluginPackageLoadSource(candidate.directory, provisionalSource);
462
+ if (/^plugins\/[^/]+$/.test(candidate.packagePath)) {
463
+ const folder = candidate.packagePath.split("/").at(-1);
464
+ if (plugin.manifest.shortName !== folder)
465
+ throw new PluginError("invalid_package", `${candidate.packagePath}: shortName must match its plugin folder`);
466
+ }
467
+ if (!remote)
468
+ plugin = { ...plugin, source: uploadedPluginSource(plugin.packageDigest) };
469
+ const id = createId();
470
+ plugin = await this.packages.prepare(plugin, id);
471
+ const secret = randomBytes(32).toString("base64url");
472
+ const token = `${id}.${secret}`;
473
+ const expiresAt = Date.now() + PREPARATION_TTL_MS;
474
+ this.preparations.set(id, {
475
+ actorUserId,
476
+ expiresAt,
477
+ id,
478
+ plugin,
479
+ secretHash: createHash("sha256").update(secret).digest(),
480
+ });
481
+ prepared.push(preparedSummary(plugin, token, expiresAt));
482
+ }
483
+ onProgress("prepared", "Plugin package is verified and ready to install.");
484
+ return prepared;
485
+ }
486
+ catch (error) {
487
+ if (error instanceof PluginError)
488
+ throw error;
489
+ throw new PluginError("invalid_package", errorMessage(error));
490
+ }
491
+ finally {
492
+ await this.packages.removeDownloadDirectory(directory);
493
+ }
494
+ }
495
+ async preparationTake(actorUserId, token) {
496
+ this.preparationsExpire();
497
+ const match = /^([a-z0-9]+)\.([A-Za-z0-9_-]{43})$/.exec(token);
498
+ const prepared = match ? this.preparations.get(match[1]) : undefined;
499
+ const suppliedHash = match ? createHash("sha256").update(match[2]).digest() : undefined;
500
+ if (!prepared ||
501
+ !suppliedHash ||
502
+ prepared.actorUserId !== actorUserId ||
503
+ !timingSafeEqual(prepared.secretHash, suppliedHash))
504
+ throw new PluginError("not_found", "Prepared plugin token was not found or expired");
505
+ this.preparations.delete(prepared.id);
506
+ return prepared;
507
+ }
508
+ preparationsExpire() {
509
+ const now = Date.now();
510
+ for (const [id, prepared] of this.preparations)
511
+ if (prepared.expiresAt <= now) {
512
+ this.preparations.delete(id);
513
+ void this.packages.removePreparation(id).catch(this.onError);
514
+ }
241
515
  }
242
516
  activate(installationId) {
243
517
  if (this.closed || this.activations.has(installationId))
@@ -253,12 +527,17 @@ export class PluginService {
253
527
  const configuration = await pluginInstallationGetRuntimeConfiguration(this.executor, this.secrets, installationId);
254
528
  if (configuration.type === "skills_only")
255
529
  return undefined;
256
- const transport = configuration.type === "stdio"
530
+ if (configuration.type === "local" && !configuration.mcp)
531
+ return undefined;
532
+ const localToken = configuration.type === "local"
533
+ ? await this.pluginRuntimeToken(configuration)
534
+ : undefined;
535
+ const transport = configuration.type === "local"
257
536
  ? await this.runtime.openLocal({
258
537
  containerName: configuration.containerName,
259
- command: configuration.command,
260
- args: configuration.args,
261
- environment: configuration.environment,
538
+ command: configuration.mcp.command,
539
+ args: configuration.mcp.args,
540
+ environment: this.runtimeEnvironment(configuration, localToken),
262
541
  }, signal)
263
542
  : new RemotePluginMcpTransport({
264
543
  headers: configuration.headers,
@@ -280,6 +559,10 @@ export class PluginService {
280
559
  }
281
560
  async runActivation(installationId, signal) {
282
561
  let preparedContainerName;
562
+ let preparedContainerInstanceId;
563
+ let commandHandle;
564
+ let buildContextDirectory;
565
+ this.closeCommand(installationId);
283
566
  try {
284
567
  signal.throwIfAborted();
285
568
  await this.status(installationId, "preparing", "Preparing the installed plugin runtime.");
@@ -291,21 +574,28 @@ export class PluginService {
291
574
  }
292
575
  if (configuration.type === "remote") {
293
576
  await this.status(installationId, "starting", "Checking the remote MCP server.");
294
- await this.probeRemote(configuration, signal);
295
- await this.status(installationId, "ready", "Remote MCP server is healthy.");
577
+ const tools = await this.probeRemote(configuration, signal);
578
+ const hint = await pluginMcpToolsReplace(this.executor, installationId, tools);
579
+ await this.publish(hint).catch(this.onError);
580
+ await this.status(installationId, "ready", "Remote MCP server and cached tools are ready.");
296
581
  return;
297
582
  }
298
583
  const dockerfile = configuration.bundledDockerfile
299
584
  ? await readFile(join(configuration.packageDirectory, configuration.bundledDockerfile), "utf8")
300
585
  : undefined;
586
+ if (dockerfile)
587
+ buildContextDirectory = await this.packages.createBuildContext(configuration.pluginId, configuration.packageDirectory, configuration.shortName, configuration.packageDigest);
301
588
  const prepared = await this.runtime.prepareLocal({
302
589
  installationId,
303
590
  containerName: configuration.containerName,
591
+ containerInstanceId: createId(),
592
+ existingContainerInstanceId: configuration.containerInstanceId,
304
593
  imageTag: configuration.imageTag,
594
+ workspaceDirectory: await this.packages.workspaceDirectory(configuration.pluginId, installationId),
305
595
  ...(dockerfile
306
596
  ? {
307
597
  build: {
308
- contextDirectory: configuration.packageDirectory,
598
+ contextDirectory: buildContextDirectory,
309
599
  dockerfile,
310
600
  tag: configuration.imageTag,
311
601
  },
@@ -313,98 +603,165 @@ export class PluginService {
313
603
  : {}),
314
604
  }, signal);
315
605
  preparedContainerName = configuration.containerName;
316
- this.localContainers.add(configuration.containerName);
317
- await this.status(installationId, "starting", "Starting and checking the containerized MCP server.", undefined, prepared.imageTag);
318
- await this.probeLocal(configuration, signal);
319
- await this.status(installationId, "ready", "Containerized MCP server is healthy.", undefined, prepared.imageTag);
606
+ preparedContainerInstanceId = prepared.containerInstanceId;
607
+ const token = await this.tokens.issuePluginRuntimeToken({
608
+ installationId,
609
+ containerInstanceId: prepared.containerInstanceId,
610
+ permissions: configuration.permissions,
611
+ });
612
+ const environment = this.runtimeEnvironment(configuration, token);
613
+ await this.status(installationId, "starting", "Starting and checking the containerized plugin runtime.", undefined, prepared.imageTag, prepared.containerInstanceId);
614
+ if (configuration.command) {
615
+ commandHandle = prepared.reused
616
+ ? await this.runtime.monitorLocalCommand(configuration.containerName, signal)
617
+ : await this.runtime.startLocalCommand({
618
+ containerName: configuration.containerName,
619
+ command: configuration.command.command,
620
+ args: configuration.command.args,
621
+ environment,
622
+ }, signal);
623
+ this.commandHandles.set(installationId, commandHandle);
624
+ await commandSurviveStartup(commandHandle.wait, signal);
625
+ }
626
+ if (configuration.mcp) {
627
+ const tools = await this.probeLocal(configuration, environment, signal);
628
+ const hint = await pluginMcpToolsReplace(this.executor, installationId, tools);
629
+ await this.publish(hint).catch(this.onError);
630
+ }
631
+ await this.status(installationId, "ready", configuration.mcp
632
+ ? "Containerized plugin runtime and MCP tools are ready."
633
+ : "Containerized plugin command is running.", undefined, prepared.imageTag, prepared.containerInstanceId);
634
+ if (commandHandle)
635
+ this.monitorCommand(installationId, configuration.containerName, commandHandle);
320
636
  }
321
637
  catch (error) {
322
- if (preparedContainerName) {
323
- this.localContainers.delete(preparedContainerName);
324
- await this.runtime.removeLocal(preparedContainerName).catch(this.onError);
638
+ if (commandHandle) {
639
+ if (this.commandHandles.get(installationId) === commandHandle)
640
+ this.commandHandles.delete(installationId);
641
+ commandHandle.close();
325
642
  }
326
643
  if (signal.aborted && this.closed)
327
644
  return;
645
+ if (preparedContainerName)
646
+ await this.runtime.removeLocal(preparedContainerName).catch(this.onError);
328
647
  const broken = error instanceof PluginError && error.code === "broken_configuration";
329
648
  await this.status(installationId, broken ? "broken_configuration" : "failed", broken
330
649
  ? "Plugin configuration must be corrected before it can start."
331
- : "Plugin runtime failed to prepare or start.", errorMessage(error)).catch(this.onError);
650
+ : "Plugin runtime failed to prepare or start.", errorMessage(error), undefined, preparedContainerInstanceId ? null : undefined).catch(this.onError);
651
+ }
652
+ finally {
653
+ if (buildContextDirectory)
654
+ await this.packages.removeBuildContext(buildContextDirectory).catch(this.onError);
332
655
  }
333
656
  }
334
- async probeLocal(configuration, signal) {
657
+ async probeLocal(configuration, environment, signal) {
658
+ if (!configuration.mcp)
659
+ return [];
335
660
  const transport = await this.runtime.openLocal({
336
661
  containerName: configuration.containerName,
337
- command: configuration.command,
338
- args: configuration.args,
339
- environment: configuration.environment,
662
+ command: configuration.mcp.command,
663
+ args: configuration.mcp.args,
664
+ environment,
340
665
  }, signal);
666
+ return this.discoverTools(transport, signal);
667
+ }
668
+ async discoverTools(transport, signal) {
341
669
  const client = new Client({ name: "happy2-plugin-health", version: "1.0.0" });
342
670
  try {
343
671
  await withTimeout(client.connect(transport), HEALTH_TIMEOUT_MS, "MCP initialization", signal);
344
672
  await withTimeout(client.ping(), HEALTH_TIMEOUT_MS, "MCP ping", signal);
673
+ const tools = [];
674
+ const cursors = new Set();
675
+ let cursor;
676
+ do {
677
+ const listed = await withTimeout(client.listTools(cursor ? { cursor } : undefined), HEALTH_TIMEOUT_MS, "MCP tool discovery", signal);
678
+ tools.push(...listed.tools.map((tool) => ({
679
+ name: tool.name,
680
+ ...(tool.title ? { title: tool.title } : {}),
681
+ ...(tool.description ? { description: tool.description } : {}),
682
+ inputSchema: tool.inputSchema,
683
+ ...(tool.outputSchema ? { outputSchema: tool.outputSchema } : {}),
684
+ ...(tool.annotations ? { annotations: tool.annotations } : {}),
685
+ })));
686
+ if (tools.length > MAX_PLUGIN_MCP_TOOLS)
687
+ throw new PluginError("broken_configuration", "Plugin MCP exposes too many tools");
688
+ cursor = listed.nextCursor;
689
+ if (cursor && cursors.has(cursor))
690
+ throw new PluginError("broken_configuration", "Plugin MCP tool pagination repeated a cursor");
691
+ if (cursor)
692
+ cursors.add(cursor);
693
+ if (cursors.size > MAX_PLUGIN_MCP_TOOLS)
694
+ throw new PluginError("broken_configuration", "Plugin MCP tool pagination has too many pages");
695
+ } while (cursor);
696
+ return tools;
345
697
  }
346
698
  finally {
347
699
  await client.close().catch(() => transport.close());
348
700
  }
349
701
  }
350
702
  async probeRemote(configuration, signal) {
351
- const destination = await withTimeout(this.urlPolicy.resolveForDelivery(configuration.url), HEALTH_TIMEOUT_MS, "Remote MCP DNS resolution", signal);
352
- const id = createId();
353
- const response = await withTimeout(this.remoteTransport.deliver({
354
- deliveryId: `plugin-health:${configuration.installationId}`,
355
- eventId: id,
356
- eventType: "plugin.mcp.initialize",
357
- url: destination.url,
358
- allowedAddresses: destination.addresses,
359
- headers: {
360
- ...configuration.headers,
361
- accept: "application/json, text/event-stream",
362
- "content-type": "application/json",
363
- "mcp-protocol-version": LATEST_PROTOCOL_VERSION,
364
- },
365
- body: JSON.stringify({
366
- jsonrpc: "2.0",
367
- id,
368
- method: "initialize",
369
- params: {
370
- protocolVersion: LATEST_PROTOCOL_VERSION,
371
- capabilities: {},
372
- clientInfo: { name: "happy2-plugin-health", version: "1.0.0" },
373
- },
374
- }),
375
- }), HEALTH_TIMEOUT_MS, "Remote MCP initialization", signal);
376
- if (response.statusCode < 200 || response.statusCode >= 300)
377
- throw new Error(`Remote MCP initialization returned HTTP ${response.statusCode}`);
378
- const payload = remoteJson(response.body ?? "");
379
- if (!payload ||
380
- payload.jsonrpc !== "2.0" ||
381
- payload.id !== id ||
382
- (!payload.result && !payload.error))
383
- throw new Error("Remote MCP initialization returned an invalid JSON-RPC response");
384
- if (payload.error) {
385
- const error = payload.error && typeof payload.error === "object" && !Array.isArray(payload.error)
386
- ? payload.error
387
- : undefined;
388
- const code = typeof error?.code === "number" ? ` with code ${error.code}` : "";
389
- throw new Error(`Remote MCP initialization returned a JSON-RPC error${code}`);
390
- }
703
+ return this.discoverTools(new RemotePluginMcpTransport({
704
+ headers: configuration.headers,
705
+ installationId: configuration.installationId,
706
+ remoteTransport: this.remoteTransport,
707
+ signal,
708
+ url: configuration.url,
709
+ urlPolicy: this.urlPolicy,
710
+ }), signal);
391
711
  }
392
- async status(installationId, status, detail, error, runtimeImageTag) {
712
+ async status(installationId, status, detail, error, runtimeImageTag, containerInstanceId) {
393
713
  const hint = await pluginInstallationUpdateStatus(this.executor, {
394
714
  installationId,
395
715
  status,
396
716
  detail,
397
717
  error,
398
718
  runtimeImageTag,
719
+ containerInstanceId,
399
720
  });
400
721
  await this.publish(hint).catch(this.onError);
401
722
  }
402
723
  publish(hint) {
403
724
  return this.pubsub.publish(realtimeTopics.server, { type: "sync", ...hint });
404
725
  }
726
+ closeCommand(installationId) {
727
+ const handle = this.commandHandles.get(installationId);
728
+ if (!handle)
729
+ return;
730
+ this.commandHandles.delete(installationId);
731
+ handle.close();
732
+ }
733
+ monitorCommand(installationId, containerName, handle) {
734
+ void handle.wait
735
+ .then(async (result) => {
736
+ if (this.closed || this.commandHandles.get(installationId) !== handle)
737
+ return;
738
+ this.commandHandles.delete(installationId);
739
+ await this.runtime.removeLocal(containerName).catch(this.onError);
740
+ await this.status(installationId, "failed", "Plugin runtime command exited.", commandExitMessage(result), undefined, null);
741
+ })
742
+ .catch(this.onError);
743
+ }
744
+ runtimeEnvironment(configuration, token) {
745
+ return {
746
+ ...configuration.environment,
747
+ HAPPY2_PLUGIN_API_URL: this.hostApiUrl,
748
+ HAPPY2_PLUGIN_API_TOKEN: token,
749
+ };
750
+ }
751
+ pluginRuntimeToken(configuration) {
752
+ if (!configuration.containerInstanceId)
753
+ throw new PluginError("not_ready", "Plugin container incarnation is unavailable");
754
+ return this.tokens.issuePluginRuntimeToken({
755
+ installationId: configuration.installationId,
756
+ containerInstanceId: configuration.containerInstanceId,
757
+ permissions: configuration.permissions,
758
+ });
759
+ }
405
760
  }
406
761
  class PluginFunctionCatalogError extends Error {
407
762
  }
763
+ class PluginSkillCatalogError extends Error {
764
+ }
408
765
  function pluginFunctionName(installationId, toolName) {
409
766
  const normalized = toolName
410
767
  .normalize("NFKD")
@@ -438,36 +795,29 @@ function mcpErrorMessage(content) {
438
795
  }
439
796
  return "The plugin MCP tool returned an error";
440
797
  }
441
- function remoteJson(body) {
442
- const direct = jsonRecord(body.trim());
443
- if (direct)
444
- return direct;
445
- let data = [];
446
- for (const line of body.split(/\r?\n/)) {
447
- if (!line) {
448
- const event = jsonRecord(data.join("\n"));
449
- if (event)
450
- return event;
451
- data = [];
452
- }
453
- else if (line.startsWith("data:")) {
454
- data.push(line.slice(5).trimStart());
455
- }
456
- }
457
- return jsonRecord(data.join("\n"));
798
+ function commandSurviveStartup(wait, signal) {
799
+ if (signal.aborted)
800
+ return Promise.reject(abortReason(signal));
801
+ return new Promise((resolve, reject) => {
802
+ let settled = false;
803
+ const finish = (action) => {
804
+ if (settled)
805
+ return;
806
+ settled = true;
807
+ clearTimeout(timer);
808
+ signal.removeEventListener("abort", aborted);
809
+ action();
810
+ };
811
+ const aborted = () => finish(() => reject(abortReason(signal)));
812
+ const timer = setTimeout(() => finish(resolve), COMMAND_STARTUP_GRACE_MS);
813
+ signal.addEventListener("abort", aborted, { once: true });
814
+ wait.then((result) => finish(() => reject(new Error(`Plugin command exited during startup: ${commandExitMessage(result)}`))), (error) => finish(() => reject(error)));
815
+ });
458
816
  }
459
- function jsonRecord(source) {
460
- if (!source)
461
- return undefined;
462
- try {
463
- const value = JSON.parse(source);
464
- return value && typeof value === "object" && !Array.isArray(value)
465
- ? value
466
- : undefined;
467
- }
468
- catch {
469
- return undefined;
470
- }
817
+ function commandExitMessage(result) {
818
+ return result.signal
819
+ ? `Plugin command exited after signal ${result.signal}`
820
+ : `Plugin command exited with code ${result.exitCode ?? "unknown"}`;
471
821
  }
472
822
  function withTimeout(promise, timeoutMs, operation, signal) {
473
823
  if (signal?.aborted)
@@ -535,4 +885,33 @@ function errorMessage(error) {
535
885
  const message = error instanceof Error ? error.message : String(error);
536
886
  return message.slice(0, 4_000);
537
887
  }
888
+ function preparedSummary(plugin, preparedToken, expiresAt) {
889
+ const mcp = plugin.manifest.mcp;
890
+ return {
891
+ preparedToken,
892
+ expiresAt: new Date(expiresAt).toISOString(),
893
+ sourceKind: plugin.source.kind,
894
+ sourceReference: plugin.source.reference,
895
+ packageDigest: plugin.packageDigest,
896
+ version: plugin.manifest.version,
897
+ displayName: plugin.manifest.displayName,
898
+ shortName: plugin.manifest.shortName,
899
+ description: plugin.manifest.description,
900
+ skills: plugin.skills.map(({ name, description }) => ({ name, description })),
901
+ variables: plugin.manifest.variables,
902
+ ...(mcp
903
+ ? {
904
+ mcp: {
905
+ type: mcp.type,
906
+ container: mcp.type === "remote"
907
+ ? "none"
908
+ : mcp.container
909
+ ? "bundled"
910
+ : "selection_required",
911
+ },
912
+ }
913
+ : {}),
914
+ image: plugin.image,
915
+ };
916
+ }
538
917
  //# sourceMappingURL=service.js.map