From 5a42d06f3163f34134b03e5f4dfa9ecdf9f89a8d Mon Sep 17 00:00:00 2001
From: Alena Petraki <alena.petraki@gmail.com>
Date: Mon, 9 Oct 2023 11:23:18 +0300
Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?=
 =?UTF-8?q?=D0=BA=D0=B0=20=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80=D0=B5=D0=BD?=
 =?UTF-8?q?=D0=B8=D1=8F=D0=BC=D0=B8=20=D0=B4=D0=BB=D0=B8=D1=82=D0=B5=D0=BB?=
 =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D1=85=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86?=
 =?UTF-8?q?=D0=B8=D0=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 perxis-proto                                  |   2 +-
 pkg/extension/client.go                       |  15 -
 pkg/extension/extension.go                    |  54 +-
 pkg/extension/manager.go                      |   1 +
 pkg/extension/manager_client.go               |  12 +
 .../middleware/error_logging_middleware.go    | 114 ++++
 .../middleware/logging_middleware.go          | 354 +++++++++++++
 pkg/extension/middleware/middleware.go        |  28 +
 .../middleware/recovering_middleware.go       | 138 +++++
 pkg/extension/mocks/Manager.go                |  33 ++
 pkg/extension/mocks/Storage.go                |  47 +-
 pkg/extension/schema.go                       |  38 +-
 pkg/extension/server.go                       |  65 ++-
 pkg/extension/server_test.go                  | 191 +++----
 pkg/extension/storage.go                      |  82 ++-
 pkg/items/item.go                             |   5 +
 pkg/operation/operation.go                    |   4 +-
 pkg/operation/operation_test.go               |   2 +-
 pkg/operation/service.go                      |   6 +-
 pkg/setup/collection.go                       |  18 +-
 pkg/setup/collection_test.go                  |  31 +-
 pkg/setup/setup_test.go                       |  21 +-
 proto/extensions/extension_service.pb.go      | 178 +++----
 proto/extensions/manager_service.pb.go        | 488 +++++++++---------
 proto/extensions/manager_service_grpc.pb.go   |  56 +-
 25 files changed, 1433 insertions(+), 550 deletions(-)
 create mode 100644 pkg/extension/middleware/error_logging_middleware.go
 create mode 100644 pkg/extension/middleware/logging_middleware.go
 create mode 100644 pkg/extension/middleware/middleware.go
 create mode 100644 pkg/extension/middleware/recovering_middleware.go

diff --git a/perxis-proto b/perxis-proto
index d394a1e5..bf0e4424 160000
--- a/perxis-proto
+++ b/perxis-proto
@@ -1 +1 @@
-Subproject commit d394a1e5f62879152247b18cc3cb8c5d7a1bd23b
+Subproject commit bf0e4424c57db4a5fac4ead73a14713a075cecbf
diff --git a/pkg/extension/client.go b/pkg/extension/client.go
index 44772edb..3f8d8bcb 100644
--- a/pkg/extension/client.go
+++ b/pkg/extension/client.go
@@ -25,21 +25,6 @@ func (c Client) GetDescriptor() *ExtensionDescriptor {
 	return nil
 }
 
-// no usage found
-//func (c Client) wait(ctx context.Context, fn func(context.Context) (*operation.Proto, error)) error {
-//	pbOperation, err := fn(ctx)
-//	if err != nil {
-//		return err
-//	}
-//
-//	op := operation.Wrap(c.opsClient, pbOperation)
-//	if err = op.Wait(ctx); err != nil {
-//		return err
-//	}
-//
-//	return op.Error()
-//}
-
 func (c *Client) InstallOperation(ctx context.Context, req *InstallRequest) (*operation.Operation, error) {
 	pbOperation, err := c.client.Install(ctx, req)
 	if err != nil {
diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go
index 1166b9d3..46f9f48d 100644
--- a/pkg/extension/extension.go
+++ b/pkg/extension/extension.go
@@ -11,12 +11,12 @@ import (
 )
 
 const (
-	StatePending    = pb.SpaceExtensions_PENDING
-	StateInstalled  = pb.SpaceExtensions_INSTALLED
-	StateInProgress = pb.SpaceExtensions_IN_PROGRESS
-	StateFail       = pb.SpaceExtensions_FAIL
+	StatePending    = pb.State_PENDING
+	StateInstalled  = pb.State_INSTALLED
+	StateInProgress = pb.State_IN_PROGRESS
+	StateFail       = pb.State_FAIL
 
-	ExtensionMetadataKey = "extension"
+	ExtensionMetadataKey = "extension" // todo: давайте переименуем -> MetadataKey? везде импорты extension.ExtensionMetadataKey
 )
 
 type (
@@ -24,10 +24,29 @@ type (
 	CheckRequest     = pb.CheckRequest
 	UninstallRequest = pb.UninstallRequest
 
-	ExtensionDescriptor  = pb.ExtensionDescriptor
-	SpaceExtensionsState = pb.SpaceExtensions_State
+	ExtensionDescriptor = pb.ExtensionDescriptor
+	State               = pb.State
 )
 
+//type State pb.State
+//
+//func (s State) Value() int {
+//	return int(s)
+//}
+//
+//func (s State) String() string {
+//	return pb.State(s).String()
+//}
+//
+//const (
+//	StatePending    = State(pb.State_PENDING)
+//	StateInstalled  = State(pb.State_INSTALLED)
+//	StateInProgress = State(pb.State_IN_PROGRESS)
+//	StateFail       = State(pb.State_FAIL)
+//
+//	//ExtensionMetadataKey = "extension"
+//)
+
 var (
 	ErrStart = errors.New("start failed")
 	ErrStop  = errors.New("stop failed")
@@ -37,7 +56,6 @@ var (
 	ErrCheck     = errors.New("check failed")
 	ErrUninstall = errors.New("uninstall failed")
 
-	ErrUpdateAvailable  = errors.New("update available")
 	ErrNotInstalled     = errors.New("not installed")
 	ErrUnknownExtension = errors.New("unknown extension")
 )
@@ -68,8 +86,7 @@ type Extension interface {
 
 func CheckInstalled(ctx context.Context, content *content.Content, spaceID, envID, extension string) (bool, error) {
 	res, _, err := content.Items.Find(ctx, spaceID, envID, StatusCollectionID,
-		&items.Filter{Q: []string{fmt.Sprintf("extension == '%s'", extension)}})
-
+		&items.Filter{Q: []string{fmt.Sprintf("id == '%s'", extension)}})
 	if err != nil {
 		return false, err
 	}
@@ -79,14 +96,15 @@ func CheckInstalled(ctx context.Context, content *content.Content, spaceID, envI
 	}
 
 	return true, nil
-}
 
-func ExtensionError(err error, ext string) error {
-	return errors.WithContext(err, "extension", ext)
 }
 
-func ExtensionFromError(err error) string {
-	v, _ := errors.ContextKey(err, "extension")
-	ext, _ := v.(string)
-	return ext
-}
+//func ExtensionError(err error, ext string) error {
+//	return errors.WithContext(err, "extension", ext)
+//}
+//
+//func ExtensionFromError(err error) string {
+//	v, _ := errors.ContextKey(err, "extension")
+//	ext, _ := v.(string)
+//	return ext
+//}
diff --git a/pkg/extension/manager.go b/pkg/extension/manager.go
index 958ac178..d196bdad 100644
--- a/pkg/extension/manager.go
+++ b/pkg/extension/manager.go
@@ -15,6 +15,7 @@ type Manager interface {
 	RegisterExtensions(ctx context.Context, ext ...*ExtensionConnector) error
 	UnregisterExtensions(ctx context.Context, ext ...*ExtensionConnector) error
 	ListExtensions(ctx context.Context, filter *ListExtensionsFilter) ([]*ExtensionConnector, error)
+	GetInstalledExtensions(ctx context.Context, space, env string, extensions ...string) ([]*Status, error)
 }
 
 type (
diff --git a/pkg/extension/manager_client.go b/pkg/extension/manager_client.go
index 3da83cab..126cbe86 100644
--- a/pkg/extension/manager_client.go
+++ b/pkg/extension/manager_client.go
@@ -70,3 +70,15 @@ func (c *ManagerClient) ListExtensions(ctx context.Context, filter *ListExtensio
 
 	return exts, nil
 }
+
+func (c *ManagerClient) GetInstalledExtensions(ctx context.Context, space, env string, extensions ...string) ([]*Status, error) {
+	resp, err := c.manager.GetInstalledExtensions(ctx, &pb.GetInstalledExtensionsRequest{
+		Extensions: extensions,
+		SpaceId:    space,
+		EnvId:      env,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return resp.Status, err
+}
diff --git a/pkg/extension/middleware/error_logging_middleware.go b/pkg/extension/middleware/error_logging_middleware.go
new file mode 100644
index 00000000..2b3ec2f6
--- /dev/null
+++ b/pkg/extension/middleware/error_logging_middleware.go
@@ -0,0 +1,114 @@
+package middleware
+
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/error_log
+// gowrap: http://github.com/hexdigest/gowrap
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/error_log -o error_logging_middleware.go -l ""
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/pkg/extension"
+	"go.uber.org/zap"
+)
+
+// errorLoggingMiddleware implements extension.Manager that is instrumented with logging
+type errorLoggingMiddleware struct {
+	logger *zap.Logger
+	next   extension.Manager
+}
+
+// ErrorLoggingMiddleware instruments an implementation of the extension.Manager with simple logging
+func ErrorLoggingMiddleware(logger *zap.Logger) Middleware {
+	return func(next extension.Manager) extension.Manager {
+		return &errorLoggingMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *errorLoggingMiddleware) Action(ctx context.Context, in *extension.ActionRequest) (ap1 *extension.ActionResponse, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Action(ctx, in)
+}
+
+func (m *errorLoggingMiddleware) Check(ctx context.Context, in *extension.CheckRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Check(ctx, in)
+}
+
+func (m *errorLoggingMiddleware) GetDescriptor() (ep1 *extension.ExtensionDescriptor) {
+	return m.next.GetDescriptor()
+}
+
+func (m *errorLoggingMiddleware) GetInstalledExtensions(ctx context.Context, space string, env string, extensions ...string) (spa1 []*extension.Status, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.GetInstalledExtensions(ctx, space, env, extensions...)
+}
+
+func (m *errorLoggingMiddleware) Install(ctx context.Context, in *extension.InstallRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Install(ctx, in)
+}
+
+func (m *errorLoggingMiddleware) ListExtensions(ctx context.Context, filter *extension.ListExtensionsFilter) (epa1 []*extension.ExtensionConnector, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.ListExtensions(ctx, filter)
+}
+
+func (m *errorLoggingMiddleware) RegisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.RegisterExtensions(ctx, ext...)
+}
+
+func (m *errorLoggingMiddleware) Uninstall(ctx context.Context, in *extension.UninstallRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Uninstall(ctx, in)
+}
+
+func (m *errorLoggingMiddleware) UnregisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.UnregisterExtensions(ctx, ext...)
+}
diff --git a/pkg/extension/middleware/logging_middleware.go b/pkg/extension/middleware/logging_middleware.go
new file mode 100644
index 00000000..49eda622
--- /dev/null
+++ b/pkg/extension/middleware/logging_middleware.go
@@ -0,0 +1,354 @@
+package middleware
+
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/access_log
+// gowrap: http://github.com/hexdigest/gowrap
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/access_log -o logging_middleware.go -l ""
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
+	"git.perx.ru/perxis/perxis-go/pkg/extension"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// loggingMiddleware implements extension.Manager that is instrumented with logging
+type loggingMiddleware struct {
+	logger *zap.Logger
+	next   extension.Manager
+}
+
+// LoggingMiddleware instruments an implementation of the extension.Manager with simple logging
+func LoggingMiddleware(logger *zap.Logger) Middleware {
+	return func(next extension.Manager) extension.Manager {
+		return &loggingMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *loggingMiddleware) Action(ctx context.Context, in *extension.ActionRequest) (ap1 *extension.ActionResponse, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"in":  in} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Action.Request", fields...)
+
+	ap1, err = m.next.Action(ctx, in)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"ap1": ap1,
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Action.Response", fields...)
+
+	return ap1, err
+}
+
+func (m *loggingMiddleware) Check(ctx context.Context, in *extension.CheckRequest) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"in":  in} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Check.Request", fields...)
+
+	err = m.next.Check(ctx, in)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Check.Response", fields...)
+
+	return err
+}
+
+func (m *loggingMiddleware) GetDescriptor() (ep1 *extension.ExtensionDescriptor) {
+	begin := time.Now()
+	var fields []zapcore.Field
+
+	m.logger.Debug("GetDescriptor.Request", fields...)
+
+	ep1 = m.next.GetDescriptor()
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"ep1": ep1} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("GetDescriptor.Response", fields...)
+
+	return ep1
+}
+
+func (m *loggingMiddleware) GetInstalledExtensions(ctx context.Context, space string, env string, extensions ...string) (spa1 []*extension.Status, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":        ctx,
+		"space":      space,
+		"env":        env,
+		"extensions": extensions} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("GetInstalledExtensions.Request", fields...)
+
+	spa1, err = m.next.GetInstalledExtensions(ctx, space, env, extensions...)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"spa1": spa1,
+		"err":  err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("GetInstalledExtensions.Response", fields...)
+
+	return spa1, err
+}
+
+func (m *loggingMiddleware) Install(ctx context.Context, in *extension.InstallRequest) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"in":  in} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Install.Request", fields...)
+
+	err = m.next.Install(ctx, in)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Install.Response", fields...)
+
+	return err
+}
+
+func (m *loggingMiddleware) ListExtensions(ctx context.Context, filter *extension.ListExtensionsFilter) (epa1 []*extension.ExtensionConnector, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":    ctx,
+		"filter": filter} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("ListExtensions.Request", fields...)
+
+	epa1, err = m.next.ListExtensions(ctx, filter)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"epa1": epa1,
+		"err":  err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("ListExtensions.Response", fields...)
+
+	return epa1, err
+}
+
+func (m *loggingMiddleware) RegisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"ext": ext} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("RegisterExtensions.Request", fields...)
+
+	err = m.next.RegisterExtensions(ctx, ext...)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("RegisterExtensions.Response", fields...)
+
+	return err
+}
+
+func (m *loggingMiddleware) Uninstall(ctx context.Context, in *extension.UninstallRequest) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"in":  in} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Uninstall.Request", fields...)
+
+	err = m.next.Uninstall(ctx, in)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Uninstall.Response", fields...)
+
+	return err
+}
+
+func (m *loggingMiddleware) UnregisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx": ctx,
+		"ext": ext} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("UnregisterExtensions.Request", fields...)
+
+	err = m.next.UnregisterExtensions(ctx, ext...)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			err, _ := v.(error)
+			fields = append(fields, zap.Error(err))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("UnregisterExtensions.Response", fields...)
+
+	return err
+}
diff --git a/pkg/extension/middleware/middleware.go b/pkg/extension/middleware/middleware.go
new file mode 100644
index 00000000..52b8bff7
--- /dev/null
+++ b/pkg/extension/middleware/middleware.go
@@ -0,0 +1,28 @@
+package middleware
+
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/middleware
+// gowrap: http://github.com/hexdigest/gowrap
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/middleware -o middleware.go -l ""
+
+import (
+	"git.perx.ru/perxis/perxis-go/pkg/extension"
+	"go.uber.org/zap"
+)
+
+type Middleware func(extension.Manager) extension.Manager
+
+func WithLog(s extension.Manager, logger *zap.Logger, log_access bool) extension.Manager {
+	if logger == nil {
+		logger = zap.NewNop()
+	}
+
+	logger = logger.Named("Manager")
+	s = ErrorLoggingMiddleware(logger)(s)
+	if log_access {
+		s = LoggingMiddleware(logger)(s)
+	}
+	s = RecoveringMiddleware(logger)(s)
+	return s
+}
diff --git a/pkg/extension/middleware/recovering_middleware.go b/pkg/extension/middleware/recovering_middleware.go
new file mode 100644
index 00000000..5d9a3b56
--- /dev/null
+++ b/pkg/extension/middleware/recovering_middleware.go
@@ -0,0 +1,138 @@
+package middleware
+
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/recovery
+// gowrap: http://github.com/hexdigest/gowrap
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/recovery -o recovering_middleware.go -l ""
+
+import (
+	"context"
+	"fmt"
+
+	"git.perx.ru/perxis/perxis-go/pkg/extension"
+	"go.uber.org/zap"
+)
+
+// recoveringMiddleware implements extension.Manager that is instrumented with logging
+type recoveringMiddleware struct {
+	logger *zap.Logger
+	next   extension.Manager
+}
+
+// RecoveringMiddleware instruments an implementation of the extension.Manager with simple logging
+func RecoveringMiddleware(logger *zap.Logger) Middleware {
+	return func(next extension.Manager) extension.Manager {
+		return &recoveringMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *recoveringMiddleware) Action(ctx context.Context, in *extension.ActionRequest) (ap1 *extension.ActionResponse, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Action(ctx, in)
+}
+
+func (m *recoveringMiddleware) Check(ctx context.Context, in *extension.CheckRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Check(ctx, in)
+}
+
+func (m *recoveringMiddleware) GetDescriptor() (ep1 *extension.ExtensionDescriptor) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+		}
+	}()
+
+	return m.next.GetDescriptor()
+}
+
+func (m *recoveringMiddleware) GetInstalledExtensions(ctx context.Context, space string, env string, extensions ...string) (spa1 []*extension.Status, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.GetInstalledExtensions(ctx, space, env, extensions...)
+}
+
+func (m *recoveringMiddleware) Install(ctx context.Context, in *extension.InstallRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Install(ctx, in)
+}
+
+func (m *recoveringMiddleware) ListExtensions(ctx context.Context, filter *extension.ListExtensionsFilter) (epa1 []*extension.ExtensionConnector, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.ListExtensions(ctx, filter)
+}
+
+func (m *recoveringMiddleware) RegisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.RegisterExtensions(ctx, ext...)
+}
+
+func (m *recoveringMiddleware) Uninstall(ctx context.Context, in *extension.UninstallRequest) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Uninstall(ctx, in)
+}
+
+func (m *recoveringMiddleware) UnregisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.UnregisterExtensions(ctx, ext...)
+}
diff --git a/pkg/extension/mocks/Manager.go b/pkg/extension/mocks/Manager.go
index 0c19069e..7d4266a3 100644
--- a/pkg/extension/mocks/Manager.go
+++ b/pkg/extension/mocks/Manager.go
@@ -72,6 +72,39 @@ func (_m *Manager) GetDescriptor() *extensions.ExtensionDescriptor {
 	return r0
 }
 
+// GetInstalledExtensions provides a mock function with given fields: ctx, space, env, _a3
+func (_m *Manager) GetInstalledExtensions(ctx context.Context, space string, env string, _a3 ...string) ([]*extensions.GetInstalledExtensionsResponse_Status, error) {
+	_va := make([]interface{}, len(_a3))
+	for _i := range _a3 {
+		_va[_i] = _a3[_i]
+	}
+	var _ca []interface{}
+	_ca = append(_ca, ctx, space, env)
+	_ca = append(_ca, _va...)
+	ret := _m.Called(_ca...)
+
+	var r0 []*extensions.GetInstalledExtensionsResponse_Status
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) ([]*extensions.GetInstalledExtensionsResponse_Status, error)); ok {
+		return rf(ctx, space, env, _a3...)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) []*extensions.GetInstalledExtensionsResponse_Status); ok {
+		r0 = rf(ctx, space, env, _a3...)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]*extensions.GetInstalledExtensionsResponse_Status)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, string, string, ...string) error); ok {
+		r1 = rf(ctx, space, env, _a3...)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // Install provides a mock function with given fields: ctx, in
 func (_m *Manager) Install(ctx context.Context, in *extensions.InstallRequest) error {
 	ret := _m.Called(ctx, in)
diff --git a/pkg/extension/mocks/Storage.go b/pkg/extension/mocks/Storage.go
index c767c3c6..702f178f 100644
--- a/pkg/extension/mocks/Storage.go
+++ b/pkg/extension/mocks/Storage.go
@@ -29,20 +29,53 @@ func (_m *Storage) DeleteStatus(ctx context.Context, spaceID string, envID strin
 	return r0
 }
 
+// FindStatuses provides a mock function with given fields: ctx, spaceID, envID, _a3
+func (_m *Storage) FindStatuses(ctx context.Context, spaceID string, envID string, _a3 ...string) ([]*extensions.GetInstalledExtensionsResponse_Status, error) {
+	_va := make([]interface{}, len(_a3))
+	for _i := range _a3 {
+		_va[_i] = _a3[_i]
+	}
+	var _ca []interface{}
+	_ca = append(_ca, ctx, spaceID, envID)
+	_ca = append(_ca, _va...)
+	ret := _m.Called(_ca...)
+
+	var r0 []*extensions.GetInstalledExtensionsResponse_Status
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) ([]*extensions.GetInstalledExtensionsResponse_Status, error)); ok {
+		return rf(ctx, spaceID, envID, _a3...)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) []*extensions.GetInstalledExtensionsResponse_Status); ok {
+		r0 = rf(ctx, spaceID, envID, _a3...)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]*extensions.GetInstalledExtensionsResponse_Status)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, string, string, ...string) error); ok {
+		r1 = rf(ctx, spaceID, envID, _a3...)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // GetStatus provides a mock function with given fields: ctx, spaceID, envID, _a3
-func (_m *Storage) GetStatus(ctx context.Context, spaceID string, envID string, _a3 string) (*extensions.GetExtensionsResponse_Status, error) {
+func (_m *Storage) GetStatus(ctx context.Context, spaceID string, envID string, _a3 string) (*extensions.GetInstalledExtensionsResponse_Status, error) {
 	ret := _m.Called(ctx, spaceID, envID, _a3)
 
-	var r0 *extensions.GetExtensionsResponse_Status
+	var r0 *extensions.GetInstalledExtensionsResponse_Status
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*extensions.GetExtensionsResponse_Status, error)); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*extensions.GetInstalledExtensionsResponse_Status, error)); ok {
 		return rf(ctx, spaceID, envID, _a3)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *extensions.GetExtensionsResponse_Status); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *extensions.GetInstalledExtensionsResponse_Status); ok {
 		r0 = rf(ctx, spaceID, envID, _a3)
 	} else {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*extensions.GetExtensionsResponse_Status)
+			r0 = ret.Get(0).(*extensions.GetInstalledExtensionsResponse_Status)
 		}
 	}
 
@@ -56,11 +89,11 @@ func (_m *Storage) GetStatus(ctx context.Context, spaceID string, envID string,
 }
 
 // SetStatus provides a mock function with given fields: ctx, spaceID, envID, _a3, status
-func (_m *Storage) SetStatus(ctx context.Context, spaceID string, envID string, _a3 string, status *extensions.GetExtensionsResponse_Status) error {
+func (_m *Storage) SetStatus(ctx context.Context, spaceID string, envID string, _a3 string, status *extensions.GetInstalledExtensionsResponse_Status) error {
 	ret := _m.Called(ctx, spaceID, envID, _a3, status)
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *extensions.GetExtensionsResponse_Status) error); ok {
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *extensions.GetInstalledExtensionsResponse_Status) error); ok {
 		r0 = rf(ctx, spaceID, envID, _a3, status)
 	} else {
 		r0 = ret.Error(0)
diff --git a/pkg/extension/schema.go b/pkg/extension/schema.go
index 3e478231..47724bb3 100644
--- a/pkg/extension/schema.go
+++ b/pkg/extension/schema.go
@@ -1,6 +1,8 @@
 package extension
 
 import (
+	"sort"
+
 	"git.perx.ru/perxis/perxis-go/pkg/collections"
 	"git.perx.ru/perxis/perxis-go/pkg/references"
 	"git.perx.ru/perxis/perxis-go/pkg/schema"
@@ -29,15 +31,29 @@ func NewActionsCollection(spaceID, envID string) *collections.Collection {
 	}
 }
 
-func getActionsSchema() *schema.Schema {
-	enum := make([]validate.EnumOpt, len(pb.Action_Kind_name))
-	for v, n := range pb.Action_Kind_name {
-		enum[v] = validate.EnumOpt{Name: n, Value: float64(v)}
+func getEnumOpt(opts map[int32]string) []validate.EnumOpt {
+	keys := make([]string, 0, len(opts))
+	for _, k := range opts {
+		keys = append(keys, k)
 	}
+	sort.Strings(keys)
+
+	enum := make([]validate.EnumOpt, len(opts))
+	for i, n := range keys {
+		enum[i] = validate.EnumOpt{Name: n, Value: float64(i)}
+	}
+	return enum
+}
 
+func getActionsSchema() *schema.Schema {
 	action := schema.New(
 		"extension", field.String(validate.Required()).SetTitle("Расширение").SetTextSearch(true),
 		"action", field.String(validate.Required()).SetTitle("Действия").SetTextSearch(true),
+		"target", field.Number(
+			field.NumberFormatInt,
+			validate.Enum(getEnumOpt(pb.Action_Kind_name)...),
+		).SetTitle("Отображение результата действия").WithUI(&field.UI{Widget: "Select"}),
+		"parent", field.String().SetTitle("Идентификатор родительского действия"),
 		"name", field.String().SetTitle("Название").SetTextSearch(true),
 		"description", field.String().SetTitle("Описание"),
 		"icon", field.String().SetTitle("Название иконки"),
@@ -48,7 +64,7 @@ func getActionsSchema() *schema.Schema {
 			WithUI(&field.UI{Widget: "SelectList"}),
 		"kind", field.Number(
 			field.NumberFormatInt,
-			validate.Enum(enum...),
+			validate.Enum(getEnumOpt(pb.Target_name)...),
 		).SetTitle("Вид").WithUI(&field.UI{Widget: "Select"}),
 		"classes", field.Array(field.String().SetAdditionalValues()).SetTitle("Класс").
 			WithUI(&field.UI{Widget: "SelectList"}).
@@ -62,6 +78,12 @@ func getActionsSchema() *schema.Schema {
 			SetDescription("Выполняется переход пользователя в пользовательском интерфейсе").
 			WithUI(&field.UI{Widget: "Checkbox"}),
 		"navigation_route", field.String().SetTitle("Путь в интерфейсе"),
+		"autorun", field.Bool().SetTitle("Автозапуск").
+			SetDescription("Действие выполняется автоматически каждый раз при загрузке приложения").
+			WithUI(&field.UI{Widget: "Checkbox"}),
+		"confirm", field.Bool().SetTitle("С подтверждением").
+			SetDescription("Пользователь должен подтвердить запуск действия").
+			WithUI(&field.UI{Widget: "Checkbox"}),
 	)
 
 	// Includes
@@ -69,10 +91,10 @@ func getActionsSchema() *schema.Schema {
 		field.Include{Ref: "hoop_item_options", Optional: true},
 	)
 
-	//UI
+	// UI
 	action.Field.UI.ListView = &field.View{Options: map[string]interface{}{
-		"fields":    []string{"action", "name", "extension", "kind"},
-		"sort":      []string{"action"},
+		"fields":    []string{"name", "action", "kind", "target", "updated_at", "updated_by"},
+		"sort":      []string{"name"},
 		"page_size": 50,
 	}}
 
diff --git a/pkg/extension/server.go b/pkg/extension/server.go
index 2d509d76..bb0f097d 100644
--- a/pkg/extension/server.go
+++ b/pkg/extension/server.go
@@ -17,18 +17,19 @@ type Server struct {
 	pb.UnimplementedExtensionServiceServer
 }
 
-func NewServer(svc ...Extension) *Server {
+func NewServer(operation operation.Service, extensions ...Extension) *Server {
 	srv := &Server{
-		extensions: make(map[string]Extension, len(svc)),
+		extensions: make(map[string]Extension, len(extensions)),
+		// todo: нужно как-то неявно создавать и регистрировать сервер операций
+		operations: operation,
 	}
-	for _, s := range svc {
+	for _, s := range extensions {
 		srv.extensions[s.GetDescriptor().Extension] = s
 	}
-	srv.operations = operation.NewDefaultService()
 	return srv
 }
 
-func (s *Server) getExtensions(ctx context.Context, extensions []string) ([]Extension, error) {
+func (s *Server) getExtensions(_ context.Context, extensions []string) ([]Extension, error) {
 	var res []Extension
 	for _, ext := range extensions {
 		e, ok := s.extensions[ext]
@@ -167,3 +168,57 @@ func (s *Server) Stop() error {
 
 	return nil
 }
+
+// --------------
+// Попытки сделать один сервер для расширений и для менеджера
+// --------------
+
+type ExtensionsGetter interface {
+	GetInstalledExtensions(ctx context.Context, extensions ...string) ([]Extension, error)
+}
+
+func NewMultiExtensionsGetter(svc ...Extension) ExtensionsGetter {
+	g := &multiExtensionsGetter{
+		extensions: make(map[string]Extension, len(svc)),
+	}
+	for _, s := range svc {
+		g.extensions[s.GetDescriptor().Extension] = s
+	}
+	return g
+}
+
+type multiExtensionsGetter struct {
+	extensions map[string]Extension
+}
+
+func (g *multiExtensionsGetter) GetInstalledExtensions(_ context.Context, extensions ...string) ([]Extension, error) {
+	var res []Extension
+	if len(extensions) == 0 {
+		for _, e := range g.extensions {
+			res = append(res, e)
+		}
+		return res, nil
+	}
+
+	for _, ext := range extensions {
+		e, ok := g.extensions[ext]
+		if !ok {
+			return nil, errors.Wrap(ErrUnknownExtension, ext)
+		}
+
+		res = append(res, e)
+	}
+	return res, nil
+}
+
+func NewMonoExtensionsGetter(svc Extension) ExtensionsGetter {
+	return &monoExtensionsGetter{extension: svc}
+}
+
+type monoExtensionsGetter struct {
+	extension Extension
+}
+
+func (g *monoExtensionsGetter) GetInstalledExtensions(_ context.Context, _ ...string) ([]Extension, error) {
+	return []Extension{g.extension}, nil
+}
diff --git a/pkg/extension/server_test.go b/pkg/extension/server_test.go
index 9adc8da7..2f19ba57 100644
--- a/pkg/extension/server_test.go
+++ b/pkg/extension/server_test.go
@@ -1,98 +1,109 @@
 package extension
 
+import (
+	"context"
+	"fmt"
+	"strings"
+	"testing"
+
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"git.perx.ru/perxis/perxis-go/pkg/operation"
+	"github.com/stretchr/testify/assert"
+)
+
 // не актуальные тесты
-//func TestGetResults(t *testing.T) {
+// func TestGetResults(t *testing.T) {
 //
-//	getDummyExtension := func(name string, wantErr ...bool) Extension {
-//		ext := &testServerExtension{name: name}
+//		getDummyExtension := func(name string, wantErr ...bool) Extension {
+//			ext := &testServerExtension{name: name}
 //
-//		if len(wantErr) > 0 {
-//			ext.err = errors.WithDetail(errors.New("some err"), "Ошибка")
-//		}
+//			if len(wantErr) > 0 {
+//				ext.err = errors.WithDetail(errors.New("some err"), "Ошибка")
+//			}
 //
-//		return ext
-//	}
+//			return ext
+//		}
 //
-//	tests := []struct {
-//		name       string
-//		services   []Extension
-//		extensions []string
-//		fn         func(svc Extension) error
-//		want       []*RequestResult
-//	}{
-//		{
-//			name:       "one extension without errors",
-//			services:   []Extension{getDummyExtension("a"), getDummyExtension("b")},
-//			extensions: []string{"a"},
-//			fn:         func(svc Extension) error { return nil },
-//			want: []*RequestResult{
-//				{Extension: "a", State: RequestOK},
+//		tests := []struct {
+//			name       string
+//			services   []Extension
+//			extensions []string
+//			fn         func(svc Extension) error
+//			want       []*RequestResult
+//		}{
+//			{
+//				name:       "one extension without errors",
+//				services:   []Extension{getDummyExtension("a"), getDummyExtension("b")},
+//				extensions: []string{"a"},
+//				fn:         func(svc Extension) error { return nil },
+//				want: []*RequestResult{
+//					{Extension: "a", State: RequestOK},
+//				},
 //			},
-//		},
-//		{
-//			name:       "multiple extensions without errors",
-//			services:   []Extension{getDummyExtension("a"), getDummyExtension("b"), getDummyExtension("c")},
-//			extensions: []string{"a", "c"},
-//			fn:         func(svc Extension) error { return nil },
-//			want: []*RequestResult{
-//				{Extension: "a", State: RequestOK},
-//				{Extension: "c", State: RequestOK},
+//			{
+//				name:       "multiple extensions without errors",
+//				services:   []Extension{getDummyExtension("a"), getDummyExtension("b"), getDummyExtension("c")},
+//				extensions: []string{"a", "c"},
+//				fn:         func(svc Extension) error { return nil },
+//				want: []*RequestResult{
+//					{Extension: "a", State: RequestOK},
+//					{Extension: "c", State: RequestOK},
+//				},
 //			},
-//		},
-//		{
-//			name:       "multiple extensions, one returns error",
-//			services:   []Extension{getDummyExtension("a"), getDummyExtension("b"), getDummyExtension("c", true)},
-//			extensions: []string{"a", "c"},
-//			fn:         func(svc Extension) error { return svc.Install(nil, nil) },
-//			want: []*RequestResult{
-//				{Extension: "a", State: RequestOK},
-//				{Extension: "c", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//			{
+//				name:       "multiple extensions, one returns error",
+//				services:   []Extension{getDummyExtension("a"), getDummyExtension("b"), getDummyExtension("c", true)},
+//				extensions: []string{"a", "c"},
+//				fn:         func(svc Extension) error { return svc.Install(nil, nil) },
+//				want: []*RequestResult{
+//					{Extension: "a", State: RequestOK},
+//					{Extension: "c", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//				},
 //			},
-//		},
-//		{
-//			name:       "multiple extensions, all return error",
-//			services:   []Extension{getDummyExtension("a", true), getDummyExtension("b", true), getDummyExtension("c", true)},
-//			extensions: []string{"a", "b", "c"},
-//			fn:         func(svc Extension) error { return svc.Install(nil, nil) },
-//			want: []*RequestResult{
-//				{Extension: "a", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
-//				{Extension: "b", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
-//				{Extension: "c", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//			{
+//				name:       "multiple extensions, all return error",
+//				services:   []Extension{getDummyExtension("a", true), getDummyExtension("b", true), getDummyExtension("c", true)},
+//				extensions: []string{"a", "b", "c"},
+//				fn:         func(svc Extension) error { return svc.Install(nil, nil) },
+//				want: []*RequestResult{
+//					{Extension: "a", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//					{Extension: "b", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//					{Extension: "c", State: RequestError, Error: "some err", Msg: "Ошибка\n"},
+//				},
 //			},
-//		},
-//	}
-//
-//	for _, tt := range tests {
-//		t.Run(tt.name, func(t *testing.T) {
-//			srv := NewServer(tt.services...)
-//			if got := srv.getResults(tt.extensions, tt.fn); !reflect.DeepEqual(got, tt.want) {
-//				t.Errorf("getResults() = %v, want %v", got, tt.want)
-//			}
-//		})
-//	}
-//}
-//
-//// не подходит использование mock.Extension из-за возникающих циклических импортов
-//type testServerExtension struct {
-//	err  error
-//	name string
-//}
+//		}
 //
-//func (t testServerExtension) GetDescriptor() *ExtensionDescriptor {
-//	return &ExtensionDescriptor{
-//		Extension:   t.name,
-//		Title:       strings.ToTitle(t.name),
-//		Description: "test extension",
-//		Version:     "0.0.0",
+//		for _, tt := range tests {
+//			t.Run(tt.name, func(t *testing.T) {
+//				srv := NewServer(tt.services...)
+//				if got := srv.getResults(tt.extensions, tt.fn); !reflect.DeepEqual(got, tt.want) {
+//					t.Errorf("getResults() = %v, want %v", got, tt.want)
+//				}
+//			})
+//		}
 //	}
-//}
 //
-//func (t testServerExtension) Install(ctx context.Context, in *InstallRequest) error     { return t.err }
-//func (t testServerExtension) Check(ctx context.Context, in *CheckRequest) error         { return t.err }
-//func (t testServerExtension) Uninstall(ctx context.Context, in *UninstallRequest) error { return t.err }
-//func (t testServerExtension) Action(ctx context.Context, in *ActionRequest) (*ActionResponse, error) {
-//	return &ActionResponse{}, t.err
-//}
+// не подходит использование mock.Extension из-за возникающих циклических импортов
+type testServerExtension struct {
+	err  error
+	name string
+}
+
+func (t testServerExtension) GetDescriptor() *ExtensionDescriptor {
+	return &ExtensionDescriptor{
+		Extension:   t.name,
+		Title:       strings.ToTitle(t.name),
+		Description: "test extension",
+		Version:     "0.0.0",
+	}
+}
+
+func (t testServerExtension) Install(ctx context.Context, in *InstallRequest) error     { return t.err }
+func (t testServerExtension) Check(ctx context.Context, in *CheckRequest) error         { return t.err }
+func (t testServerExtension) Uninstall(ctx context.Context, in *UninstallRequest) error { return t.err }
+func (t testServerExtension) Action(ctx context.Context, in *ActionRequest) (*ActionResponse, error) {
+	return &ActionResponse{}, t.err
+}
 
 func TestServer_Action(t *testing.T) {
 	getDummyExtension := func(name string, wantErr ...bool) Extension {
@@ -107,14 +118,14 @@ func TestServer_Action(t *testing.T) {
 
 	var tests = []struct {
 		name     string
-		services map[string]Extension
+		services Extension
 		in       *ActionRequest
 		want     *ActionResponse
 		wantErr  string
 	}{
 		{
 			name:     "GRPC",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				Action:  "grpc:///test-extension/test-action",
 				SpaceId: "sp",
@@ -124,7 +135,7 @@ func TestServer_Action(t *testing.T) {
 		},
 		{
 			name:     "invalid schema",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				Action:  "some:///space/env/coll",
 				SpaceId: "sp",
@@ -135,7 +146,7 @@ func TestServer_Action(t *testing.T) {
 		},
 		{
 			name:     "Deprecated call",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				Action:    "test-action",
 				SpaceId:   "sp",
@@ -146,7 +157,7 @@ func TestServer_Action(t *testing.T) {
 		},
 		{
 			name:     "unknown extension",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				Action:  "grpc:///test-extension-2/test-action",
 				SpaceId: "sp",
@@ -157,7 +168,7 @@ func TestServer_Action(t *testing.T) {
 		},
 		{
 			name:     "Deprecated call, without extension",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				Action:  "test-action",
 				SpaceId: "sp",
@@ -168,7 +179,7 @@ func TestServer_Action(t *testing.T) {
 		},
 		{
 			name:     "Deprecated call, without action and extension)",
-			services: map[string]Extension{"test-extension": getDummyExtension("test-extension")},
+			services: getDummyExtension("test-extension"),
 			in: &ActionRequest{
 				SpaceId: "sp",
 				EnvId:   "env",
@@ -180,9 +191,7 @@ func TestServer_Action(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 
-			srv := &Server{
-				services: tt.services,
-			}
+			srv := NewServer(operation.NewDefaultService(), tt.services)
 			got, err := srv.Action(context.Background(), tt.in)
 			if tt.wantErr != "" {
 				assert.EqualErrorf(t, err, tt.wantErr, fmt.Sprintf("Action(%v)", tt.in))
diff --git a/pkg/extension/storage.go b/pkg/extension/storage.go
index 6edb21f5..d6875bfb 100644
--- a/pkg/extension/storage.go
+++ b/pkg/extension/storage.go
@@ -2,18 +2,23 @@ package extension
 
 import (
 	"context"
+	"strings"
 
+	"git.perx.ru/perxis/perxis-go/pkg/collections"
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"git.perx.ru/perxis/perxis-go/pkg/setup"
 	pb "git.perx.ru/perxis/perxis-go/proto/extensions"
 
 	"git.perx.ru/perxis/perxis-go/pkg/content"
 	"git.perx.ru/perxis/perxis-go/pkg/items"
 )
 
-type Status = pb.GetExtensionsResponse_Status
+type Status = pb.GetInstalledExtensionsResponse_Status
 
 // Storage описывает интерфейс хранилища состояний расширений
 type Storage interface {
 	GetStatus(ctx context.Context, spaceID, envID string, extension string) (*Status, error)
+	FindStatuses(ctx context.Context, spaceID, envID string, extensions ...string) ([]*Status, error)
 	SetStatus(ctx context.Context, spaceID, envID string, extension string, status *Status) error
 	DeleteStatus(ctx context.Context, spaceID, envID string, extension string) error
 }
@@ -26,30 +31,70 @@ func NewStorage(content *content.Content) Storage {
 	return &storage{content: content}
 }
 
-// GetStatus возвращает состояние расширения в пространстве
-func (s *storage) GetStatus(ctx context.Context, spaceID, envID string, extension string) (*Status, error) {
-	res, err := s.content.Items.Get(ctx, spaceID, envID, StatusCollectionID, extension)
-
-	if err != nil {
-		return nil, err
+func statusFromItem(extension string, item *items.Item) *Status {
+	if item == nil {
+		return &Status{
+			Extension: extension,
+			Installed: false,
+		}
 	}
 
-	d := res.Data
+	d := item.Data
 
+	title, _ := d["title"].(string)
+	state, _ := d["extension_state"].(int64)
+	ver, _ := d["version"].(string)
 	msg, _ := d["status_msg"].(string)
 	errmsg, _ := d["status_error"].(string)
-	ver, _ := d["version"].(string)
 
 	return &Status{
+		Extension:        extension,
+		Title:            title,
+		State:            State(state),
 		Msg:              msg,
 		Error:            errmsg,
 		Installed:        true,
 		InstalledVersion: ver,
-	}, nil
+	}
+}
+
+// GetStatus возвращает состояние расширения в пространстве
+func (s *storage) GetStatus(ctx context.Context, spaceID, envID string, extension string) (*Status, error) {
+	res, err := s.content.Items.Get(ctx, spaceID, envID, StatusCollectionID, extension)
+	if err != nil && !strings.Contains(err.Error(), "not found") {
+		return nil, err
+	}
+	return statusFromItem(extension, res), nil
+}
+
+// FindStatuses возвращает состояния расширений в пространстве. Если расширение не установлено,
+// возвращается статус с флагом `Installed: false`. Статусы возвращаются в том же порядке, что и
+// переданные расширения
+func (s *storage) FindStatuses(ctx context.Context, spaceID, envID string, extensions ...string) ([]*Status, error) {
+	itms, _, err := s.content.Items.Find(ctx, spaceID, envID, StatusCollectionID, &items.Filter{ID: extensions})
+	if err != nil {
+		return nil, err
+	}
+
+	extensionToItem := make(map[string]*items.Item, len(itms))
+	for _, item := range itms {
+		extensionToItem[item.ID] = item
+	}
+
+	res := make([]*Status, len(extensions))
+	for i, extension := range extensions {
+		res[i] = statusFromItem(extension, extensionToItem[extension])
+	}
+
+	return res, nil
 }
 
 // SetStatus устанавливает состояние расширения в пространстве
 func (s *storage) SetStatus(ctx context.Context, spaceID, envID string, extension string, status *Status) error {
+	if err := s.init(ctx, spaceID, envID); err != nil {
+		return errors.Wrap(err, "prepare collections")
+	}
+
 	item := &items.Item{
 		ID:           extension,
 		SpaceID:      spaceID,
@@ -57,17 +102,20 @@ func (s *storage) SetStatus(ctx context.Context, spaceID, envID string, extensio
 		CollectionID: StatusCollectionID,
 	}
 
+	_ = item.Set("id", extension)
+	_ = item.Set("title", status.Title)
+	_ = item.Set("extension_state", float64(status.State))
 	_ = item.Set("version", status.InstalledVersion)
 	_ = item.Set("status_msg", status.Msg)
 	_ = item.Set("status_error", status.Error)
 
 	i, _ := s.content.Items.Get(ctx, spaceID, envID, StatusCollectionID, extension)
 	if i == nil {
-		_, err := s.content.Items.Create(ctx, i)
+		_, err := s.content.Items.Create(ctx, item)
 		return err
 	}
 
-	return s.content.Items.Update(ctx, i)
+	return s.content.Items.Update(ctx, item)
 }
 
 // DeleteStatus удаляет состояние расширения в пространстве (при удалении расширения)
@@ -80,3 +128,13 @@ func (s *storage) DeleteStatus(ctx context.Context, spaceID, envID string, exten
 	}
 	return s.content.Items.Delete(ctx, item)
 }
+
+func (s *storage) init(ctx context.Context, spaceID, envID string) error {
+	// миграция окружения не должна запуститься, поскольку окружение может быть сломано
+	// расширениями - нужно дать возможность восстановиться
+	stp := setup.NewSetup(s.content, spaceID, envID, nil).AddCollections([]*collections.Collection{
+		NewStatusCollection(spaceID, envID),
+		NewActionsCollection(spaceID, envID),
+	}, setup.SkipMigration())
+	return stp.Install(ctx)
+}
diff --git a/pkg/items/item.go b/pkg/items/item.go
index f0fc8180..b8d577a9 100644
--- a/pkg/items/item.go
+++ b/pkg/items/item.go
@@ -286,6 +286,11 @@ func (i *Item) SetSystemField(field string, value interface{}) error {
 	switch field {
 	case "id":
 		i.ID, ok = value.(string)
+		if !ok {
+			return ErrIncorrectValue
+		}
+		// нужно учитывать, что поле ID может быть в схеме и запрошена установка именно для него
+		return i.setItemData("id", value)
 	case "space_id":
 		i.SpaceID, ok = value.(string)
 	case "env_id":
diff --git a/pkg/operation/operation.go b/pkg/operation/operation.go
index fdecd1ed..5c294b3e 100644
--- a/pkg/operation/operation.go
+++ b/pkg/operation/operation.go
@@ -193,11 +193,11 @@ func (o *Operation) Wait(ctx context.Context, opts ...grpc.CallOption) error {
 	return o.WaitInterval(ctx, DefaultPollInterval, opts...)
 }
 
-// waitInterval ожидает завершения операции с указанным интервалом опроса
+// WaitInterval ожидает завершения операции с указанным интервалом опроса
 func (o *Operation) WaitInterval(ctx context.Context, pollInterval time.Duration, opts ...grpc.CallOption) error {
 	for !o.IsDone() {
 		if err := o.Poll(ctx, opts...); err != nil {
-			return errors.Wrap(err, "operation poll fail")
+			return errors.Wrap(err, "operation poll failed")
 		}
 
 		if o.IsDone() {
diff --git a/pkg/operation/operation_test.go b/pkg/operation/operation_test.go
index 42aa701a..b5973170 100644
--- a/pkg/operation/operation_test.go
+++ b/pkg/operation/operation_test.go
@@ -19,7 +19,7 @@ import (
 
 func TestOperation(t *testing.T) {
 	op := New(&Proto{})
-	assert.NotNil(t, op)
+	require.NotNil(t, op)
 	assert.NotEmpty(t, op.Id())
 	assert.False(t, op.IsExpired())
 	assert.False(t, op.IsDone())
diff --git a/pkg/operation/service.go b/pkg/operation/service.go
index 93de883a..7561b52a 100644
--- a/pkg/operation/service.go
+++ b/pkg/operation/service.go
@@ -41,11 +41,11 @@ type service struct {
 	cleanupInterval time.Duration         // Cleanup interval
 }
 
-func NewService(retention, cleanupPeriod time.Duration) Service {
+func NewService(cleanupInterval time.Duration) Service {
 	return &service{
 		ops:             make(map[string]*Operation),
 		mu:              sync.RWMutex{},
-		cleanupInterval: time.Minute,
+		cleanupInterval: cleanupInterval,
 	}
 }
 
@@ -104,7 +104,7 @@ func (s *service) Get(_ context.Context, id string) (*Operation, error) {
 }
 
 // Cancel отменяет операцию по ее идентификатору
-func (s *service) Cancel(ctx context.Context, id string) (*Operation, error) {
+func (s *service) Cancel(_ context.Context, id string) (*Operation, error) {
 	s.mu.RLock()
 	defer s.mu.Unlock()
 	op, ok := s.ops[id]
diff --git a/pkg/setup/collection.go b/pkg/setup/collection.go
index fcce47d6..14ccdb61 100644
--- a/pkg/setup/collection.go
+++ b/pkg/setup/collection.go
@@ -8,7 +8,6 @@ import (
 	"git.perx.ru/perxis/perxis-go/pkg/collections"
 	"git.perx.ru/perxis/perxis-go/pkg/data"
 	"git.perx.ru/perxis/perxis-go/pkg/errors"
-	"git.perx.ru/perxis/perxis-go/pkg/extension"
 	"git.perx.ru/perxis/perxis-go/pkg/schema"
 	"go.uber.org/zap"
 )
@@ -24,9 +23,10 @@ type UpdateCollectionFn func(s *Setup, exist, new *collections.Collection) (coll
 type DeleteCollectionFn func(s *Setup, col *collections.Collection) (bool, error)
 
 type CollectionConfig struct {
-	collection *collections.Collection
-	UpdateFn   UpdateCollectionFn
-	DeleteFn   DeleteCollectionFn
+	collection    *collections.Collection
+	UpdateFn      UpdateCollectionFn
+	DeleteFn      DeleteCollectionFn
+	SkipMigration bool
 }
 
 func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsOption) CollectionConfig {
@@ -42,6 +42,12 @@ func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsO
 	return c
 }
 
+func SkipMigration() CollectionsOption {
+	return func(c *CollectionConfig) {
+		c.SkipMigration = true
+	}
+}
+
 func OverwriteCollection() CollectionsOption {
 	return func(c *CollectionConfig) {
 		c.UpdateFn = func(s *Setup, old, new *collections.Collection) (*collections.Collection, bool, bool, error) {
@@ -79,7 +85,7 @@ func isMetadataExtensionEqual(s1, s2 *schema.Schema) bool {
 		return false
 	}
 
-	return s1.Metadata[extension.ExtensionMetadataKey] == s2.Metadata[extension.ExtensionMetadataKey]
+	return s1.Metadata["extension"] == s2.Metadata["extension"] // todo: Setup ничего не должен знать про расширения
 }
 
 func DefaultUpdateCollectionStrategy() CollectionsOption {
@@ -128,7 +134,7 @@ func (s *Setup) InstallCollections(ctx context.Context) (err error) {
 			)
 			return errors.WithDetailf(errors.Wrap(err, "failed to install collection"), "Возникла ошибка при настройке коллекции %s(%s)", c.collection.Name, c.collection.ID)
 		}
-		if setSchema {
+		if !c.SkipMigration && setSchema {
 			migrate = true
 		}
 	}
diff --git a/pkg/setup/collection_test.go b/pkg/setup/collection_test.go
index 78f414db..af2352ef 100644
--- a/pkg/setup/collection_test.go
+++ b/pkg/setup/collection_test.go
@@ -10,7 +10,6 @@ import (
 	"git.perx.ru/perxis/perxis-go/pkg/environments"
 	envmocks "git.perx.ru/perxis/perxis-go/pkg/environments/mocks"
 	"git.perx.ru/perxis/perxis-go/pkg/errors"
-	"git.perx.ru/perxis/perxis-go/pkg/extension"
 	"git.perx.ru/perxis/perxis-go/pkg/schema"
 	"git.perx.ru/perxis/perxis-go/pkg/schema/field"
 	"github.com/stretchr/testify/assert"
@@ -109,11 +108,11 @@ func TestSetup_InstallCollections(t *testing.T) {
 		},
 		{
 			name:        "Update extension collection with metadata",
-			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}},
+			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}},
 			collectionsCall: func(svc *mockscollections.Collections) {
-				svc.On("Get", mock.Anything, "sp", "env", "1").Return(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}, nil).Once()
-				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}).Return(nil).Once()
-				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")).Return(nil).Once()
+				svc.On("Get", mock.Anything, "sp", "env", "1").Return(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}, nil).Once()
+				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}).Return(nil).Once()
+				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata("extension", "test-extension")).Return(nil).Once()
 			},
 			envsCall: func(svc *envmocks.Environments) {
 				svc.On("Migrate", mock.Anything, "sp", "env").Return(nil).Once()
@@ -124,7 +123,7 @@ func TestSetup_InstallCollections(t *testing.T) {
 		},
 		{
 			name:        "Fail to update user collection with same id as in extensions collection",
-			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}},
+			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}},
 			collectionsCall: func(svc *mockscollections.Collections) {
 				svc.On("Get", mock.Anything, "sp", "env", "1").Return(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String())}, nil).Once()
 			},
@@ -135,11 +134,11 @@ func TestSetup_InstallCollections(t *testing.T) {
 		},
 		{
 			name:        "Update user collection with same id as in extensions collection with force",
-			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}},
+			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}},
 			collectionsCall: func(svc *mockscollections.Collections) {
 				svc.On("Get", mock.Anything, "sp", "env", "1").Return(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String())}, nil).Once()
-				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}).Return(nil).Once()
-				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")).Return(nil).Once()
+				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}).Return(nil).Once()
+				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata("extension", "test-extension")).Return(nil).Once()
 			},
 			envsCall: func(svc *envmocks.Environments) {
 				svc.On("Migrate", mock.Anything, "sp", "env").Return(nil).Once()
@@ -151,11 +150,11 @@ func TestSetup_InstallCollections(t *testing.T) {
 		},
 		{
 			name:        "Update exist view collection with the same id",
-			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}},
+			collections: []*collections.Collection{{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}},
 			collectionsCall: func(svc *mockscollections.Collections) {
 				svc.On("Get", mock.Anything, "sp", "env", "1").Return(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", View: &collections.View{SpaceID: "sp2", EnvID: environments.DefaultEnvironment, CollectionID: "2"}}, nil).Once()
-				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")}).Return(nil).Once()
-				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test-extension")).Return(nil).Once()
+				svc.On("Update", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "test-extension")}).Return(nil).Once()
+				svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String()).WithMetadata("extension", "test-extension")).Return(nil).Once()
 			},
 			envsCall: func(svc *envmocks.Environments) {
 				svc.On("Migrate", mock.Anything, "sp", "env").Return(nil).Once()
@@ -225,13 +224,13 @@ func Test_isMetadataExtensionEqual(t *testing.T) {
 	}{
 		{
 			"Not equal #1 (no metadata)",
-			schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test"),
+			schema.New("name", field.String()).WithMetadata("extension", "test"),
 			schema.New("name", field.String()),
 			false,
 		},
 		{
 			"Not equal #2 (different metadata)",
-			schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test"),
+			schema.New("name", field.String()).WithMetadata("extension", "test"),
 			schema.New("name", field.String()).WithMetadata("test", "test"),
 			false,
 		},
@@ -243,8 +242,8 @@ func Test_isMetadataExtensionEqual(t *testing.T) {
 		},
 		{
 			"Equal #2 (equal metadata)",
-			schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test"),
-			schema.New("name", field.String()).WithMetadata(extension.ExtensionMetadataKey, "test"),
+			schema.New("name", field.String()).WithMetadata("extension", "test"),
+			schema.New("name", field.String()).WithMetadata("extension", "test"),
 			true,
 		},
 	}
diff --git a/pkg/setup/setup_test.go b/pkg/setup/setup_test.go
index 044d8294..68115888 100644
--- a/pkg/setup/setup_test.go
+++ b/pkg/setup/setup_test.go
@@ -12,7 +12,6 @@ import (
 	"git.perx.ru/perxis/perxis-go/pkg/data"
 	environmentMock "git.perx.ru/perxis/perxis-go/pkg/environments/mocks"
 	"git.perx.ru/perxis/perxis-go/pkg/errors"
-	"git.perx.ru/perxis/perxis-go/pkg/extension"
 	"git.perx.ru/perxis/perxis-go/pkg/items"
 	itemsMock "git.perx.ru/perxis/perxis-go/pkg/items/mocks"
 	"git.perx.ru/perxis/perxis-go/pkg/roles"
@@ -66,7 +65,7 @@ func getActions() []*items.Item {
 			ID:           "act",
 			SpaceID:      spaceID,
 			EnvID:        envID,
-			CollectionID: extension.ActionsCollectionID,
+			CollectionID: "actions",
 			Data: map[string]interface{}{
 				"action":    "act",
 				"name":      "Action",
@@ -705,7 +704,7 @@ func TestSetupInstall(t *testing.T) {
 	//
 	//	itmMock := &itemsMock.Items{}
 	//	for _, act := range getActions() {
-	//		itmMock.On("Get", mock.Anything, spaceID, envID, extension.ActionsCollectionID, act.ID).
+	//		itmMock.On("Get", mock.Anything, spaceID, envID, "actions", act.ID).
 	//			Return(nil, items.ErrNotFound).
 	//			Once()
 	//
@@ -775,7 +774,7 @@ func TestSetupUninstall(t *testing.T) {
 				del := args[1].(*items.Item)
 				require.Equal(t, spaceID, del.SpaceID)
 				require.Equal(t, envID, del.EnvID)
-				require.Equal(t, extension.ActionsCollectionID, del.CollectionID)
+				require.Equal(t, "actions", del.CollectionID)
 				require.Equal(t, act.ID, del.ID)
 			}).
 				Return(nil).
@@ -827,7 +826,7 @@ func TestSetupUninstall(t *testing.T) {
 				del := args[1].(*items.Item)
 				require.Equal(t, spaceID, del.SpaceID)
 				require.Equal(t, envID, del.EnvID)
-				require.Equal(t, extension.ActionsCollectionID, del.CollectionID)
+				require.Equal(t, "actions", del.CollectionID)
 				require.Equal(t, act.ID, del.ID)
 			}).
 				Return(nil).
@@ -863,7 +862,7 @@ func TestSetupUninstall(t *testing.T) {
 
 		itmMock := &itemsMock.Items{}
 		for _, act := range getActions() {
-			itmMock.On("Delete", mock.Anything, spaceID, envID, extension.ActionsCollectionID, act.ID).
+			itmMock.On("Delete", mock.Anything, spaceID, envID, "actions", act.ID).
 				Return(nil).
 				Once()
 		}
@@ -897,7 +896,7 @@ func TestSetupUninstall(t *testing.T) {
 
 		itmMock := &itemsMock.Items{}
 		for _, act := range getActions() {
-			itmMock.On("Delete", mock.Anything, spaceID, envID, extension.ActionsCollectionID, act.ID).
+			itmMock.On("Delete", mock.Anything, spaceID, envID, "actions", act.ID).
 				Return(nil).
 				Once()
 		}
@@ -937,7 +936,7 @@ func TestSetupUninstall(t *testing.T) {
 
 		itmMock := &itemsMock.Items{}
 		for _, act := range getActions() {
-			itmMock.On("Delete", mock.Anything, spaceID, envID, extension.ActionsCollectionID, act.ID).
+			itmMock.On("Delete", mock.Anything, spaceID, envID, "actions", act.ID).
 				Return(nil).
 				Once()
 		}
@@ -984,7 +983,7 @@ func TestSetupUninstall(t *testing.T) {
 				del := args[1].(*items.Item)
 				require.Equal(t, spaceID, del.SpaceID)
 				require.Equal(t, envID, del.EnvID)
-				require.Equal(t, extension.ActionsCollectionID, del.CollectionID)
+				require.Equal(t, "actions", del.CollectionID)
 				require.Equal(t, act.ID, del.ID)
 			}).
 				Return(errors.New("can't delete item")).
@@ -1047,7 +1046,7 @@ func TestSetupCheck(t *testing.T) {
 			mock.Anything,
 			spaceID,
 			envID,
-			extension.ActionsCollectionID,
+			"actions",
 			mock.MatchedBy(func(filter *items.Filter) bool { return data.Contains("act", filter.ID) }),
 			mock.MatchedBy(func(opt *items.FindOptions) bool { return opt.Regular && opt.Hidden && opt.Templates }),
 		).Return(getActions(), 0, nil).Once()
@@ -1219,7 +1218,7 @@ func TestSetupCheck(t *testing.T) {
 	//
 	//	itmMock := &itemsMock.Items{}
 	//	for _, act := range getActions() {
-	//		itmMock.On("Get", mock.Anything, spaceID, envID, extension.ActionsCollectionID, act.ID).
+	//		itmMock.On("Get", mock.Anything, spaceID, envID, "actions", act.ID).
 	//			Return(act, nil).
 	//			Once()
 	//	}
diff --git a/proto/extensions/extension_service.pb.go b/proto/extensions/extension_service.pb.go
index f8f4cd44..69db8cb2 100644
--- a/proto/extensions/extension_service.pb.go
+++ b/proto/extensions/extension_service.pb.go
@@ -144,9 +144,8 @@ type InstallRequest struct {
 
 	Extensions []string `protobuf:"bytes,10000,rep,name=extensions,proto3" json:"extensions,omitempty"`          // Список расширений для установки
 	SpaceId    string   `protobuf:"bytes,10010,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` // Пространство для установки расширений
-	EnvId      string   `protobuf:"bytes,10020,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"`       // Идентификатор окружения для установки (по умолчанию master)
+	EnvId      string   `protobuf:"bytes,10020,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"`       // Идентификатор окружения для установки
 	Force      bool     `protobuf:"varint,10100,opt,name=force,proto3" json:"force,omitempty"`                   // Устанавливать расширения вне зависимости от возможных ошибок
-	Update     bool     `protobuf:"varint,10200,opt,name=update,proto3" json:"update,omitempty"`                 // Установить обновления расширений
 }
 
 func (x *InstallRequest) Reset() {
@@ -181,7 +180,7 @@ func (*InstallRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_extension_service_proto_rawDescGZIP(), []int{0}
 }
 
-func (x *InstallRequest) GetExtensions() []string {
+func (x *InstallRequest) GetInstalledExtensions() []string {
 	if x != nil {
 		return x.Extensions
 	}
@@ -209,13 +208,6 @@ func (x *InstallRequest) GetForce() bool {
 	return false
 }
 
-func (x *InstallRequest) GetUpdate() bool {
-	if x != nil {
-		return x.Update
-	}
-	return false
-}
-
 // UninstallRequest - запрос на удаление расширений
 type UninstallRequest struct {
 	state         protoimpl.MessageState
@@ -225,7 +217,7 @@ type UninstallRequest struct {
 	Extensions []string `protobuf:"bytes,10000,rep,name=extensions,proto3" json:"extensions,omitempty"`          // Список расширений для удаления
 	SpaceId    string   `protobuf:"bytes,10010,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` // Пространство для удаления расширений
 	EnvId      string   `protobuf:"bytes,10020,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"`       // Идентификатор окружения для установки (по умолчанию master)
-	Remove     bool     `protobuf:"varint,10100,opt,name=remove,proto3" json:"remove,omitempty"`                 // Удалить изменения сделанные расширением в пространстве, если возможно
+	Remove     bool     `protobuf:"varint,10100,opt,name=remove,proto3" json:"remove,omitempty"`                 // Удалить сделанные расширением изменения в пространстве, если возможно
 	Force      bool     `protobuf:"varint,10200,opt,name=force,proto3" json:"force,omitempty"`                   // Удалять расширения вне зависимости от возможных ошибок, без учета зависимостей
 }
 
@@ -261,7 +253,7 @@ func (*UninstallRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_extension_service_proto_rawDescGZIP(), []int{1}
 }
 
-func (x *UninstallRequest) GetExtensions() []string {
+func (x *UninstallRequest) GetInstalledExtensions() []string {
 	if x != nil {
 		return x.Extensions
 	}
@@ -339,7 +331,7 @@ func (*CheckRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_extension_service_proto_rawDescGZIP(), []int{2}
 }
 
-func (x *CheckRequest) GetExtensions() []string {
+func (x *CheckRequest) GetInstalledExtensions() []string {
 	if x != nil {
 		return x.Extensions
 	}
@@ -490,92 +482,90 @@ var file_extensions_extension_service_proto_rawDesc = []byte{
 	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
 	0x73, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x22, 0x95, 0x01, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x73, 0x18, 0x90, 0x4e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69,
-	0x64, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49,
-	0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0xa4, 0x4e, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x05, 0x66, 0x6f, 0x72,
-	0x63, 0x65, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65,
-	0x12, 0x17, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0xd8, 0x4f, 0x20, 0x01, 0x28,
-	0x08, 0x52, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x10, 0x55, 0x6e,
-	0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f,
-	0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x90, 0x4e, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12,
-	0x1a, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x9a, 0x4e, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65,
-	0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0xa4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e,
-	0x76, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0xf4, 0x4e,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x15, 0x0a, 0x05,
-	0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0xd8, 0x4f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f,
-	0x72, 0x63, 0x65, 0x22, 0x63, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75,
+	0x6f, 0x22, 0x7c, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75,
 	0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
 	0x73, 0x18, 0x90, 0x4e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
 	0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64,
 	0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64,
 	0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0xa4, 0x4e, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x22, 0xed, 0x04, 0x0a, 0x0e, 0x41, 0x63, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x73,
-	0x74, 0x61, 0x74, 0x65, 0x18, 0x90, 0x4e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x65, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73,
-	0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x9a,
-	0x4e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65,
-	0x74, 0x12, 0x3a, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0xc2, 0x4e, 0x20, 0x01,
-	0x28, 0x0e, 0x32, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
-	0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46,
-	0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x11, 0x0a,
-	0x03, 0x6d, 0x73, 0x67, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67,
-	0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0xfe, 0x4e, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x15, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65,
-	0x18, 0x9c, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x15,
-	0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xd8, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
-	0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x04, 0x6e, 0x65, 0x78, 0x74, 0x18, 0xbc, 0x50,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x6e, 0x65, 0x78, 0x74, 0x12, 0x45,
-	0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0xa0, 0x51, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x28, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65,
-	0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74,
-	0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x73, 0x18, 0xd0, 0x50,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72,
-	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65,
-	0x6e, 0x63, 0x65, 0x52, 0x04, 0x72, 0x65, 0x66, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
-	0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
-	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
-	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
-	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x53, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
-	0x08, 0x0a, 0x04, 0x44, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52,
-	0x4f, 0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10,
-	0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53,
-	0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x53,
-	0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x22, 0x2b, 0x0a, 0x06, 0x46,
-	0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00,
-	0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x4d, 0x4c, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x41,
-	0x52, 0x4b, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x32, 0x89, 0x02, 0x0a, 0x10, 0x45, 0x78, 0x74,
-	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a,
-	0x07, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70,
-	0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x09, 0x55, 0x6e, 0x69,
-	0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70,
-	0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x05, 0x43, 0x68, 0x65,
-	0x63, 0x6b, 0x12, 0x18, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
-	0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63,
-	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
-	0x00, 0x12, 0x41, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x65, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78,
-	0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69,
-	0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
-	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63,
+	0x65, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22,
+	0x97, 0x01, 0x0a, 0x10, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+	0x6e, 0x73, 0x18, 0x90, 0x4e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69,
+	0x64, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49,
+	0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0xa4, 0x4e, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x06, 0x72, 0x65, 0x6d,
+	0x6f, 0x76, 0x65, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f,
+	0x76, 0x65, 0x12, 0x15, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0xd8, 0x4f, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x63, 0x0a, 0x0c, 0x43, 0x68, 0x65,
+	0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x90, 0x4e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a,
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x70,
+	0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
+	0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64,
+	0x18, 0xa4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x22, 0xed,
+	0x04, 0x0a, 0x0e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x37, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x90, 0x4e, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x20, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41,
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x74, 0x61,
+	0x72, 0x67, 0x65, 0x74, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x65, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52,
+	0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x3a, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x74, 0x18, 0xc2, 0x4e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72,
+	0x6d, 0x61, 0x74, 0x12, 0x11, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18,
+	0xfe, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x15, 0x0a,
+	0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x9c, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69,
+	0x6d, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xd8, 0x4f,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x04, 0x6e,
+	0x65, 0x78, 0x74, 0x18, 0xbc, 0x50, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04,
+	0x6e, 0x65, 0x78, 0x74, 0x12, 0x45, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x18, 0xa0, 0x51, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x04, 0x72,
+	0x65, 0x66, 0x73, 0x18, 0xd0, 0x50, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e,
+	0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e,
+	0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x04, 0x72, 0x65, 0x66, 0x73, 0x1a,
+	0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x53, 0x0a, 0x05,
+	0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12,
+	0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45,
+	0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52,
+	0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x41,
+	0x4d, 0x45, 0x54, 0x45, 0x52, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10,
+	0x04, 0x22, 0x2b, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x09, 0x0a, 0x05, 0x50,
+	0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x4d, 0x4c, 0x10, 0x01,
+	0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x41, 0x52, 0x4b, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x32, 0x89,
+	0x02, 0x0a, 0x10, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1a,
+	0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74,
+	0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x6d,
+	0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12,
+	0x3e, 0x0a, 0x09, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x1c, 0x2e, 0x65,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74,
+	0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x6d,
+	0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12,
+	0x36, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x18, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f,
+	0x6e, 0x12, 0x19, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41,
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69,
+	0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73,
+	0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/proto/extensions/manager_service.pb.go b/proto/extensions/manager_service.pb.go
index 7091339c..38161da1 100644
--- a/proto/extensions/manager_service.pb.go
+++ b/proto/extensions/manager_service.pb.go
@@ -47,24 +47,24 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-type SpaceExtensions_State int32
+type State int32
 
 const (
-	SpaceExtensions_PENDING     SpaceExtensions_State = 0
-	SpaceExtensions_INSTALLED   SpaceExtensions_State = 1
-	SpaceExtensions_IN_PROGRESS SpaceExtensions_State = 2
-	SpaceExtensions_FAIL        SpaceExtensions_State = 3
+	State_PENDING     State = 0
+	State_INSTALLED   State = 1
+	State_IN_PROGRESS State = 2
+	State_FAIL        State = 3
 )
 
-// Enum value maps for SpaceExtensions_State.
+// Enum value maps for State.
 var (
-	SpaceExtensions_State_name = map[int32]string{
+	State_name = map[int32]string{
 		0: "PENDING",
 		1: "INSTALLED",
 		2: "IN_PROGRESS",
 		3: "FAIL",
 	}
-	SpaceExtensions_State_value = map[string]int32{
+	State_value = map[string]int32{
 		"PENDING":     0,
 		"INSTALLED":   1,
 		"IN_PROGRESS": 2,
@@ -72,34 +72,36 @@ var (
 	}
 )
 
-func (x SpaceExtensions_State) Enum() *SpaceExtensions_State {
-	p := new(SpaceExtensions_State)
+func (x State) Enum() *State {
+	p := new(State)
 	*p = x
 	return p
 }
 
-func (x SpaceExtensions_State) String() string {
+func (x State) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
 
-func (SpaceExtensions_State) Descriptor() protoreflect.EnumDescriptor {
+func (State) Descriptor() protoreflect.EnumDescriptor {
 	return file_extensions_manager_service_proto_enumTypes[0].Descriptor()
 }
 
-func (SpaceExtensions_State) Type() protoreflect.EnumType {
+func (State) Type() protoreflect.EnumType {
 	return &file_extensions_manager_service_proto_enumTypes[0]
 }
 
-func (x SpaceExtensions_State) Number() protoreflect.EnumNumber {
+func (x State) Number() protoreflect.EnumNumber {
 	return protoreflect.EnumNumber(x)
 }
 
-// Deprecated: Use SpaceExtensions_State.Descriptor instead.
-func (SpaceExtensions_State) EnumDescriptor() ([]byte, []int) {
-	return file_extensions_manager_service_proto_rawDescGZIP(), []int{10, 0}
+// Deprecated: Use State.Descriptor instead.
+func (State) EnumDescriptor() ([]byte, []int) {
+	return file_extensions_manager_service_proto_rawDescGZIP(), []int{0}
 }
 
-type GetExtensionsRequest struct {
+// GetInstalledExtensionsRequest - запрос на получение статуса расширений в пространстве и окружении.
+// Если список расширений в запросе не передан, возвращаются все установленные расширения
+type GetInstalledExtensionsRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
@@ -109,8 +111,8 @@ type GetExtensionsRequest struct {
 	EnvId      string   `protobuf:"bytes,3,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"`       // Идентификатор окружения
 }
 
-func (x *GetExtensionsRequest) Reset() {
-	*x = GetExtensionsRequest{}
+func (x *GetInstalledExtensionsRequest) Reset() {
+	*x = GetInstalledExtensionsRequest{}
 	if protoimpl.UnsafeEnabled {
 		mi := &file_extensions_manager_service_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -118,13 +120,13 @@ func (x *GetExtensionsRequest) Reset() {
 	}
 }
 
-func (x *GetExtensionsRequest) String() string {
+func (x *GetInstalledExtensionsRequest) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*GetExtensionsRequest) ProtoMessage() {}
+func (*GetInstalledExtensionsRequest) ProtoMessage() {}
 
-func (x *GetExtensionsRequest) ProtoReflect() protoreflect.Message {
+func (x *GetInstalledExtensionsRequest) ProtoReflect() protoreflect.Message {
 	mi := &file_extensions_manager_service_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -136,42 +138,43 @@ func (x *GetExtensionsRequest) ProtoReflect() protoreflect.Message {
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use GetExtensionsRequest.ProtoReflect.Descriptor instead.
-func (*GetExtensionsRequest) Descriptor() ([]byte, []int) {
+// Deprecated: Use GetInstalledExtensionsRequest.ProtoReflect.Descriptor instead.
+func (*GetInstalledExtensionsRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{0}
 }
 
-func (x *GetExtensionsRequest) GetExtensions() []string {
+func (x *GetInstalledExtensionsRequest) GetInstalledExtensions() []string {
 	if x != nil {
 		return x.Extensions
 	}
 	return nil
 }
 
-func (x *GetExtensionsRequest) GetSpaceId() string {
+func (x *GetInstalledExtensionsRequest) GetSpaceId() string {
 	if x != nil {
 		return x.SpaceId
 	}
 	return ""
 }
 
-func (x *GetExtensionsRequest) GetEnvId() string {
+func (x *GetInstalledExtensionsRequest) GetEnvId() string {
 	if x != nil {
 		return x.EnvId
 	}
 	return ""
 }
 
-type GetExtensionsResponse struct {
+// GetExtensionResponse - описание расширения
+type GetInstalledExtensionsResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Status []*GetExtensionsResponse_Status `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
+	Status []*GetInstalledExtensionsResponse_Status `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
 }
 
-func (x *GetExtensionsResponse) Reset() {
-	*x = GetExtensionsResponse{}
+func (x *GetInstalledExtensionsResponse) Reset() {
+	*x = GetInstalledExtensionsResponse{}
 	if protoimpl.UnsafeEnabled {
 		mi := &file_extensions_manager_service_proto_msgTypes[1]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -179,13 +182,13 @@ func (x *GetExtensionsResponse) Reset() {
 	}
 }
 
-func (x *GetExtensionsResponse) String() string {
+func (x *GetInstalledExtensionsResponse) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*GetExtensionsResponse) ProtoMessage() {}
+func (*GetInstalledExtensionsResponse) ProtoMessage() {}
 
-func (x *GetExtensionsResponse) ProtoReflect() protoreflect.Message {
+func (x *GetInstalledExtensionsResponse) ProtoReflect() protoreflect.Message {
 	mi := &file_extensions_manager_service_proto_msgTypes[1]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -197,19 +200,19 @@ func (x *GetExtensionsResponse) ProtoReflect() protoreflect.Message {
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use GetExtensionsResponse.ProtoReflect.Descriptor instead.
-func (*GetExtensionsResponse) Descriptor() ([]byte, []int) {
+// Deprecated: Use GetInstalledExtensionsResponse.ProtoReflect.Descriptor instead.
+func (*GetInstalledExtensionsResponse) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{1}
 }
 
-func (x *GetExtensionsResponse) GetStatus() []*GetExtensionsResponse_Status {
+func (x *GetInstalledExtensionsResponse) GetStatus() []*GetInstalledExtensionsResponse_Status {
 	if x != nil {
 		return x.Status
 	}
 	return nil
 }
 
-// ServiceDescription описание расширения (возвращается сервисом при регистрации)
+// ExtensionDescriptor описание расширения (возвращается сервисом при регистрации)
 type ExtensionDescriptor struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -353,7 +356,7 @@ func (*RegisterExtensionsRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{3}
 }
 
-func (x *RegisterExtensionsRequest) GetExtensions() []*ExtensionDescriptor {
+func (x *RegisterExtensionsRequest) GetInstalledExtensions() []*ExtensionDescriptor {
 	if x != nil {
 		return x.Extensions
 	}
@@ -438,7 +441,7 @@ func (*UnregisterExtensionsRequest) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{5}
 }
 
-func (x *UnregisterExtensionsRequest) GetExtensions() []*ExtensionDescriptor {
+func (x *UnregisterExtensionsRequest) GetInstalledExtensions() []*ExtensionDescriptor {
 	if x != nil {
 		return x.Extensions
 	}
@@ -617,27 +620,25 @@ func (*ListExtensionsResponse) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{9}
 }
 
-func (x *ListExtensionsResponse) GetExtensions() []*ExtensionDescriptor {
+func (x *ListExtensionsResponse) GetInstalledExtensions() []*ExtensionDescriptor {
 	if x != nil {
 		return x.Extensions
 	}
 	return nil
 }
 
-// Описание коллекций
-// space_extensions (Пространство/Расширения)
 type SpaceExtensions struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Extension   string                `protobuf:"bytes,10000,opt,name=extension,proto3" json:"extension,omitempty"`
-	Title       string                `protobuf:"bytes,10010,opt,name=title,proto3" json:"title,omitempty"`
-	Version     string                `protobuf:"bytes,10100,opt,name=version,proto3" json:"version,omitempty"`
-	Deps        []string              `protobuf:"bytes,10200,rep,name=deps,proto3" json:"deps,omitempty"`
-	State       SpaceExtensions_State `protobuf:"varint,10300,opt,name=state,proto3,enum=extensions.SpaceExtensions_State" json:"state,omitempty"`
-	StatusError string                `protobuf:"bytes,10400,opt,name=status_error,json=statusError,proto3" json:"status_error,omitempty"` // Сообщение к ошибке
-	StatusMsg   string                `protobuf:"bytes,10500,opt,name=status_msg,json=statusMsg,proto3" json:"status_msg,omitempty"`       // Сообщение к статусу
+	Extension   string   `protobuf:"bytes,10000,opt,name=extension,proto3" json:"extension,omitempty"`
+	Title       string   `protobuf:"bytes,10010,opt,name=title,proto3" json:"title,omitempty"`
+	Version     string   `protobuf:"bytes,10100,opt,name=version,proto3" json:"version,omitempty"`
+	Deps        []string `protobuf:"bytes,10200,rep,name=deps,proto3" json:"deps,omitempty"`
+	State       State    `protobuf:"varint,10300,opt,name=state,proto3,enum=extensions.State" json:"state,omitempty"`
+	StatusError string   `protobuf:"bytes,10400,opt,name=status_error,json=statusError,proto3" json:"status_error,omitempty"` // Сообщение к ошибке
+	StatusMsg   string   `protobuf:"bytes,10500,opt,name=status_msg,json=statusMsg,proto3" json:"status_msg,omitempty"`       // Сообщение к статусу
 }
 
 func (x *SpaceExtensions) Reset() {
@@ -700,11 +701,11 @@ func (x *SpaceExtensions) GetDeps() []string {
 	return nil
 }
 
-func (x *SpaceExtensions) GetState() SpaceExtensions_State {
+func (x *SpaceExtensions) GetState() State {
 	if x != nil {
 		return x.State
 	}
-	return SpaceExtensions_PENDING
+	return State_PENDING
 }
 
 func (x *SpaceExtensions) GetStatusError() string {
@@ -721,12 +722,14 @@ func (x *SpaceExtensions) GetStatusMsg() string {
 	return ""
 }
 
-type GetExtensionsResponse_Status struct {
+type GetInstalledExtensionsResponse_Status struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Extension        string `protobuf:"bytes,10100,opt,name=extension,proto3" json:"extension,omitempty"`                                       // Имя расширения
+	Extension        string `protobuf:"bytes,10100,opt,name=extension,proto3" json:"extension,omitempty"` // Имя расширения
+	Title            string `protobuf:"bytes,10110,opt,name=title,proto3" json:"title,omitempty"`
+	State            State  `protobuf:"varint,10120,opt,name=state,proto3,enum=extensions.State" json:"state,omitempty"`
 	Msg              string `protobuf:"bytes,10200,opt,name=msg,proto3" json:"msg,omitempty"`                                                   // Сообщение
 	Error            string `protobuf:"bytes,10300,opt,name=error,proto3" json:"error,omitempty"`                                               // Ошибка (state == ERROR)
 	NotFound         bool   `protobuf:"varint,10350,opt,name=not_found,json=notFound,proto3" json:"not_found,omitempty"`                        // Расширение не найдено
@@ -736,8 +739,8 @@ type GetExtensionsResponse_Status struct {
 	AvailableVersion string `protobuf:"bytes,10520,opt,name=available_version,json=availableVersion,proto3" json:"available_version,omitempty"` // Доступная версия расширения
 }
 
-func (x *GetExtensionsResponse_Status) Reset() {
-	*x = GetExtensionsResponse_Status{}
+func (x *GetInstalledExtensionsResponse_Status) Reset() {
+	*x = GetInstalledExtensionsResponse_Status{}
 	if protoimpl.UnsafeEnabled {
 		mi := &file_extensions_manager_service_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -745,13 +748,13 @@ func (x *GetExtensionsResponse_Status) Reset() {
 	}
 }
 
-func (x *GetExtensionsResponse_Status) String() string {
+func (x *GetInstalledExtensionsResponse_Status) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*GetExtensionsResponse_Status) ProtoMessage() {}
+func (*GetInstalledExtensionsResponse_Status) ProtoMessage() {}
 
-func (x *GetExtensionsResponse_Status) ProtoReflect() protoreflect.Message {
+func (x *GetInstalledExtensionsResponse_Status) ProtoReflect() protoreflect.Message {
 	mi := &file_extensions_manager_service_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -763,61 +766,75 @@ func (x *GetExtensionsResponse_Status) ProtoReflect() protoreflect.Message {
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use GetExtensionsResponse_Status.ProtoReflect.Descriptor instead.
-func (*GetExtensionsResponse_Status) Descriptor() ([]byte, []int) {
+// Deprecated: Use GetInstalledExtensionsResponse_Status.ProtoReflect.Descriptor instead.
+func (*GetInstalledExtensionsResponse_Status) Descriptor() ([]byte, []int) {
 	return file_extensions_manager_service_proto_rawDescGZIP(), []int{1, 0}
 }
 
-func (x *GetExtensionsResponse_Status) GetExtension() string {
+func (x *GetInstalledExtensionsResponse_Status) GetExtension() string {
 	if x != nil {
 		return x.Extension
 	}
 	return ""
 }
 
-func (x *GetExtensionsResponse_Status) GetMsg() string {
+func (x *GetInstalledExtensionsResponse_Status) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *GetInstalledExtensionsResponse_Status) GetState() State {
+	if x != nil {
+		return x.State
+	}
+	return State_PENDING
+}
+
+func (x *GetInstalledExtensionsResponse_Status) GetMsg() string {
 	if x != nil {
 		return x.Msg
 	}
 	return ""
 }
 
-func (x *GetExtensionsResponse_Status) GetError() string {
+func (x *GetInstalledExtensionsResponse_Status) GetError() string {
 	if x != nil {
 		return x.Error
 	}
 	return ""
 }
 
-func (x *GetExtensionsResponse_Status) GetNotFound() bool {
+func (x *GetInstalledExtensionsResponse_Status) GetNotFound() bool {
 	if x != nil {
 		return x.NotFound
 	}
 	return false
 }
 
-func (x *GetExtensionsResponse_Status) GetInstalled() bool {
+func (x *GetInstalledExtensionsResponse_Status) GetInstalled() bool {
 	if x != nil {
 		return x.Installed
 	}
 	return false
 }
 
-func (x *GetExtensionsResponse_Status) GetUpdateAvailable() bool {
+func (x *GetInstalledExtensionsResponse_Status) GetUpdateAvailable() bool {
 	if x != nil {
 		return x.UpdateAvailable
 	}
 	return false
 }
 
-func (x *GetExtensionsResponse_Status) GetInstalledVersion() string {
+func (x *GetInstalledExtensionsResponse_Status) GetInstalledVersion() string {
 	if x != nil {
 		return x.InstalledVersion
 	}
 	return ""
 }
 
-func (x *GetExtensionsResponse_Status) GetAvailableVersion() string {
+func (x *GetInstalledExtensionsResponse_Status) GetAvailableVersion() string {
 	if x != nil {
 		return x.AvailableVersion
 	}
@@ -829,140 +846,146 @@ var File_extensions_manager_service_proto protoreflect.FileDescriptor
 var file_extensions_manager_service_proto_rawDesc = []byte{
 	0x0a, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6d, 0x61, 0x6e,
 	0x61, 0x67, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x12, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x68,
-	0x0a, 0x14, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f,
-	0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49,
-	0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x22, 0xf2, 0x02, 0x0a, 0x15, 0x47, 0x65, 0x74,
+	0x74, 0x6f, 0x12, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x71,
+	0x0a, 0x1d, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+	0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e,
+	0x76, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49,
+	0x64, 0x22, 0xc5, 0x03, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c,
+	0x65, 0x64, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a,
+	0xd7, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74,
+	0x6c, 0x65, 0x18, 0xfe, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65,
+	0x12, 0x28, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x88, 0x4f, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x11, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x03, 0x6d, 0x73,
+	0x67, 0x18, 0xd8, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x15, 0x0a,
+	0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xbc, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65,
+	0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e,
+	0x64, 0x18, 0xee, 0x50, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x46, 0x6f, 0x75,
+	0x6e, 0x64, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18,
+	0xa0, 0x51, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65,
+	0x64, 0x12, 0x2a, 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x76, 0x61, 0x69,
+	0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x84, 0x52, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2c, 0x0a,
+	0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69,
+	0x6f, 0x6e, 0x18, 0x8e, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61,
+	0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x61,
+	0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x18, 0x98, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62,
+	0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xea, 0x02, 0x0a, 0x13, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
+	0x72, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x90,
+	0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+	0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x07, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x13, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xfe, 0x4e, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x65, 0x70, 0x73, 0x18,
+	0xd8, 0x4f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73, 0x12, 0x10, 0x0a, 0x03,
+	0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x49,
+	0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x2d, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
+	0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+	0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
+	0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5c, 0x0a, 0x19, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
+	0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
 	0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x28, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
-	0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x1a, 0x96, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
-	0x1d, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xf4, 0x4e, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x11,
-	0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0xd8, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73,
-	0x67, 0x12, 0x15, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xbc, 0x50, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f,
-	0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0xee, 0x50, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f,
-	0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c,
-	0x6c, 0x65, 0x64, 0x18, 0xa0, 0x51, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74,
-	0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
-	0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x84, 0x52, 0x20, 0x01, 0x28, 0x08,
-	0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c,
-	0x65, 0x12, 0x2c, 0x0a, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x8e, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69,
-	0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
-	0x2c, 0x0a, 0x11, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72,
-	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x98, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x76, 0x61,
-	0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xea, 0x02,
-	0x0a, 0x13, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x18, 0x90, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x9a, 0x4e,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x64,
-	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa4, 0x4e, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19,
-	0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xf4, 0x4e, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x13, 0x76, 0x65, 0x72,
-	0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
-	0x18, 0xfe, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-	0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x13, 0x0a, 0x04, 0x64,
-	0x65, 0x70, 0x73, 0x18, 0xd8, 0x4f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73,
-	0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75,
-	0x72, 0x6c, 0x12, 0x49, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
-	0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a,
-	0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5c, 0x0a, 0x19, 0x52, 0x65,
-	0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x65, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x65, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69,
-	0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x1b, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69,
-	0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+	0x73, 0x65, 0x22, 0x5e, 0x0a, 0x1b, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
+	0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+	0x6e, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
+	0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x22, 0x34, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74,
+	0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x38, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x20, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x69, 0x6c,
+	0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x16, 0x4c,
+	0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
 	0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x65, 0x78, 0x74, 0x65,
 	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
 	0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69,
-	0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1c,
-	0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28,
-	0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x15,
-	0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22,
-	0x59, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x65, 0x78, 0x74,
-	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
-	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0a,
-	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb5, 0x02, 0x0a, 0x0f, 0x53,
-	0x70, 0x61, 0x63, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d,
-	0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x90, 0x4e, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a,
-	0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
-	0x69, 0x74, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
-	0xf4, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
-	0x13, 0x0a, 0x04, 0x64, 0x65, 0x70, 0x73, 0x18, 0xd8, 0x4f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,
-	0x64, 0x65, 0x70, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0xbc, 0x50,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22,
-	0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xa0,
-	0x51, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x72, 0x72,
-	0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x73, 0x67,
-	0x18, 0x84, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d,
-	0x73, 0x67, 0x22, 0x3e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x50,
-	0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x53, 0x54,
-	0x41, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52,
-	0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c,
-	0x10, 0x03, 0x32, 0xa0, 0x03, 0x0a, 0x17, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65,
-	0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x65, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
-	0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6b, 0x0a, 0x14, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73,
-	0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x27, 0x2e,
-	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67,
-	0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78,
-	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x22, 0x00, 0x12, 0x59, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
-	0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a,
-	0x0d, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20,
-	0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45,
-	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, 0x65,
-	0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72,
-	0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78,
-	0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x74, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
-	0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0f, 0x53, 0x70, 0x61, 0x63, 0x65,
+	0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x90, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x05, 0x74, 0x69, 0x74,
+	0x6c, 0x65, 0x18, 0x9a, 0x4e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65,
+	0x12, 0x19, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xf4, 0x4e, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x13, 0x0a, 0x04, 0x64,
+	0x65, 0x70, 0x73, 0x18, 0xd8, 0x4f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73,
+	0x12, 0x28, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0xbc, 0x50, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x11, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xa0, 0x51, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1e,
+	0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x84, 0x52, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x73, 0x67, 0x2a, 0x3e,
+	0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49,
+	0x4e, 0x47, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45,
+	0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45,
+	0x53, 0x53, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x03, 0x32, 0xbb,
+	0x03, 0x0a, 0x17, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61,
+	0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65, 0x0a, 0x12, 0x52, 0x65,
+	0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x12, 0x25, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65,
+	0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+	0x00, 0x12, 0x6b, 0x0a, 0x14, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x27, 0x2e, 0x65, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
+	0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x28, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59,
+	0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x12, 0x21, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69,
+	0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x71, 0x0a, 0x16, 0x47, 0x65, 0x74,
+	0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+	0x6f, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a,
+	0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x49,
+	0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+	0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38,
+	0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78,
+	0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -980,42 +1003,43 @@ func file_extensions_manager_service_proto_rawDescGZIP() []byte {
 var file_extensions_manager_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_extensions_manager_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
 var file_extensions_manager_service_proto_goTypes = []interface{}{
-	(SpaceExtensions_State)(0),           // 0: extensions.SpaceExtensions.State
-	(*GetExtensionsRequest)(nil),         // 1: extensions.GetExtensionsRequest
-	(*GetExtensionsResponse)(nil),        // 2: extensions.GetExtensionsResponse
-	(*ExtensionDescriptor)(nil),          // 3: extensions.ExtensionDescriptor
-	(*RegisterExtensionsRequest)(nil),    // 4: extensions.RegisterExtensionsRequest
-	(*RegisterExtensionsResponse)(nil),   // 5: extensions.RegisterExtensionsResponse
-	(*UnregisterExtensionsRequest)(nil),  // 6: extensions.UnregisterExtensionsRequest
-	(*UnregisterExtensionsResponse)(nil), // 7: extensions.UnregisterExtensionsResponse
-	(*ListExtensionsFilter)(nil),         // 8: extensions.ListExtensionsFilter
-	(*ListExtensionsRequest)(nil),        // 9: extensions.ListExtensionsRequest
-	(*ListExtensionsResponse)(nil),       // 10: extensions.ListExtensionsResponse
-	(*SpaceExtensions)(nil),              // 11: extensions.SpaceExtensions
-	(*GetExtensionsResponse_Status)(nil), // 12: extensions.GetExtensionsResponse.Status
-	nil,                                  // 13: extensions.ExtensionDescriptor.MetadataEntry
+	(State)(0),                                    // 0: extensions.State
+	(*GetInstalledExtensionsRequest)(nil),         // 1: extensions.GetInstalledExtensionsRequest
+	(*GetInstalledExtensionsResponse)(nil),        // 2: extensions.GetInstalledExtensionsResponse
+	(*ExtensionDescriptor)(nil),                   // 3: extensions.ExtensionDescriptor
+	(*RegisterExtensionsRequest)(nil),             // 4: extensions.RegisterExtensionsRequest
+	(*RegisterExtensionsResponse)(nil),            // 5: extensions.RegisterExtensionsResponse
+	(*UnregisterExtensionsRequest)(nil),           // 6: extensions.UnregisterExtensionsRequest
+	(*UnregisterExtensionsResponse)(nil),          // 7: extensions.UnregisterExtensionsResponse
+	(*ListExtensionsFilter)(nil),                  // 8: extensions.ListExtensionsFilter
+	(*ListExtensionsRequest)(nil),                 // 9: extensions.ListExtensionsRequest
+	(*ListExtensionsResponse)(nil),                // 10: extensions.ListExtensionsResponse
+	(*SpaceExtensions)(nil),                       // 11: extensions.SpaceExtensions
+	(*GetInstalledExtensionsResponse_Status)(nil), // 12: extensions.GetInstalledExtensionsResponse.Status
+	nil, // 13: extensions.ExtensionDescriptor.MetadataEntry
 }
 var file_extensions_manager_service_proto_depIdxs = []int32{
-	12, // 0: extensions.GetExtensionsResponse.status:type_name -> extensions.GetExtensionsResponse.Status
+	12, // 0: extensions.GetInstalledExtensionsResponse.status:type_name -> extensions.GetInstalledExtensionsResponse.Status
 	13, // 1: extensions.ExtensionDescriptor.metadata:type_name -> extensions.ExtensionDescriptor.MetadataEntry
 	3,  // 2: extensions.RegisterExtensionsRequest.extensions:type_name -> extensions.ExtensionDescriptor
 	3,  // 3: extensions.UnregisterExtensionsRequest.extensions:type_name -> extensions.ExtensionDescriptor
 	8,  // 4: extensions.ListExtensionsRequest.filter:type_name -> extensions.ListExtensionsFilter
 	3,  // 5: extensions.ListExtensionsResponse.extensions:type_name -> extensions.ExtensionDescriptor
-	0,  // 6: extensions.SpaceExtensions.state:type_name -> extensions.SpaceExtensions.State
-	4,  // 7: extensions.ExtensionManagerService.RegisterExtensions:input_type -> extensions.RegisterExtensionsRequest
-	6,  // 8: extensions.ExtensionManagerService.UnregisterExtensions:input_type -> extensions.UnregisterExtensionsRequest
-	9,  // 9: extensions.ExtensionManagerService.ListExtensions:input_type -> extensions.ListExtensionsRequest
-	1,  // 10: extensions.ExtensionManagerService.GetExtensions:input_type -> extensions.GetExtensionsRequest
-	5,  // 11: extensions.ExtensionManagerService.RegisterExtensions:output_type -> extensions.RegisterExtensionsResponse
-	7,  // 12: extensions.ExtensionManagerService.UnregisterExtensions:output_type -> extensions.UnregisterExtensionsResponse
-	10, // 13: extensions.ExtensionManagerService.ListExtensions:output_type -> extensions.ListExtensionsResponse
-	2,  // 14: extensions.ExtensionManagerService.GetExtensions:output_type -> extensions.GetExtensionsResponse
-	11, // [11:15] is the sub-list for method output_type
-	7,  // [7:11] is the sub-list for method input_type
-	7,  // [7:7] is the sub-list for extension type_name
-	7,  // [7:7] is the sub-list for extension extendee
-	0,  // [0:7] is the sub-list for field type_name
+	0,  // 6: extensions.SpaceExtensions.state:type_name -> extensions.State
+	0,  // 7: extensions.GetInstalledExtensionsResponse.Status.state:type_name -> extensions.State
+	4,  // 8: extensions.ExtensionManagerService.RegisterExtensions:input_type -> extensions.RegisterExtensionsRequest
+	6,  // 9: extensions.ExtensionManagerService.UnregisterExtensions:input_type -> extensions.UnregisterExtensionsRequest
+	9,  // 10: extensions.ExtensionManagerService.ListExtensions:input_type -> extensions.ListExtensionsRequest
+	1,  // 11: extensions.ExtensionManagerService.GetInstalledExtensions:input_type -> extensions.GetInstalledExtensionsRequest
+	5,  // 12: extensions.ExtensionManagerService.RegisterExtensions:output_type -> extensions.RegisterExtensionsResponse
+	7,  // 13: extensions.ExtensionManagerService.UnregisterExtensions:output_type -> extensions.UnregisterExtensionsResponse
+	10, // 14: extensions.ExtensionManagerService.ListExtensions:output_type -> extensions.ListExtensionsResponse
+	2,  // 15: extensions.ExtensionManagerService.GetInstalledExtensions:output_type -> extensions.GetInstalledExtensionsResponse
+	12, // [12:16] is the sub-list for method output_type
+	8,  // [8:12] is the sub-list for method input_type
+	8,  // [8:8] is the sub-list for extension type_name
+	8,  // [8:8] is the sub-list for extension extendee
+	0,  // [0:8] is the sub-list for field type_name
 }
 
 func init() { file_extensions_manager_service_proto_init() }
@@ -1025,7 +1049,7 @@ func file_extensions_manager_service_proto_init() {
 	}
 	if !protoimpl.UnsafeEnabled {
 		file_extensions_manager_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*GetExtensionsRequest); i {
+			switch v := v.(*GetInstalledExtensionsRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1037,7 +1061,7 @@ func file_extensions_manager_service_proto_init() {
 			}
 		}
 		file_extensions_manager_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*GetExtensionsResponse); i {
+			switch v := v.(*GetInstalledExtensionsResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1157,7 +1181,7 @@ func file_extensions_manager_service_proto_init() {
 			}
 		}
 		file_extensions_manager_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*GetExtensionsResponse_Status); i {
+			switch v := v.(*GetInstalledExtensionsResponse_Status); i {
 			case 0:
 				return &v.state
 			case 1:
diff --git a/proto/extensions/manager_service_grpc.pb.go b/proto/extensions/manager_service_grpc.pb.go
index 5d83652f..182bb41d 100644
--- a/proto/extensions/manager_service_grpc.pb.go
+++ b/proto/extensions/manager_service_grpc.pb.go
@@ -46,10 +46,10 @@ import (
 const _ = grpc.SupportPackageIsVersion7
 
 const (
-	ExtensionManagerService_RegisterExtensions_FullMethodName   = "/extensions.ExtensionManagerService/RegisterExtensions"
-	ExtensionManagerService_UnregisterExtensions_FullMethodName = "/extensions.ExtensionManagerService/UnregisterExtensions"
-	ExtensionManagerService_ListExtensions_FullMethodName       = "/extensions.ExtensionManagerService/ListExtensions"
-	ExtensionManagerService_GetExtensions_FullMethodName        = "/extensions.ExtensionManagerService/GetExtensions"
+	ExtensionManagerService_RegisterExtensions_FullMethodName     = "/extensions.ExtensionManagerService/RegisterExtensions"
+	ExtensionManagerService_UnregisterExtensions_FullMethodName   = "/extensions.ExtensionManagerService/UnregisterExtensions"
+	ExtensionManagerService_ListExtensions_FullMethodName         = "/extensions.ExtensionManagerService/ListExtensions"
+	ExtensionManagerService_GetInstalledExtensions_FullMethodName = "/extensions.ExtensionManagerService/GetInstalledExtensions"
 )
 
 // ExtensionManagerServiceClient is the client API for ExtensionManagerService service.
@@ -58,22 +58,22 @@ const (
 type ExtensionManagerServiceClient interface {
 	// ##  Регистрация расширений
 	//
-	// Регистрация\Дерегистрация происходить через сервис менеджера расширений (Extension Manager). В процессе регистрации сервис сообщает
+	// Регистрация\Дерегистрация происходит через сервис менеджера расширений (Extension Manager). В процессе регистрации сервис сообщает
 	// о поддерживаемых сервисом действиях (Actions) и версии сервиса и зависимостях:
-	// 1. Действия (Actions) - перечень действия которые обрабатываются сервисом. Включает в себя как системные действия,
-	// так и пользовательские, которые могут быть использованы в интерфейсе;
+	// ~~1. Действия (Actions) - перечень действия которые обрабатываются сервисом. Включает в себя как системные действия,
+	// так и пользовательские, которые могут быть использованы в интерфейсе;~~
 	// 2. Имя сервиса/расширения - название сервиса внутри системы;
 	// 3. Версия сервиса - сервис сообщает текущую версию сервиса. Контроллер сообщает пользователю о возможности обновления
 	// расширения при смене версии;
 	// 4. Описание версии - содержит информацию об изменениях в последних версиях расширения;
 	// 5. Зависимости - перечень расширений которые необходимы сервису для функционирования. При установке сервиса
-	// все расширения от которых он зависит, будут так же установлены.
+	// все расширения, от которых он зависит, будут также установлены.
 	RegisterExtensions(ctx context.Context, in *RegisterExtensionsRequest, opts ...grpc.CallOption) (*RegisterExtensionsResponse, error)
 	UnregisterExtensions(ctx context.Context, in *UnregisterExtensionsRequest, opts ...grpc.CallOption) (*UnregisterExtensionsResponse, error)
 	// Получить список зарегистрированных сервисов
 	ListExtensions(ctx context.Context, in *ListExtensionsRequest, opts ...grpc.CallOption) (*ListExtensionsResponse, error)
-	// GetExtensionStatus - получить статус расширения
-	GetExtensions(ctx context.Context, in *GetExtensionsRequest, opts ...grpc.CallOption) (*GetExtensionsResponse, error)
+	// GetInstalledExtensions - получить статус расширения
+	GetInstalledExtensions(ctx context.Context, in *GetInstalledExtensionsRequest, opts ...grpc.CallOption) (*GetInstalledExtensionsResponse, error)
 }
 
 type extensionManagerServiceClient struct {
@@ -111,9 +111,9 @@ func (c *extensionManagerServiceClient) ListExtensions(ctx context.Context, in *
 	return out, nil
 }
 
-func (c *extensionManagerServiceClient) GetExtensions(ctx context.Context, in *GetExtensionsRequest, opts ...grpc.CallOption) (*GetExtensionsResponse, error) {
-	out := new(GetExtensionsResponse)
-	err := c.cc.Invoke(ctx, ExtensionManagerService_GetExtensions_FullMethodName, in, out, opts...)
+func (c *extensionManagerServiceClient) GetInstalledExtensions(ctx context.Context, in *GetInstalledExtensionsRequest, opts ...grpc.CallOption) (*GetInstalledExtensionsResponse, error) {
+	out := new(GetInstalledExtensionsResponse)
+	err := c.cc.Invoke(ctx, ExtensionManagerService_GetInstalledExtensions_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -126,22 +126,22 @@ func (c *extensionManagerServiceClient) GetExtensions(ctx context.Context, in *G
 type ExtensionManagerServiceServer interface {
 	// ##  Регистрация расширений
 	//
-	// Регистрация\Дерегистрация происходить через сервис менеджера расширений (Extension Manager). В процессе регистрации сервис сообщает
+	// Регистрация\Дерегистрация происходит через сервис менеджера расширений (Extension Manager). В процессе регистрации сервис сообщает
 	// о поддерживаемых сервисом действиях (Actions) и версии сервиса и зависимостях:
-	// 1. Действия (Actions) - перечень действия которые обрабатываются сервисом. Включает в себя как системные действия,
-	// так и пользовательские, которые могут быть использованы в интерфейсе;
+	// ~~1. Действия (Actions) - перечень действия которые обрабатываются сервисом. Включает в себя как системные действия,
+	// так и пользовательские, которые могут быть использованы в интерфейсе;~~
 	// 2. Имя сервиса/расширения - название сервиса внутри системы;
 	// 3. Версия сервиса - сервис сообщает текущую версию сервиса. Контроллер сообщает пользователю о возможности обновления
 	// расширения при смене версии;
 	// 4. Описание версии - содержит информацию об изменениях в последних версиях расширения;
 	// 5. Зависимости - перечень расширений которые необходимы сервису для функционирования. При установке сервиса
-	// все расширения от которых он зависит, будут так же установлены.
+	// все расширения, от которых он зависит, будут также установлены.
 	RegisterExtensions(context.Context, *RegisterExtensionsRequest) (*RegisterExtensionsResponse, error)
 	UnregisterExtensions(context.Context, *UnregisterExtensionsRequest) (*UnregisterExtensionsResponse, error)
 	// Получить список зарегистрированных сервисов
 	ListExtensions(context.Context, *ListExtensionsRequest) (*ListExtensionsResponse, error)
-	// GetExtensionStatus - получить статус расширения
-	GetExtensions(context.Context, *GetExtensionsRequest) (*GetExtensionsResponse, error)
+	// GetInstalledExtensions - получить статус расширения
+	GetInstalledExtensions(context.Context, *GetInstalledExtensionsRequest) (*GetInstalledExtensionsResponse, error)
 	mustEmbedUnimplementedExtensionManagerServiceServer()
 }
 
@@ -158,8 +158,8 @@ func (UnimplementedExtensionManagerServiceServer) UnregisterExtensions(context.C
 func (UnimplementedExtensionManagerServiceServer) ListExtensions(context.Context, *ListExtensionsRequest) (*ListExtensionsResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ListExtensions not implemented")
 }
-func (UnimplementedExtensionManagerServiceServer) GetExtensions(context.Context, *GetExtensionsRequest) (*GetExtensionsResponse, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method GetExtensions not implemented")
+func (UnimplementedExtensionManagerServiceServer) GetInstalledExtensions(context.Context, *GetInstalledExtensionsRequest) (*GetInstalledExtensionsResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetInstalledExtensions not implemented")
 }
 func (UnimplementedExtensionManagerServiceServer) mustEmbedUnimplementedExtensionManagerServiceServer() {
 }
@@ -229,20 +229,20 @@ func _ExtensionManagerService_ListExtensions_Handler(srv interface{}, ctx contex
 	return interceptor(ctx, in, info, handler)
 }
 
-func _ExtensionManagerService_GetExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(GetExtensionsRequest)
+func _ExtensionManagerService_GetInstalledExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetInstalledExtensionsRequest)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
 	if interceptor == nil {
-		return srv.(ExtensionManagerServiceServer).GetExtensions(ctx, in)
+		return srv.(ExtensionManagerServiceServer).GetInstalledExtensions(ctx, in)
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: ExtensionManagerService_GetExtensions_FullMethodName,
+		FullMethod: ExtensionManagerService_GetInstalledExtensions_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(ExtensionManagerServiceServer).GetExtensions(ctx, req.(*GetExtensionsRequest))
+		return srv.(ExtensionManagerServiceServer).GetInstalledExtensions(ctx, req.(*GetInstalledExtensionsRequest))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -267,8 +267,8 @@ var ExtensionManagerService_ServiceDesc = grpc.ServiceDesc{
 			Handler:    _ExtensionManagerService_ListExtensions_Handler,
 		},
 		{
-			MethodName: "GetExtensions",
-			Handler:    _ExtensionManagerService_GetExtensions_Handler,
+			MethodName: "GetInstalledExtensions",
+			Handler:    _ExtensionManagerService_GetInstalledExtensions_Handler,
 		},
 	},
 	Streams:  []grpc.StreamDesc{},
-- 
GitLab