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.
- package/README.md +10 -0
- package/package.json +2 -2
- package/packages/happy2-server/PLUGINS.md +205 -45
- package/packages/happy2-server/README.md +19 -7
- package/packages/happy2-server/dist/daemon.d.ts +39 -0
- package/packages/happy2-server/dist/daemon.d.ts.map +1 -0
- package/packages/happy2-server/dist/daemon.js +302 -0
- package/packages/happy2-server/dist/daemon.js.map +1 -0
- package/packages/happy2-server/dist/daemon.test.d.ts +2 -0
- package/packages/happy2-server/dist/daemon.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/daemon.test.js +245 -0
- package/packages/happy2-server/dist/daemon.test.js.map +1 -0
- package/packages/happy2-server/dist/index.d.ts +3 -2
- package/packages/happy2-server/dist/index.d.ts.map +1 -1
- package/packages/happy2-server/dist/index.js +2 -1
- package/packages/happy2-server/dist/index.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatBind.d.ts +1 -0
- package/packages/happy2-server/dist/modules/agent/agentChatBind.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatBind.js +4 -0
- package/packages/happy2-server/dist/modules/agent/agentChatBind.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js +3 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts +7 -0
- package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js +15 -0
- package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentCreate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentCreate.js +1 -0
- package/packages/happy2-server/dist/modules/agent/agentCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.d.ts +4 -2
- package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.js +8 -8
- package/packages/happy2-server/dist/modules/agent/agentEffortBindingList.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.d.ts +3 -3
- package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.js +4 -4
- package/packages/happy2-server/dist/modules/agent/agentEffortGetContext.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.d.ts +4 -4
- package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.js +57 -41
- package/packages/happy2-server/dist/modules/agent/agentEffortUpdate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGet.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGet.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageGet.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.d.ts +2 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js +11 -4
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageList.d.ts +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageList.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageList.js +8 -4
- package/packages/happy2-server/dist/modules/agent/agentImageList.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentDelete.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretAssignmentList.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToAgent.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretAttachToChannel.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.d.ts +4 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.js +5 -5
- package/packages/happy2-server/dist/modules/agent/agentSecretAuthorizeManagement.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromAgent.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.d.ts +2 -2
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.js +4 -4
- package/packages/happy2-server/dist/modules/agent/agentSecretDetachFromChannel.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.d.ts +1 -1
- package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentSecretRecordRegistration.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.d.ts +4 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.js +207 -9
- package/packages/happy2-server/dist/modules/agent/agentTurnStreamReply.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.d.ts +8 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.js +86 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceGet.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.d.ts +19 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.js +87 -0
- package/packages/happy2-server/dist/modules/agent/agentTurnTraceStart.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/impl/agentChatContext.d.ts +2 -1
- package/packages/happy2-server/dist/modules/agent/impl/agentChatContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContext.d.ts +4 -1
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.d.ts +3 -3
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.js +26 -40
- package/packages/happy2-server/dist/modules/agent/impl/agentEffortContextDb.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.js +63 -2
- package/packages/happy2-server/dist/modules/agent/impl/finishAgentTurn.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/types.d.ts +53 -0
- package/packages/happy2-server/dist/modules/agent/types.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agents/daemon.d.ts +31 -2
- package/packages/happy2-server/dist/modules/agents/daemon.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agents/daemon.js +12 -2
- package/packages/happy2-server/dist/modules/agents/daemon.js.map +1 -1
- package/packages/happy2-server/dist/modules/agents/service.d.ts +13 -6
- package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agents/service.js +497 -49
- package/packages/happy2-server/dist/modules/agents/service.js.map +1 -1
- package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.d.ts +12 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.js +27 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenCreate.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.d.ts +8 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.js +22 -0
- package/packages/happy2-server/dist/modules/auth/developmentTokenFindActive.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.d.ts +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/auth/methods.js +10 -6
- package/packages/happy2-server/dist/modules/auth/methods.js.map +1 -1
- package/packages/happy2-server/dist/modules/auth/service.d.ts +2 -0
- package/packages/happy2-server/dist/modules/auth/service.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/auth/service.js +26 -0
- package/packages/happy2-server/dist/modules/auth/service.js.map +1 -1
- package/packages/happy2-server/dist/modules/auth/tokens.d.ts +13 -0
- package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/auth/tokens.js +59 -0
- package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -1
- package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/tokens.test.js +48 -0
- package/packages/happy2-server/dist/modules/auth/tokens.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.d.ts +17 -0
- package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.js +98 -0
- package/packages/happy2-server/dist/modules/chat/asAgentTurnTrace.js.map +1 -0
- package/packages/happy2-server/dist/modules/chat/asServiceMessage.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/chat/asServiceMessage.js +13 -5
- package/packages/happy2-server/dist/modules/chat/asServiceMessage.js.map +1 -1
- package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.d.ts +20 -0
- package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.js +38 -0
- package/packages/happy2-server/dist/modules/chat/chatUpdateMetadata.js.map +1 -0
- package/packages/happy2-server/dist/modules/chat/types.d.ts +6 -0
- package/packages/happy2-server/dist/modules/chat/types.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/chat/types.js.map +1 -1
- package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.d.ts +7 -0
- package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.js +19 -0
- package/packages/happy2-server/dist/modules/chat/userRequireActiveHuman.js.map +1 -0
- package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.d.ts +2 -2
- package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.js +8 -5
- package/packages/happy2-server/dist/modules/chat/userRequireServerAdmin.js.map +1 -1
- package/packages/happy2-server/dist/modules/config/defaults.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/config/defaults.js +3 -0
- package/packages/happy2-server/dist/modules/config/defaults.js.map +1 -1
- package/packages/happy2-server/dist/modules/config/defaults.test.js +1 -0
- package/packages/happy2-server/dist/modules/config/defaults.test.js.map +1 -1
- package/packages/happy2-server/dist/modules/config/loader.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/config/loader.js +9 -0
- package/packages/happy2-server/dist/modules/config/loader.js.map +1 -1
- package/packages/happy2-server/dist/modules/config/loader.test.js +27 -0
- package/packages/happy2-server/dist/modules/config/loader.test.js.map +1 -1
- package/packages/happy2-server/dist/modules/config/type.d.ts +5 -0
- package/packages/happy2-server/dist/modules/config/type.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/message/messageGetProjection.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/message/messageGetProjection.js +28 -0
- package/packages/happy2-server/dist/modules/message/messageGetProjection.js.map +1 -1
- package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.d.ts +4 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.js +39 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionEffectiveDb.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.d.ts +10 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.js +31 -0
- package/packages/happy2-server/dist/modules/permission/impl/permissionMutationRecord.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/permissionGetEffective.d.ts +8 -0
- package/packages/happy2-server/dist/modules/permission/permissionGetEffective.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/permissionGetEffective.js +13 -0
- package/packages/happy2-server/dist/modules/permission/permissionGetEffective.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleCreate.d.ts +16 -0
- package/packages/happy2-server/dist/modules/permission/roleCreate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleCreate.js +70 -0
- package/packages/happy2-server/dist/modules/permission/roleCreate.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleDelete.d.ts +11 -0
- package/packages/happy2-server/dist/modules/permission/roleDelete.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleDelete.js +41 -0
- package/packages/happy2-server/dist/modules/permission/roleDelete.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleList.d.ts +8 -0
- package/packages/happy2-server/dist/modules/permission/roleList.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleList.js +36 -0
- package/packages/happy2-server/dist/modules/permission/roleList.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleUpdate.d.ts +14 -0
- package/packages/happy2-server/dist/modules/permission/roleUpdate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/roleUpdate.js +78 -0
- package/packages/happy2-server/dist/modules/permission/roleUpdate.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/types.d.ts +24 -0
- package/packages/happy2-server/dist/modules/permission/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/types.js +10 -0
- package/packages/happy2-server/dist/modules/permission/types.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionGet.d.ts +16 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionGet.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionGet.js +33 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionGet.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.d.ts +12 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.js +44 -0
- package/packages/happy2-server/dist/modules/permission/userPermissionUpdate.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.d.ts +8 -0
- package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.js +12 -0
- package/packages/happy2-server/dist/modules/permission/userRequireAnyPermission.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRequirePermission.d.ts +8 -0
- package/packages/happy2-server/dist/modules/permission/userRequirePermission.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRequirePermission.js +12 -0
- package/packages/happy2-server/dist/modules/permission/userRequirePermission.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRoleAssign.d.ts +12 -0
- package/packages/happy2-server/dist/modules/permission/userRoleAssign.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRoleAssign.js +46 -0
- package/packages/happy2-server/dist/modules/permission/userRoleAssign.js.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRoleUnassign.d.ts +12 -0
- package/packages/happy2-server/dist/modules/permission/userRoleUnassign.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/permission/userRoleUnassign.js +53 -0
- package/packages/happy2-server/dist/modules/permission/userRoleUnassign.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/archive.d.ts +7 -0
- package/packages/happy2-server/dist/modules/plugin/archive.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/archive.js +222 -0
- package/packages/happy2-server/dist/modules/plugin/archive.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/catalog.d.ts +5 -1
- package/packages/happy2-server/dist/modules/plugin/catalog.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/catalog.js +75 -15
- package/packages/happy2-server/dist/modules/plugin/catalog.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/catalog.test.js +37 -0
- package/packages/happy2-server/dist/modules/plugin/catalog.test.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/httpBridge.d.ts +1 -0
- package/packages/happy2-server/dist/modules/plugin/httpBridge.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/httpBridge.js +7 -0
- package/packages/happy2-server/dist/modules/plugin/httpBridge.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js +3 -2
- package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js +17 -3
- package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts +3 -0
- package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js +12 -0
- package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js +11 -0
- package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.d.ts +11 -0
- package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.js +2 -0
- package/packages/happy2-server/dist/modules/plugin/impl/pluginSkillSource.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts +13 -0
- package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/packageStore.js +122 -14
- package/packages/happy2-server/dist/modules/plugin/packageStore.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.d.ts +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.js +3 -3
- package/packages/happy2-server/dist/modules/plugin/pluginAuthorizeManagement.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js +15 -1
- package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts +10 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js +20 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts +12 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js +44 -0
- package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.d.ts +3 -1
- package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.js +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginFindBySource.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginGetImage.d.ts +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginGetImage.js +3 -3
- package/packages/happy2-server/dist/modules/plugin/pluginGetImage.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginGetSource.d.ts +13 -0
- package/packages/happy2-server/dist/modules/plugin/pluginGetSource.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginGetSource.js +37 -0
- package/packages/happy2-server/dist/modules/plugin/pluginGetSource.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.js +28 -9
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js +18 -7
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.d.ts +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.js +3 -3
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationList.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts +14 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js +20 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginList.d.ts +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginList.js +3 -3
- package/packages/happy2-server/dist/modules/plugin/pluginList.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts +11 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js +43 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts +15 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js +37 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts +16 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js +71 -0
- package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.d.ts +8 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.js +24 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListInstalled.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.d.ts +8 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.js +25 -0
- package/packages/happy2-server/dist/modules/plugin/pluginSkillsListReady.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginUninstall.d.ts +13 -0
- package/packages/happy2-server/dist/modules/plugin/pluginUninstall.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginUninstall.js +63 -0
- package/packages/happy2-server/dist/modules/plugin/pluginUninstall.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/runtime.d.ts +20 -0
- package/packages/happy2-server/dist/modules/plugin/runtime.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/runtime.js +88 -2
- package/packages/happy2-server/dist/modules/plugin/runtime.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/service.d.ts +64 -5
- package/packages/happy2-server/dist/modules/plugin/service.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/service.js +552 -173
- package/packages/happy2-server/dist/modules/plugin/service.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/source.d.ts +35 -0
- package/packages/happy2-server/dist/modules/plugin/source.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/source.js +189 -0
- package/packages/happy2-server/dist/modules/plugin/source.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/types.d.ts +87 -11
- package/packages/happy2-server/dist/modules/plugin/types.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/types.js +1 -0
- package/packages/happy2-server/dist/modules/plugin/types.js.map +1 -1
- package/packages/happy2-server/dist/modules/realtime/events.d.ts +3 -0
- package/packages/happy2-server/dist/modules/realtime/events.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/realtime/events.js +37 -5
- package/packages/happy2-server/dist/modules/realtime/events.js.map +1 -1
- package/packages/happy2-server/dist/modules/realtime/local.test.js +2 -0
- package/packages/happy2-server/dist/modules/realtime/local.test.js.map +1 -1
- package/packages/happy2-server/dist/modules/sandbox/index.d.ts +1 -1
- package/packages/happy2-server/dist/modules/sandbox/index.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts +8 -1
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js +105 -3
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js.map +1 -1
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js +82 -3
- package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js.map +1 -1
- package/packages/happy2-server/dist/modules/sandbox/types.d.ts +17 -0
- package/packages/happy2-server/dist/modules/sandbox/types.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/schema.d.ts +2245 -233
- package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/schema.js +120 -0
- package/packages/happy2-server/dist/modules/schema.js.map +1 -1
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.js +2 -0
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.js.map +1 -1
- package/packages/happy2-server/dist/modules/user/userAdministrationList.js +2 -2
- package/packages/happy2-server/dist/modules/user/userAdministrationList.js.map +1 -1
- package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.js +49 -6
- package/packages/happy2-server/dist/modules/user/userAdministrationUpdate.js.map +1 -1
- package/packages/happy2-server/dist/modules/user/userCreateProfile.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/user/userCreateProfile.js +17 -2
- package/packages/happy2-server/dist/modules/user/userCreateProfile.js.map +1 -1
- package/packages/happy2-server/dist/routes/agents.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/agents.js +4 -2
- package/packages/happy2-server/dist/routes/agents.js.map +1 -1
- package/packages/happy2-server/dist/routes/auth.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/auth.js +12 -0
- package/packages/happy2-server/dist/routes/auth.js.map +1 -1
- package/packages/happy2-server/dist/routes/collaboration.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/collaboration.js +7 -0
- package/packages/happy2-server/dist/routes/collaboration.js.map +1 -1
- package/packages/happy2-server/dist/routes/files.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/files.js +2 -0
- package/packages/happy2-server/dist/routes/files.js.map +1 -1
- package/packages/happy2-server/dist/routes/permissions.d.ts +6 -0
- package/packages/happy2-server/dist/routes/permissions.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/permissions.js +207 -0
- package/packages/happy2-server/dist/routes/permissions.js.map +1 -0
- package/packages/happy2-server/dist/routes/pluginHost.d.ts +6 -0
- package/packages/happy2-server/dist/routes/pluginHost.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/pluginHost.js +106 -0
- package/packages/happy2-server/dist/routes/pluginHost.js.map +1 -0
- package/packages/happy2-server/dist/routes/plugins.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/plugins.js +159 -5
- package/packages/happy2-server/dist/routes/plugins.js.map +1 -1
- package/packages/happy2-server/dist/runner.js +20 -1
- package/packages/happy2-server/dist/runner.js.map +1 -1
- package/packages/happy2-server/dist/server.d.ts +4 -0
- package/packages/happy2-server/dist/server.d.ts.map +1 -1
- package/packages/happy2-server/dist/server.js +23 -1
- package/packages/happy2-server/dist/server.js.map +1 -1
- package/packages/happy2-server/dist/systemService.d.ts.map +1 -1
- package/packages/happy2-server/dist/systemService.js +16 -1
- package/packages/happy2-server/dist/systemService.js.map +1 -1
- package/packages/happy2-server/dist/systemService.test.js +15 -1
- package/packages/happy2-server/dist/systemService.test.js.map +1 -1
- package/packages/happy2-server/dist/web/assets/index-BaPUPGPe.css +2 -0
- package/packages/happy2-server/dist/web/assets/index-BnhFxR3U.js +39 -0
- package/packages/happy2-server/dist/web/index.html +2 -2
- package/packages/happy2-server/drizzle/0022_plugin_container_runtime_tools.sql +16 -0
- package/packages/happy2-server/drizzle/0023_roles_and_permissions.sql +82 -0
- package/packages/happy2-server/drizzle/0024_session_bound_dev_tokens.sql +11 -0
- package/packages/happy2-server/drizzle/0025_plugin_skills.sql +8 -0
- package/packages/happy2-server/drizzle/0026_agent_turn_traces.sql +35 -0
- package/packages/happy2-server/drizzle/0027_chat_agent_effort.sql +9 -0
- package/packages/happy2-server/drizzle/meta/_journal.json +42 -0
- package/packages/happy2-server/happy2.example.toml +14 -0
- package/packages/happy2-server/plugins/README.md +3 -1
- package/packages/happy2-server/plugins/chat-management/container/Dockerfile +6 -0
- package/packages/happy2-server/plugins/chat-management/plugin.json +17 -0
- package/packages/happy2-server/plugins/chat-management/plugin.png +0 -0
- package/packages/happy2-server/plugins/chat-management/server.mjs +113 -0
- package/packages/happy2-server/dist/web/assets/index-9SGCQLg7.js +0 -46
- 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 {
|
|
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
|
|
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
|
-
|
|
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 !== "
|
|
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
|
|
264
|
+
command: configuration.mcp.command,
|
|
265
|
+
args: configuration.mcp.args,
|
|
266
|
+
environment,
|
|
114
267
|
});
|
|
115
268
|
}
|
|
116
269
|
async listFunctions(signal) {
|
|
117
|
-
|
|
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
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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:
|
|
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
|
-
|
|
240
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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:
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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 (
|
|
323
|
-
this.
|
|
324
|
-
|
|
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
|
|
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
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|