chore: checkpoint all working changes

This commit is contained in:
Alex Dunmow 2026-09-05 21:14:15 +08:00
parent 2b015a56d5
commit 3e8444cc52
7 changed files with 2044 additions and 465 deletions

View File

@ -1145,11 +1145,14 @@ func writeMod(path string, m *core.ModFile) error {
b.WriteString("sitemap = true\n")
}
if m.Compatibility != nil &&
(m.Compatibility.BlockCore != "" || m.Compatibility.AdminAPI != "") {
(m.Compatibility.BlockCore != "" || m.Compatibility.PluginSDK != "" || m.Compatibility.AdminAPI != "") {
b.WriteString("\n[compatibility]\n")
if m.Compatibility.BlockCore != "" {
fmt.Fprintf(&b, "block_core = %q\n", m.Compatibility.BlockCore)
}
if m.Compatibility.PluginSDK != "" {
fmt.Fprintf(&b, "plugin_sdk = %q\n", m.Compatibility.PluginSDK)
}
if m.Compatibility.AdminAPI != "" {
fmt.Fprintf(&b, "admin_api = %q\n", m.Compatibility.AdminAPI)
}

View File

@ -373,14 +373,14 @@ func TestWriteMod_CompatibilityFields(t *testing.T) {
}{
{
name: "admin api only",
compat: &core.ModCompat{AdminAPI: ">=0.1.2"},
want: []string{"[compatibility]", `admin_api = ">=0.1.2"`},
compat: &core.ModCompat{PluginSDK: ">=0.3.7", AdminAPI: ">=0.1.2"},
want: []string{"[compatibility]", `plugin_sdk = ">=0.3.7"`, `admin_api = ">=0.1.2"`},
doNotWant: []string{"block_core"},
},
{
name: "empty compatibility omitted",
compat: &core.ModCompat{},
doNotWant: []string{"[compatibility]", "block_core", "admin_api"},
doNotWant: []string{"[compatibility]", "block_core", "plugin_sdk", "admin_api"},
},
}
@ -438,6 +438,7 @@ func TestWriteMod_RoundTripsFirstClassFields(t *testing.T) {
},
Compatibility: &core.ModCompat{
BlockCore: ">=0.3.4",
PluginSDK: ">=0.3.7 <0.4.0",
AdminAPI: ">=0.1.2",
},
}
@ -475,6 +476,9 @@ func TestWriteMod_RoundTripsFirstClassFields(t *testing.T) {
if back.Compatibility.BlockCore != ">=0.3.4" {
t.Errorf("block_core not preserved: %q\n%s", back.Compatibility.BlockCore, data)
}
if back.Compatibility.PluginSDK != ">=0.3.7 <0.4.0" {
t.Errorf("plugin_sdk not preserved: %q\n%s", back.Compatibility.PluginSDK, data)
}
if back.Compatibility.AdminAPI != ">=0.1.2" {
t.Errorf("admin_api not preserved: %q\n%s", back.Compatibility.AdminAPI, data)
}

5
go.mod
View File

@ -4,8 +4,8 @@ go 1.26.4
require (
connectrpc.com/connect v1.20.0
git.dev.alexdunmow.com/block/core v0.18.2
git.dev.alexdunmow.com/block/pluginsdk v0.3.6
git.dev.alexdunmow.com/block/core v0.20.6
git.dev.alexdunmow.com/block/pluginsdk v0.3.7
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc
github.com/chromedp/chromedp v0.15.1
github.com/klauspost/compress v1.18.6
@ -28,6 +28,7 @@ require (
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.10.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.16.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
golang.org/x/mod v0.37.0 // indirect
golang.org/x/net v0.56.0 // indirect

12
go.sum
View File

@ -1,9 +1,9 @@
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
git.dev.alexdunmow.com/block/core v0.18.2 h1:+3OfZ424yoc1k1CucXYARk8TBkh8Z693HRkhf5Ci2wU=
git.dev.alexdunmow.com/block/core v0.18.2/go.mod h1:GGuUu826AoJepC/hKLGJ7BX3PQaDss9ueCT0se6Ao2w=
git.dev.alexdunmow.com/block/pluginsdk v0.3.6 h1:wK5gUAmK1gFrCWLqR4zRaq+aSAPgNmpTKHDK8nPX4OI=
git.dev.alexdunmow.com/block/pluginsdk v0.3.6/go.mod h1:Z+eG+WZxAP0jfreLqlGcc0kkWKt8RWevzWyWn8d+dhM=
git.dev.alexdunmow.com/block/core v0.20.6 h1:/f6zP1SKz44ftE5hVDOU4hJvl6TLz3vufGSkqvc2cSg=
git.dev.alexdunmow.com/block/core v0.20.6/go.mod h1:G3MNnwiM4i9roLamhs9DAlVO2mXiYAlTRQoHPpw1AmI=
git.dev.alexdunmow.com/block/pluginsdk v0.3.7 h1:PUT1YElhXre43m1UejDabSqRPAnx1BV7BEWKpG++7Rs=
git.dev.alexdunmow.com/block/pluginsdk v0.3.7/go.mod h1:Z+eG+WZxAP0jfreLqlGcc0kkWKt8RWevzWyWn8d+dhM=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc h1:wkN/LMi5vc60pBRWx6qpbk/aEvq3/ZVNpnMvsw8PVVU=
@ -51,8 +51,8 @@ github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhA
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc=
github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=

View File

@ -99,6 +99,9 @@ const (
// PluginRegistryServiceResolveInstallForInstanceProcedure is the fully-qualified name of the
// PluginRegistryService's ResolveInstallForInstance RPC.
PluginRegistryServiceResolveInstallForInstanceProcedure = "/orchestrator.v1.PluginRegistryService/ResolveInstallForInstance"
// PluginRegistryServiceConfirmPluginInstallForInstanceProcedure is the fully-qualified name of the
// PluginRegistryService's ConfirmPluginInstallForInstance RPC.
PluginRegistryServiceConfirmPluginInstallForInstanceProcedure = "/orchestrator.v1.PluginRegistryService/ConfirmPluginInstallForInstance"
// PluginModerationServiceListPendingReviewsProcedure is the fully-qualified name of the
// PluginModerationService's ListPendingReviews RPC.
PluginModerationServiceListPendingReviewsProcedure = "/orchestrator.v1.PluginModerationService/ListPendingReviews"
@ -111,6 +114,21 @@ const (
// PluginModerationServiceRequestChangesProcedure is the fully-qualified name of the
// PluginModerationService's RequestChanges RPC.
PluginModerationServiceRequestChangesProcedure = "/orchestrator.v1.PluginModerationService/RequestChanges"
// PluginModerationServiceUnpublishPluginProcedure is the fully-qualified name of the
// PluginModerationService's UnpublishPlugin RPC.
PluginModerationServiceUnpublishPluginProcedure = "/orchestrator.v1.PluginModerationService/UnpublishPlugin"
// PluginModerationServiceTakedownPluginProcedure is the fully-qualified name of the
// PluginModerationService's TakedownPlugin RPC.
PluginModerationServiceTakedownPluginProcedure = "/orchestrator.v1.PluginModerationService/TakedownPlugin"
// PluginModerationServiceRestorePluginProcedure is the fully-qualified name of the
// PluginModerationService's RestorePlugin RPC.
PluginModerationServiceRestorePluginProcedure = "/orchestrator.v1.PluginModerationService/RestorePlugin"
// PluginModerationServiceYankVersionProcedure is the fully-qualified name of the
// PluginModerationService's YankVersion RPC.
PluginModerationServiceYankVersionProcedure = "/orchestrator.v1.PluginModerationService/YankVersion"
// PluginModerationServiceDeletePublicPluginProcedure is the fully-qualified name of the
// PluginModerationService's DeletePublicPlugin RPC.
PluginModerationServiceDeletePublicPluginProcedure = "/orchestrator.v1.PluginModerationService/DeletePublicPlugin"
// PluginModerationServiceListFlaggedReviewsProcedure is the fully-qualified name of the
// PluginModerationService's ListFlaggedReviews RPC.
PluginModerationServiceListFlaggedReviewsProcedure = "/orchestrator.v1.PluginModerationService/ListFlaggedReviews"
@ -120,6 +138,15 @@ const (
// PluginModerationServiceSoftDeleteReplyProcedure is the fully-qualified name of the
// PluginModerationService's SoftDeleteReply RPC.
PluginModerationServiceSoftDeleteReplyProcedure = "/orchestrator.v1.PluginModerationService/SoftDeleteReply"
// PluginModerationServiceCreateCategoryProcedure is the fully-qualified name of the
// PluginModerationService's CreateCategory RPC.
PluginModerationServiceCreateCategoryProcedure = "/orchestrator.v1.PluginModerationService/CreateCategory"
// PluginModerationServiceUpdateCategoryProcedure is the fully-qualified name of the
// PluginModerationService's UpdateCategory RPC.
PluginModerationServiceUpdateCategoryProcedure = "/orchestrator.v1.PluginModerationService/UpdateCategory"
// PluginModerationServiceDeleteCategoryProcedure is the fully-qualified name of the
// PluginModerationService's DeleteCategory RPC.
PluginModerationServiceDeleteCategoryProcedure = "/orchestrator.v1.PluginModerationService/DeleteCategory"
// PluginGalleryServiceListScreenshotsProcedure is the fully-qualified name of the
// PluginGalleryService's ListScreenshots RPC.
PluginGalleryServiceListScreenshotsProcedure = "/orchestrator.v1.PluginGalleryService/ListScreenshots"
@ -353,6 +380,7 @@ type PluginRegistryServiceClient interface {
// required (the calling instance, not a user, is the trust unit).
ListPrivatePluginsForInstance(context.Context, *connect.Request[v1.ListPrivatePluginsForInstanceRequest]) (*connect.Response[v1.ListPrivatePluginsResponse], error)
ResolveInstallForInstance(context.Context, *connect.Request[v1.ResolveInstallForInstanceRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
ConfirmPluginInstallForInstance(context.Context, *connect.Request[v1.ConfirmPluginInstallForInstanceRequest]) (*connect.Response[v1.ConfirmPluginInstallForInstanceResponse], error)
}
// NewPluginRegistryServiceClient constructs a client for the orchestrator.v1.PluginRegistryService
@ -450,25 +478,32 @@ func NewPluginRegistryServiceClient(httpClient connect.HTTPClient, baseURL strin
connect.WithSchema(pluginRegistryServiceMethods.ByName("ResolveInstallForInstance")),
connect.WithClientOptions(opts...),
),
confirmPluginInstallForInstance: connect.NewClient[v1.ConfirmPluginInstallForInstanceRequest, v1.ConfirmPluginInstallForInstanceResponse](
httpClient,
baseURL+PluginRegistryServiceConfirmPluginInstallForInstanceProcedure,
connect.WithSchema(pluginRegistryServiceMethods.ByName("ConfirmPluginInstallForInstance")),
connect.WithClientOptions(opts...),
),
}
}
// pluginRegistryServiceClient implements PluginRegistryServiceClient.
type pluginRegistryServiceClient struct {
createPlugin *connect.Client[v1.CreatePluginRequest, v1.CreatePluginResponse]
getPlugin *connect.Client[v1.GetPluginRequest, v1.GetPluginResponse]
listPlugins *connect.Client[v1.ListPluginsRequest, v1.ListPluginsResponse]
getVersion *connect.Client[v1.GetVersionRequest, v1.GetVersionResponse]
resolveInstall *connect.Client[v1.ResolveInstallRequest, v1.ResolveInstallResponse]
listCategories *connect.Client[v1.ListCategoriesRequest, v1.ListCategoriesResponse]
listTags *connect.Client[v1.ListTagsRequest, v1.ListTagsResponse]
submitForReview *connect.Client[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse]
listPrivatePlugins *connect.Client[v1.ListPrivatePluginsRequest, v1.ListPrivatePluginsResponse]
deletePrivatePlugin *connect.Client[v1.DeletePrivatePluginRequest, v1.DeletePrivatePluginResponse]
deletePrivatePluginVersion *connect.Client[v1.DeletePrivatePluginVersionRequest, v1.DeletePrivatePluginVersionResponse]
listPrivatePluginInstallSites *connect.Client[v1.ListPrivatePluginInstallSitesRequest, v1.ListPrivatePluginInstallSitesResponse]
listPrivatePluginsForInstance *connect.Client[v1.ListPrivatePluginsForInstanceRequest, v1.ListPrivatePluginsResponse]
resolveInstallForInstance *connect.Client[v1.ResolveInstallForInstanceRequest, v1.ResolveInstallResponse]
createPlugin *connect.Client[v1.CreatePluginRequest, v1.CreatePluginResponse]
getPlugin *connect.Client[v1.GetPluginRequest, v1.GetPluginResponse]
listPlugins *connect.Client[v1.ListPluginsRequest, v1.ListPluginsResponse]
getVersion *connect.Client[v1.GetVersionRequest, v1.GetVersionResponse]
resolveInstall *connect.Client[v1.ResolveInstallRequest, v1.ResolveInstallResponse]
listCategories *connect.Client[v1.ListCategoriesRequest, v1.ListCategoriesResponse]
listTags *connect.Client[v1.ListTagsRequest, v1.ListTagsResponse]
submitForReview *connect.Client[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse]
listPrivatePlugins *connect.Client[v1.ListPrivatePluginsRequest, v1.ListPrivatePluginsResponse]
deletePrivatePlugin *connect.Client[v1.DeletePrivatePluginRequest, v1.DeletePrivatePluginResponse]
deletePrivatePluginVersion *connect.Client[v1.DeletePrivatePluginVersionRequest, v1.DeletePrivatePluginVersionResponse]
listPrivatePluginInstallSites *connect.Client[v1.ListPrivatePluginInstallSitesRequest, v1.ListPrivatePluginInstallSitesResponse]
listPrivatePluginsForInstance *connect.Client[v1.ListPrivatePluginsForInstanceRequest, v1.ListPrivatePluginsResponse]
resolveInstallForInstance *connect.Client[v1.ResolveInstallForInstanceRequest, v1.ResolveInstallResponse]
confirmPluginInstallForInstance *connect.Client[v1.ConfirmPluginInstallForInstanceRequest, v1.ConfirmPluginInstallForInstanceResponse]
}
// CreatePlugin calls orchestrator.v1.PluginRegistryService.CreatePlugin.
@ -544,6 +579,12 @@ func (c *pluginRegistryServiceClient) ResolveInstallForInstance(ctx context.Cont
return c.resolveInstallForInstance.CallUnary(ctx, req)
}
// ConfirmPluginInstallForInstance calls
// orchestrator.v1.PluginRegistryService.ConfirmPluginInstallForInstance.
func (c *pluginRegistryServiceClient) ConfirmPluginInstallForInstance(ctx context.Context, req *connect.Request[v1.ConfirmPluginInstallForInstanceRequest]) (*connect.Response[v1.ConfirmPluginInstallForInstanceResponse], error) {
return c.confirmPluginInstallForInstance.CallUnary(ctx, req)
}
// PluginRegistryServiceHandler is an implementation of the orchestrator.v1.PluginRegistryService
// service.
type PluginRegistryServiceHandler interface {
@ -568,6 +609,7 @@ type PluginRegistryServiceHandler interface {
// required (the calling instance, not a user, is the trust unit).
ListPrivatePluginsForInstance(context.Context, *connect.Request[v1.ListPrivatePluginsForInstanceRequest]) (*connect.Response[v1.ListPrivatePluginsResponse], error)
ResolveInstallForInstance(context.Context, *connect.Request[v1.ResolveInstallForInstanceRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
ConfirmPluginInstallForInstance(context.Context, *connect.Request[v1.ConfirmPluginInstallForInstanceRequest]) (*connect.Response[v1.ConfirmPluginInstallForInstanceResponse], error)
}
// NewPluginRegistryServiceHandler builds an HTTP handler from the service implementation. It
@ -661,6 +703,12 @@ func NewPluginRegistryServiceHandler(svc PluginRegistryServiceHandler, opts ...c
connect.WithSchema(pluginRegistryServiceMethods.ByName("ResolveInstallForInstance")),
connect.WithHandlerOptions(opts...),
)
pluginRegistryServiceConfirmPluginInstallForInstanceHandler := connect.NewUnaryHandler(
PluginRegistryServiceConfirmPluginInstallForInstanceProcedure,
svc.ConfirmPluginInstallForInstance,
connect.WithSchema(pluginRegistryServiceMethods.ByName("ConfirmPluginInstallForInstance")),
connect.WithHandlerOptions(opts...),
)
return "/orchestrator.v1.PluginRegistryService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case PluginRegistryServiceCreatePluginProcedure:
@ -691,6 +739,8 @@ func NewPluginRegistryServiceHandler(svc PluginRegistryServiceHandler, opts ...c
pluginRegistryServiceListPrivatePluginsForInstanceHandler.ServeHTTP(w, r)
case PluginRegistryServiceResolveInstallForInstanceProcedure:
pluginRegistryServiceResolveInstallForInstanceHandler.ServeHTTP(w, r)
case PluginRegistryServiceConfirmPluginInstallForInstanceProcedure:
pluginRegistryServiceConfirmPluginInstallForInstanceHandler.ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
@ -756,6 +806,10 @@ func (UnimplementedPluginRegistryServiceHandler) ResolveInstallForInstance(conte
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.ResolveInstallForInstance is not implemented"))
}
func (UnimplementedPluginRegistryServiceHandler) ConfirmPluginInstallForInstance(context.Context, *connect.Request[v1.ConfirmPluginInstallForInstanceRequest]) (*connect.Response[v1.ConfirmPluginInstallForInstanceResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.ConfirmPluginInstallForInstance is not implemented"))
}
// PluginModerationServiceClient is a client for the orchestrator.v1.PluginModerationService
// service.
type PluginModerationServiceClient interface {
@ -763,11 +817,34 @@ type PluginModerationServiceClient interface {
ApproveSubmission(context.Context, *connect.Request[v1.ApproveSubmissionRequest]) (*connect.Response[v1.ApproveSubmissionResponse], error)
RejectSubmission(context.Context, *connect.Request[v1.RejectSubmissionRequest]) (*connect.Response[v1.RejectSubmissionResponse], error)
RequestChanges(context.Context, *connect.Request[v1.RequestChangesRequest]) (*connect.Response[v1.RequestChangesResponse], error)
// Post-publication lifecycle control (WO-057). These act on plugins that are
// already public (or under_review), giving operators the ability to pull a
// plugin back out of the catalog after it shipped:
// - UnpublishPlugin: public -> under_review. Stops new installs, leaves
// existing installs untouched. Reversible via re-moderation.
// - TakedownPlugin: public|under_review -> taken_down. For malware. The
// instance sweep that force-uninstalls it everywhere is a separate flow
// (WO-059); this RPC only moves catalog state.
// - RestorePlugin: taken_down -> under_review (operator re-approves; not
// auto-republished).
// - YankVersion: marks a single version unusable without touching siblings.
// - DeletePublicPlugin: superadmin hard-delete incl. archive blobs.
UnpublishPlugin(context.Context, *connect.Request[v1.UnpublishPluginRequest]) (*connect.Response[v1.UnpublishPluginResponse], error)
TakedownPlugin(context.Context, *connect.Request[v1.TakedownPluginRequest]) (*connect.Response[v1.TakedownPluginResponse], error)
RestorePlugin(context.Context, *connect.Request[v1.RestorePluginRequest]) (*connect.Response[v1.RestorePluginResponse], error)
YankVersion(context.Context, *connect.Request[v1.YankVersionRequest]) (*connect.Response[v1.YankVersionResponse], error)
DeletePublicPlugin(context.Context, *connect.Request[v1.DeletePublicPluginRequest]) (*connect.Response[v1.DeletePublicPluginResponse], error)
// Star-review moderation (ADR 0021). Unrelated to the submission queue
// above: these act on user reviews (PluginReviewService), not plugins.
ListFlaggedReviews(context.Context, *connect.Request[v1.ListFlaggedReviewsRequest]) (*connect.Response[v1.ListFlaggedReviewsResponse], error)
SoftDeleteReview(context.Context, *connect.Request[v1.SoftDeleteReviewRequest]) (*connect.Response[v1.SoftDeleteReviewResponse], error)
SoftDeleteReply(context.Context, *connect.Request[v1.SoftDeleteReplyRequest]) (*connect.Response[v1.SoftDeleteReplyResponse], error)
// Registry category catalog management. Slugs are immutable once created
// because plugin.mod manifests persist them; metadata and ordering remain
// editable. Deletion is rejected while any plugin uses the category.
CreateCategory(context.Context, *connect.Request[v1.CreateCategoryRequest]) (*connect.Response[v1.CreateCategoryResponse], error)
UpdateCategory(context.Context, *connect.Request[v1.UpdateCategoryRequest]) (*connect.Response[v1.UpdateCategoryResponse], error)
DeleteCategory(context.Context, *connect.Request[v1.DeleteCategoryRequest]) (*connect.Response[v1.DeleteCategoryResponse], error)
}
// NewPluginModerationServiceClient constructs a client for the
@ -805,6 +882,36 @@ func NewPluginModerationServiceClient(httpClient connect.HTTPClient, baseURL str
connect.WithSchema(pluginModerationServiceMethods.ByName("RequestChanges")),
connect.WithClientOptions(opts...),
),
unpublishPlugin: connect.NewClient[v1.UnpublishPluginRequest, v1.UnpublishPluginResponse](
httpClient,
baseURL+PluginModerationServiceUnpublishPluginProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("UnpublishPlugin")),
connect.WithClientOptions(opts...),
),
takedownPlugin: connect.NewClient[v1.TakedownPluginRequest, v1.TakedownPluginResponse](
httpClient,
baseURL+PluginModerationServiceTakedownPluginProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("TakedownPlugin")),
connect.WithClientOptions(opts...),
),
restorePlugin: connect.NewClient[v1.RestorePluginRequest, v1.RestorePluginResponse](
httpClient,
baseURL+PluginModerationServiceRestorePluginProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("RestorePlugin")),
connect.WithClientOptions(opts...),
),
yankVersion: connect.NewClient[v1.YankVersionRequest, v1.YankVersionResponse](
httpClient,
baseURL+PluginModerationServiceYankVersionProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("YankVersion")),
connect.WithClientOptions(opts...),
),
deletePublicPlugin: connect.NewClient[v1.DeletePublicPluginRequest, v1.DeletePublicPluginResponse](
httpClient,
baseURL+PluginModerationServiceDeletePublicPluginProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("DeletePublicPlugin")),
connect.WithClientOptions(opts...),
),
listFlaggedReviews: connect.NewClient[v1.ListFlaggedReviewsRequest, v1.ListFlaggedReviewsResponse](
httpClient,
baseURL+PluginModerationServiceListFlaggedReviewsProcedure,
@ -823,6 +930,24 @@ func NewPluginModerationServiceClient(httpClient connect.HTTPClient, baseURL str
connect.WithSchema(pluginModerationServiceMethods.ByName("SoftDeleteReply")),
connect.WithClientOptions(opts...),
),
createCategory: connect.NewClient[v1.CreateCategoryRequest, v1.CreateCategoryResponse](
httpClient,
baseURL+PluginModerationServiceCreateCategoryProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("CreateCategory")),
connect.WithClientOptions(opts...),
),
updateCategory: connect.NewClient[v1.UpdateCategoryRequest, v1.UpdateCategoryResponse](
httpClient,
baseURL+PluginModerationServiceUpdateCategoryProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("UpdateCategory")),
connect.WithClientOptions(opts...),
),
deleteCategory: connect.NewClient[v1.DeleteCategoryRequest, v1.DeleteCategoryResponse](
httpClient,
baseURL+PluginModerationServiceDeleteCategoryProcedure,
connect.WithSchema(pluginModerationServiceMethods.ByName("DeleteCategory")),
connect.WithClientOptions(opts...),
),
}
}
@ -832,9 +957,17 @@ type pluginModerationServiceClient struct {
approveSubmission *connect.Client[v1.ApproveSubmissionRequest, v1.ApproveSubmissionResponse]
rejectSubmission *connect.Client[v1.RejectSubmissionRequest, v1.RejectSubmissionResponse]
requestChanges *connect.Client[v1.RequestChangesRequest, v1.RequestChangesResponse]
unpublishPlugin *connect.Client[v1.UnpublishPluginRequest, v1.UnpublishPluginResponse]
takedownPlugin *connect.Client[v1.TakedownPluginRequest, v1.TakedownPluginResponse]
restorePlugin *connect.Client[v1.RestorePluginRequest, v1.RestorePluginResponse]
yankVersion *connect.Client[v1.YankVersionRequest, v1.YankVersionResponse]
deletePublicPlugin *connect.Client[v1.DeletePublicPluginRequest, v1.DeletePublicPluginResponse]
listFlaggedReviews *connect.Client[v1.ListFlaggedReviewsRequest, v1.ListFlaggedReviewsResponse]
softDeleteReview *connect.Client[v1.SoftDeleteReviewRequest, v1.SoftDeleteReviewResponse]
softDeleteReply *connect.Client[v1.SoftDeleteReplyRequest, v1.SoftDeleteReplyResponse]
createCategory *connect.Client[v1.CreateCategoryRequest, v1.CreateCategoryResponse]
updateCategory *connect.Client[v1.UpdateCategoryRequest, v1.UpdateCategoryResponse]
deleteCategory *connect.Client[v1.DeleteCategoryRequest, v1.DeleteCategoryResponse]
}
// ListPendingReviews calls orchestrator.v1.PluginModerationService.ListPendingReviews.
@ -857,6 +990,31 @@ func (c *pluginModerationServiceClient) RequestChanges(ctx context.Context, req
return c.requestChanges.CallUnary(ctx, req)
}
// UnpublishPlugin calls orchestrator.v1.PluginModerationService.UnpublishPlugin.
func (c *pluginModerationServiceClient) UnpublishPlugin(ctx context.Context, req *connect.Request[v1.UnpublishPluginRequest]) (*connect.Response[v1.UnpublishPluginResponse], error) {
return c.unpublishPlugin.CallUnary(ctx, req)
}
// TakedownPlugin calls orchestrator.v1.PluginModerationService.TakedownPlugin.
func (c *pluginModerationServiceClient) TakedownPlugin(ctx context.Context, req *connect.Request[v1.TakedownPluginRequest]) (*connect.Response[v1.TakedownPluginResponse], error) {
return c.takedownPlugin.CallUnary(ctx, req)
}
// RestorePlugin calls orchestrator.v1.PluginModerationService.RestorePlugin.
func (c *pluginModerationServiceClient) RestorePlugin(ctx context.Context, req *connect.Request[v1.RestorePluginRequest]) (*connect.Response[v1.RestorePluginResponse], error) {
return c.restorePlugin.CallUnary(ctx, req)
}
// YankVersion calls orchestrator.v1.PluginModerationService.YankVersion.
func (c *pluginModerationServiceClient) YankVersion(ctx context.Context, req *connect.Request[v1.YankVersionRequest]) (*connect.Response[v1.YankVersionResponse], error) {
return c.yankVersion.CallUnary(ctx, req)
}
// DeletePublicPlugin calls orchestrator.v1.PluginModerationService.DeletePublicPlugin.
func (c *pluginModerationServiceClient) DeletePublicPlugin(ctx context.Context, req *connect.Request[v1.DeletePublicPluginRequest]) (*connect.Response[v1.DeletePublicPluginResponse], error) {
return c.deletePublicPlugin.CallUnary(ctx, req)
}
// ListFlaggedReviews calls orchestrator.v1.PluginModerationService.ListFlaggedReviews.
func (c *pluginModerationServiceClient) ListFlaggedReviews(ctx context.Context, req *connect.Request[v1.ListFlaggedReviewsRequest]) (*connect.Response[v1.ListFlaggedReviewsResponse], error) {
return c.listFlaggedReviews.CallUnary(ctx, req)
@ -872,6 +1030,21 @@ func (c *pluginModerationServiceClient) SoftDeleteReply(ctx context.Context, req
return c.softDeleteReply.CallUnary(ctx, req)
}
// CreateCategory calls orchestrator.v1.PluginModerationService.CreateCategory.
func (c *pluginModerationServiceClient) CreateCategory(ctx context.Context, req *connect.Request[v1.CreateCategoryRequest]) (*connect.Response[v1.CreateCategoryResponse], error) {
return c.createCategory.CallUnary(ctx, req)
}
// UpdateCategory calls orchestrator.v1.PluginModerationService.UpdateCategory.
func (c *pluginModerationServiceClient) UpdateCategory(ctx context.Context, req *connect.Request[v1.UpdateCategoryRequest]) (*connect.Response[v1.UpdateCategoryResponse], error) {
return c.updateCategory.CallUnary(ctx, req)
}
// DeleteCategory calls orchestrator.v1.PluginModerationService.DeleteCategory.
func (c *pluginModerationServiceClient) DeleteCategory(ctx context.Context, req *connect.Request[v1.DeleteCategoryRequest]) (*connect.Response[v1.DeleteCategoryResponse], error) {
return c.deleteCategory.CallUnary(ctx, req)
}
// PluginModerationServiceHandler is an implementation of the
// orchestrator.v1.PluginModerationService service.
type PluginModerationServiceHandler interface {
@ -879,11 +1052,34 @@ type PluginModerationServiceHandler interface {
ApproveSubmission(context.Context, *connect.Request[v1.ApproveSubmissionRequest]) (*connect.Response[v1.ApproveSubmissionResponse], error)
RejectSubmission(context.Context, *connect.Request[v1.RejectSubmissionRequest]) (*connect.Response[v1.RejectSubmissionResponse], error)
RequestChanges(context.Context, *connect.Request[v1.RequestChangesRequest]) (*connect.Response[v1.RequestChangesResponse], error)
// Post-publication lifecycle control (WO-057). These act on plugins that are
// already public (or under_review), giving operators the ability to pull a
// plugin back out of the catalog after it shipped:
// - UnpublishPlugin: public -> under_review. Stops new installs, leaves
// existing installs untouched. Reversible via re-moderation.
// - TakedownPlugin: public|under_review -> taken_down. For malware. The
// instance sweep that force-uninstalls it everywhere is a separate flow
// (WO-059); this RPC only moves catalog state.
// - RestorePlugin: taken_down -> under_review (operator re-approves; not
// auto-republished).
// - YankVersion: marks a single version unusable without touching siblings.
// - DeletePublicPlugin: superadmin hard-delete incl. archive blobs.
UnpublishPlugin(context.Context, *connect.Request[v1.UnpublishPluginRequest]) (*connect.Response[v1.UnpublishPluginResponse], error)
TakedownPlugin(context.Context, *connect.Request[v1.TakedownPluginRequest]) (*connect.Response[v1.TakedownPluginResponse], error)
RestorePlugin(context.Context, *connect.Request[v1.RestorePluginRequest]) (*connect.Response[v1.RestorePluginResponse], error)
YankVersion(context.Context, *connect.Request[v1.YankVersionRequest]) (*connect.Response[v1.YankVersionResponse], error)
DeletePublicPlugin(context.Context, *connect.Request[v1.DeletePublicPluginRequest]) (*connect.Response[v1.DeletePublicPluginResponse], error)
// Star-review moderation (ADR 0021). Unrelated to the submission queue
// above: these act on user reviews (PluginReviewService), not plugins.
ListFlaggedReviews(context.Context, *connect.Request[v1.ListFlaggedReviewsRequest]) (*connect.Response[v1.ListFlaggedReviewsResponse], error)
SoftDeleteReview(context.Context, *connect.Request[v1.SoftDeleteReviewRequest]) (*connect.Response[v1.SoftDeleteReviewResponse], error)
SoftDeleteReply(context.Context, *connect.Request[v1.SoftDeleteReplyRequest]) (*connect.Response[v1.SoftDeleteReplyResponse], error)
// Registry category catalog management. Slugs are immutable once created
// because plugin.mod manifests persist them; metadata and ordering remain
// editable. Deletion is rejected while any plugin uses the category.
CreateCategory(context.Context, *connect.Request[v1.CreateCategoryRequest]) (*connect.Response[v1.CreateCategoryResponse], error)
UpdateCategory(context.Context, *connect.Request[v1.UpdateCategoryRequest]) (*connect.Response[v1.UpdateCategoryResponse], error)
DeleteCategory(context.Context, *connect.Request[v1.DeleteCategoryRequest]) (*connect.Response[v1.DeleteCategoryResponse], error)
}
// NewPluginModerationServiceHandler builds an HTTP handler from the service implementation. It
@ -917,6 +1113,36 @@ func NewPluginModerationServiceHandler(svc PluginModerationServiceHandler, opts
connect.WithSchema(pluginModerationServiceMethods.ByName("RequestChanges")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceUnpublishPluginHandler := connect.NewUnaryHandler(
PluginModerationServiceUnpublishPluginProcedure,
svc.UnpublishPlugin,
connect.WithSchema(pluginModerationServiceMethods.ByName("UnpublishPlugin")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceTakedownPluginHandler := connect.NewUnaryHandler(
PluginModerationServiceTakedownPluginProcedure,
svc.TakedownPlugin,
connect.WithSchema(pluginModerationServiceMethods.ByName("TakedownPlugin")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceRestorePluginHandler := connect.NewUnaryHandler(
PluginModerationServiceRestorePluginProcedure,
svc.RestorePlugin,
connect.WithSchema(pluginModerationServiceMethods.ByName("RestorePlugin")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceYankVersionHandler := connect.NewUnaryHandler(
PluginModerationServiceYankVersionProcedure,
svc.YankVersion,
connect.WithSchema(pluginModerationServiceMethods.ByName("YankVersion")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceDeletePublicPluginHandler := connect.NewUnaryHandler(
PluginModerationServiceDeletePublicPluginProcedure,
svc.DeletePublicPlugin,
connect.WithSchema(pluginModerationServiceMethods.ByName("DeletePublicPlugin")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceListFlaggedReviewsHandler := connect.NewUnaryHandler(
PluginModerationServiceListFlaggedReviewsProcedure,
svc.ListFlaggedReviews,
@ -935,6 +1161,24 @@ func NewPluginModerationServiceHandler(svc PluginModerationServiceHandler, opts
connect.WithSchema(pluginModerationServiceMethods.ByName("SoftDeleteReply")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceCreateCategoryHandler := connect.NewUnaryHandler(
PluginModerationServiceCreateCategoryProcedure,
svc.CreateCategory,
connect.WithSchema(pluginModerationServiceMethods.ByName("CreateCategory")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceUpdateCategoryHandler := connect.NewUnaryHandler(
PluginModerationServiceUpdateCategoryProcedure,
svc.UpdateCategory,
connect.WithSchema(pluginModerationServiceMethods.ByName("UpdateCategory")),
connect.WithHandlerOptions(opts...),
)
pluginModerationServiceDeleteCategoryHandler := connect.NewUnaryHandler(
PluginModerationServiceDeleteCategoryProcedure,
svc.DeleteCategory,
connect.WithSchema(pluginModerationServiceMethods.ByName("DeleteCategory")),
connect.WithHandlerOptions(opts...),
)
return "/orchestrator.v1.PluginModerationService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case PluginModerationServiceListPendingReviewsProcedure:
@ -945,12 +1189,28 @@ func NewPluginModerationServiceHandler(svc PluginModerationServiceHandler, opts
pluginModerationServiceRejectSubmissionHandler.ServeHTTP(w, r)
case PluginModerationServiceRequestChangesProcedure:
pluginModerationServiceRequestChangesHandler.ServeHTTP(w, r)
case PluginModerationServiceUnpublishPluginProcedure:
pluginModerationServiceUnpublishPluginHandler.ServeHTTP(w, r)
case PluginModerationServiceTakedownPluginProcedure:
pluginModerationServiceTakedownPluginHandler.ServeHTTP(w, r)
case PluginModerationServiceRestorePluginProcedure:
pluginModerationServiceRestorePluginHandler.ServeHTTP(w, r)
case PluginModerationServiceYankVersionProcedure:
pluginModerationServiceYankVersionHandler.ServeHTTP(w, r)
case PluginModerationServiceDeletePublicPluginProcedure:
pluginModerationServiceDeletePublicPluginHandler.ServeHTTP(w, r)
case PluginModerationServiceListFlaggedReviewsProcedure:
pluginModerationServiceListFlaggedReviewsHandler.ServeHTTP(w, r)
case PluginModerationServiceSoftDeleteReviewProcedure:
pluginModerationServiceSoftDeleteReviewHandler.ServeHTTP(w, r)
case PluginModerationServiceSoftDeleteReplyProcedure:
pluginModerationServiceSoftDeleteReplyHandler.ServeHTTP(w, r)
case PluginModerationServiceCreateCategoryProcedure:
pluginModerationServiceCreateCategoryHandler.ServeHTTP(w, r)
case PluginModerationServiceUpdateCategoryProcedure:
pluginModerationServiceUpdateCategoryHandler.ServeHTTP(w, r)
case PluginModerationServiceDeleteCategoryProcedure:
pluginModerationServiceDeleteCategoryHandler.ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
@ -976,6 +1236,26 @@ func (UnimplementedPluginModerationServiceHandler) RequestChanges(context.Contex
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.RequestChanges is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) UnpublishPlugin(context.Context, *connect.Request[v1.UnpublishPluginRequest]) (*connect.Response[v1.UnpublishPluginResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.UnpublishPlugin is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) TakedownPlugin(context.Context, *connect.Request[v1.TakedownPluginRequest]) (*connect.Response[v1.TakedownPluginResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.TakedownPlugin is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) RestorePlugin(context.Context, *connect.Request[v1.RestorePluginRequest]) (*connect.Response[v1.RestorePluginResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.RestorePlugin is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) YankVersion(context.Context, *connect.Request[v1.YankVersionRequest]) (*connect.Response[v1.YankVersionResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.YankVersion is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) DeletePublicPlugin(context.Context, *connect.Request[v1.DeletePublicPluginRequest]) (*connect.Response[v1.DeletePublicPluginResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.DeletePublicPlugin is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) ListFlaggedReviews(context.Context, *connect.Request[v1.ListFlaggedReviewsRequest]) (*connect.Response[v1.ListFlaggedReviewsResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.ListFlaggedReviews is not implemented"))
}
@ -988,6 +1268,18 @@ func (UnimplementedPluginModerationServiceHandler) SoftDeleteReply(context.Conte
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.SoftDeleteReply is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) CreateCategory(context.Context, *connect.Request[v1.CreateCategoryRequest]) (*connect.Response[v1.CreateCategoryResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.CreateCategory is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) UpdateCategory(context.Context, *connect.Request[v1.UpdateCategoryRequest]) (*connect.Response[v1.UpdateCategoryResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.UpdateCategory is not implemented"))
}
func (UnimplementedPluginModerationServiceHandler) DeleteCategory(context.Context, *connect.Request[v1.DeleteCategoryRequest]) (*connect.Response[v1.DeleteCategoryResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginModerationService.DeleteCategory is not implemented"))
}
// PluginGalleryServiceClient is a client for the orchestrator.v1.PluginGalleryService service.
type PluginGalleryServiceClient interface {
ListScreenshots(context.Context, *connect.Request[v1.ListScreenshotsRequest]) (*connect.Response[v1.ListScreenshotsResponse], error)

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,11 @@ service PluginRegistryService {
// required (the calling instance, not a user, is the trust unit).
rpc ListPrivatePluginsForInstance(ListPrivatePluginsForInstanceRequest) returns (ListPrivatePluginsResponse);
rpc ResolveInstallForInstance(ResolveInstallForInstanceRequest) returns (ResolveInstallResponse);
rpc BeginPluginInstallForInstance(BeginPluginInstallForInstanceRequest) returns (ResolveInstallResponse);
rpc CancelPluginInstallForInstance(CancelPluginInstallForInstanceRequest) returns (CancelPluginInstallForInstanceResponse);
rpc AdoptPluginInstallForInstance(AdoptPluginInstallForInstanceRequest) returns (AdoptPluginInstallForInstanceResponse);
rpc ConfirmPluginInstallForInstance(ConfirmPluginInstallForInstanceRequest) returns (ConfirmPluginInstallForInstanceResponse);
rpc ConfirmPluginUninstallForInstance(ConfirmPluginUninstallForInstanceRequest) returns (ConfirmPluginUninstallForInstanceResponse);
}
// PluginModerationService is the superadmin-only side: lists pending submissions
@ -50,11 +55,36 @@ service PluginModerationService {
rpc RejectSubmission(RejectSubmissionRequest) returns (RejectSubmissionResponse);
rpc RequestChanges(RequestChangesRequest) returns (RequestChangesResponse);
// Post-publication lifecycle control (WO-057). These act on plugins that are
// already public (or under_review), giving operators the ability to pull a
// plugin back out of the catalog after it shipped:
// - UnpublishPlugin: public -> under_review. Stops new installs, leaves
// existing installs untouched. Reversible via re-moderation.
// - TakedownPlugin: public|under_review -> taken_down. For malware. The
// instance sweep that force-uninstalls it everywhere is a separate flow
// (WO-059); this RPC only moves catalog state.
// - RestorePlugin: taken_down -> under_review (operator re-approves; not
// auto-republished).
// - YankVersion: marks a single version unusable without touching siblings.
// - DeletePublicPlugin: superadmin hard-delete incl. archive blobs.
rpc UnpublishPlugin(UnpublishPluginRequest) returns (UnpublishPluginResponse);
rpc TakedownPlugin(TakedownPluginRequest) returns (TakedownPluginResponse);
rpc RestorePlugin(RestorePluginRequest) returns (RestorePluginResponse);
rpc YankVersion(YankVersionRequest) returns (YankVersionResponse);
rpc DeletePublicPlugin(DeletePublicPluginRequest) returns (DeletePublicPluginResponse);
// Star-review moderation (ADR 0021). Unrelated to the submission queue
// above: these act on user reviews (PluginReviewService), not plugins.
rpc ListFlaggedReviews(ListFlaggedReviewsRequest) returns (ListFlaggedReviewsResponse);
rpc SoftDeleteReview(SoftDeleteReviewRequest) returns (SoftDeleteReviewResponse);
rpc SoftDeleteReply(SoftDeleteReplyRequest) returns (SoftDeleteReplyResponse);
// Registry category catalog management. Slugs are immutable once created
// because plugin.mod manifests persist them; metadata and ordering remain
// editable. Deletion is rejected while any plugin uses the category.
rpc CreateCategory(CreateCategoryRequest) returns (CreateCategoryResponse);
rpc UpdateCategory(UpdateCategoryRequest) returns (UpdateCategoryResponse);
rpc DeleteCategory(DeleteCategoryRequest) returns (DeleteCategoryResponse);
}
// PluginGalleryService manages a plugin's screenshot gallery. Reads are
@ -180,6 +210,7 @@ message Category {
string display_name = 2;
string description = 3;
int32 sort_order = 4;
int32 plugin_count = 5;
}
message Version {
@ -355,6 +386,21 @@ message ResolveInstallRequest {
// resolves (account_id, name) and verifies the caller's account
// membership. Ignored for public scopes.
string active_account_id = 4;
// When latest_compatible is true the registry chooses the newest
// non-yanked version that exactly matches host_abi_version and whose
// plugin_sdk constraint accepts host_sdk_version and, for an admin bundle,
// whose admin_api constraint accepts host_api_version. Host contract fields
// and current_version are required unless allow_initial_version is set; the
// registry fails closed when it cannot prove compatibility.
string host_sdk_version = 5;
uint32 host_abi_version = 6;
bool latest_compatible = 7;
string current_version = 8;
string host_api_version = 9;
// allow_initial_version is reserved for authenticated delivery migrations
// whose legacy row has no semantic version. It selects the highest stable,
// compatible release without inventing a 0.x major.
bool allow_initial_version = 10;
}
message ResolveInstallResponse {
string version_id = 1;
@ -372,6 +418,13 @@ message ResolveInstallResponse {
// for a legacy source archive. The installing instance rejects an artifact
// whose abi_version its loader cannot run.
uint32 abi_version = 12;
string admin_api_constraint = 13;
bool has_admin_ui = 14;
// BeginPluginInstallForInstance issues the operation identity after a
// side-effect-free resolve has selected a target. Plain resolve responses
// leave these fields empty.
string install_operation_token = 15;
uint64 install_operation_generation = 16;
}
// --- Instance-authenticated request shapes ---
@ -394,8 +447,74 @@ message ResolveInstallForInstanceRequest {
// calling account's private plugin (the original behavior); any other value
// resolves a PUBLIC plugin in that scope (ADR 0021).
string scope_slug = 4;
string host_sdk_version = 5;
uint32 host_abi_version = 6;
bool latest_compatible = 7;
string current_version = 8;
string host_api_version = 9;
bool allow_initial_version = 10;
reserved 11;
}
message BeginPluginInstallForInstanceRequest {
string instance_id = 1;
string version_id = 2;
// Generated once by the CMS for this exact local mutation. Retrying with
// the same ID returns the original operation token/generation.
string install_operation_id = 3;
}
message CancelPluginInstallForInstanceRequest {
string instance_id = 1;
string install_operation_token = 2;
uint64 install_operation_generation = 3;
}
message CancelPluginInstallForInstanceResponse {}
message ConfirmPluginInstallForInstanceRequest {
string instance_id = 1;
string scope_slug = 2;
string plugin_name = 3;
string version_id = 4;
string version = 5;
string archive_sha256 = 6;
string install_operation_token = 7;
uint64 install_operation_generation = 8;
}
message ConfirmPluginInstallForInstanceResponse {}
message AdoptPluginInstallForInstanceRequest {
string instance_id = 1;
string version_id = 2;
string archive_sha256 = 3;
// install_operation_id is generated once by the CMS and retained until the
// legacy current-install event has been adopted locally and remotely.
string install_operation_id = 4;
string scope_slug = 5;
string plugin_name = 6;
string version = 7;
}
message AdoptPluginInstallForInstanceResponse {
string install_operation_token = 1;
uint64 install_operation_generation = 2;
string version_id = 3;
string version = 4;
string archive_sha256 = 5;
}
message ConfirmPluginUninstallForInstanceRequest {
string instance_id = 1;
string scope_slug = 2;
string plugin_name = 3;
string install_operation_token = 4;
uint64 install_operation_generation = 5;
}
message ConfirmPluginUninstallForInstanceResponse {}
// --- Review / moderation ---
message PendingReview {
@ -445,6 +564,37 @@ message RequestChangesRequest {
}
message RequestChangesResponse {}
// --- Post-publication lifecycle (WO-057) ---
message UnpublishPluginRequest {
string plugin_id = 1;
string reason = 2; // required audit trail
}
message UnpublishPluginResponse {}
message TakedownPluginRequest {
string plugin_id = 1;
string reason = 2; // required audit trail
}
message TakedownPluginResponse {}
message RestorePluginRequest {
string plugin_id = 1;
}
message RestorePluginResponse {}
message YankVersionRequest {
string plugin_id = 1;
string version = 2; // required the version string to yank (e.g. "0.2.3")
string reason = 3; // required audit trail
}
message YankVersionResponse {}
message DeletePublicPluginRequest {
string plugin_id = 1;
}
message DeletePublicPluginResponse {}
// --- Gallery service ---
message ListScreenshotsRequest {
@ -650,12 +800,16 @@ message PollDeviceRequest { string device_code = 1; }
message PollDeviceResponse {
string access_token = 1;
string status = 2;
// Account chosen on the device-approval page (empty when none was chosen).
// The CLI uses it as the active account and skips its stdin picker.
string account_id = 3;
string account_slug = 4;
}
message ApproveDeviceRequest {
string user_code = 1;
// Optional org account the approving user selects for the CLI to act as.
// Must be an account the user is a member of.
string account_id = 2;
}
message ApproveDeviceResponse {}
@ -693,3 +847,24 @@ message ListMyAccountsForCLIRequest {}
message ListMyAccountsForCLIResponse {
repeated MyAccount accounts = 1;
}
// --- Registry category administration ---
message CreateCategoryRequest {
string slug = 1;
string display_name = 2;
string description = 3;
int32 sort_order = 4;
}
message CreateCategoryResponse { Category category = 1; }
message UpdateCategoryRequest {
string slug = 1;
string display_name = 2;
string description = 3;
int32 sort_order = 4;
}
message UpdateCategoryResponse { Category category = 1; }
message DeleteCategoryRequest { string slug = 1; }
message DeleteCategoryResponse {}