feat(ninja): wire ListTags into popular-tag prompt and list helpers
This commit is contained in:
parent
bb3ddfe1bd
commit
26b262ce73
@ -606,16 +606,22 @@ func promptCategoriesWithDefault(ctx context.Context, cli *orchclient.Client, sc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetchPopularTagsForPrompt returns a comma-joined "tag (count)" string of the
|
// fetchPopularTagsForPrompt returns a comma-joined "tag (count)" string of the
|
||||||
// top tags for the given kind, or "" if the orchestrator lookup fails. The
|
// top tags for the given kind, or "" if the orchestrator lookup fails (e.g.
|
||||||
// current implementation always returns "" because core's copy of the
|
// offline, unauthenticated, RPC error). Callers must tolerate an empty return
|
||||||
// orchestrator proto bindings does not yet expose ListTags; once the bindings
|
// and surface their own user-facing fallback message.
|
||||||
// are regenerated this body becomes a best-effort PluginRegistryService.ListTags
|
|
||||||
// call. Callers must already tolerate an empty return.
|
|
||||||
func fetchPopularTagsForPrompt(ctx context.Context, cli *orchclient.Client, kind string) string {
|
func fetchPopularTagsForPrompt(ctx context.Context, cli *orchclient.Client, kind string) string {
|
||||||
_ = ctx
|
resp, err := cli.Reg.ListTags(ctx, connect.NewRequest(&v1.ListTagsRequest{Kind: kind, Limit: 20}))
|
||||||
_ = cli
|
if err != nil {
|
||||||
_ = kind
|
return ""
|
||||||
return ""
|
}
|
||||||
|
if len(resp.Msg.Tags) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
parts := make([]string, 0, len(resp.Msg.Tags))
|
||||||
|
for _, t := range resp.Msg.Tags {
|
||||||
|
parts = append(parts, fmt.Sprintf("%s (%d)", t.Tag, t.Count))
|
||||||
|
}
|
||||||
|
return strings.Join(parts, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// promptTagsWithDefault prompts the user for free-form tags. Best-effort fetches
|
// promptTagsWithDefault prompts the user for free-form tags. Best-effort fetches
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"connectrpc.com/connect"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
core "git.dev.alexdunmow.com/block/core/plugin"
|
core "git.dev.alexdunmow.com/block/core/plugin"
|
||||||
"git.dev.alexdunmow.com/block/core/cmd/ninja/internal/creds"
|
"git.dev.alexdunmow.com/block/core/cmd/ninja/internal/creds"
|
||||||
"git.dev.alexdunmow.com/block/core/cmd/ninja/internal/orchclient"
|
"git.dev.alexdunmow.com/block/core/cmd/ninja/internal/orchclient"
|
||||||
|
v1 "git.dev.alexdunmow.com/block/core/internal/api/orchestrator/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newPluginTagsCmd() *cobra.Command {
|
func newPluginTagsCmd() *cobra.Command {
|
||||||
@ -152,14 +155,21 @@ func writeLocalModTags(mod *core.ModFile, tags []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetchPopularTagsForList returns a single user-facing line listing the most-used
|
// fetchPopularTagsForList returns a single user-facing line listing the most-used
|
||||||
// tags for the given kind. The current body returns an unavailable-notice
|
// tags for the given kind. Renders "Popular: tag (count), ...", "Popular tags:
|
||||||
// because core's copy of the orchestrator proto bindings does not yet expose
|
// (none yet)" when no tags exist on public plugins yet, or an "(unreachable)"
|
||||||
// ListTags; once bindings are regenerated this body becomes a real
|
// notice if the RPC fails.
|
||||||
// PluginRegistryService.ListTags call rendering "Popular: tag (count), ..." or
|
|
||||||
// "Popular tags: (none yet)".
|
|
||||||
func fetchPopularTagsForList(cli *orchclient.Client, kind string) string {
|
func fetchPopularTagsForList(cli *orchclient.Client, kind string) string {
|
||||||
_ = cli
|
resp, err := cli.Reg.ListTags(context.Background(), connect.NewRequest(&v1.ListTagsRequest{Kind: kind, Limit: 20}))
|
||||||
_ = kind
|
if err != nil {
|
||||||
return "(popular tags unavailable — orchestrator bindings not yet regenerated)"
|
return "(could not fetch popular tags — orchestrator unreachable)"
|
||||||
|
}
|
||||||
|
if len(resp.Msg.Tags) == 0 {
|
||||||
|
return "Popular tags: (none yet)"
|
||||||
|
}
|
||||||
|
parts := make([]string, len(resp.Msg.Tags))
|
||||||
|
for i, t := range resp.Msg.Tags {
|
||||||
|
parts[i] = fmt.Sprintf("%s (%d)", t.Tag, t.Count)
|
||||||
|
}
|
||||||
|
return "Popular: " + strings.Join(parts, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,6 +71,9 @@ const (
|
|||||||
// PluginRegistryServiceListCategoriesProcedure is the fully-qualified name of the
|
// PluginRegistryServiceListCategoriesProcedure is the fully-qualified name of the
|
||||||
// PluginRegistryService's ListCategories RPC.
|
// PluginRegistryService's ListCategories RPC.
|
||||||
PluginRegistryServiceListCategoriesProcedure = "/orchestrator.v1.PluginRegistryService/ListCategories"
|
PluginRegistryServiceListCategoriesProcedure = "/orchestrator.v1.PluginRegistryService/ListCategories"
|
||||||
|
// PluginRegistryServiceListTagsProcedure is the fully-qualified name of the PluginRegistryService's
|
||||||
|
// ListTags RPC.
|
||||||
|
PluginRegistryServiceListTagsProcedure = "/orchestrator.v1.PluginRegistryService/ListTags"
|
||||||
// PluginRegistryServiceSubmitForReviewProcedure is the fully-qualified name of the
|
// PluginRegistryServiceSubmitForReviewProcedure is the fully-qualified name of the
|
||||||
// PluginRegistryService's SubmitForReview RPC.
|
// PluginRegistryService's SubmitForReview RPC.
|
||||||
PluginRegistryServiceSubmitForReviewProcedure = "/orchestrator.v1.PluginRegistryService/SubmitForReview"
|
PluginRegistryServiceSubmitForReviewProcedure = "/orchestrator.v1.PluginRegistryService/SubmitForReview"
|
||||||
@ -280,6 +283,7 @@ type PluginRegistryServiceClient interface {
|
|||||||
GetVersion(context.Context, *connect.Request[v1.GetVersionRequest]) (*connect.Response[v1.GetVersionResponse], error)
|
GetVersion(context.Context, *connect.Request[v1.GetVersionRequest]) (*connect.Response[v1.GetVersionResponse], error)
|
||||||
ResolveInstall(context.Context, *connect.Request[v1.ResolveInstallRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
|
ResolveInstall(context.Context, *connect.Request[v1.ResolveInstallRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
|
||||||
ListCategories(context.Context, *connect.Request[v1.ListCategoriesRequest]) (*connect.Response[v1.ListCategoriesResponse], error)
|
ListCategories(context.Context, *connect.Request[v1.ListCategoriesRequest]) (*connect.Response[v1.ListCategoriesResponse], error)
|
||||||
|
ListTags(context.Context, *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error)
|
||||||
SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error)
|
SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error)
|
||||||
// Private-plugin RPCs. All require the caller to be a member of the target
|
// Private-plugin RPCs. All require the caller to be a member of the target
|
||||||
// account; the server resolves account membership from the bearer token.
|
// account; the server resolves account membership from the bearer token.
|
||||||
@ -336,6 +340,12 @@ func NewPluginRegistryServiceClient(httpClient connect.HTTPClient, baseURL strin
|
|||||||
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListCategories")),
|
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListCategories")),
|
||||||
connect.WithClientOptions(opts...),
|
connect.WithClientOptions(opts...),
|
||||||
),
|
),
|
||||||
|
listTags: connect.NewClient[v1.ListTagsRequest, v1.ListTagsResponse](
|
||||||
|
httpClient,
|
||||||
|
baseURL+PluginRegistryServiceListTagsProcedure,
|
||||||
|
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListTags")),
|
||||||
|
connect.WithClientOptions(opts...),
|
||||||
|
),
|
||||||
submitForReview: connect.NewClient[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse](
|
submitForReview: connect.NewClient[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse](
|
||||||
httpClient,
|
httpClient,
|
||||||
baseURL+PluginRegistryServiceSubmitForReviewProcedure,
|
baseURL+PluginRegistryServiceSubmitForReviewProcedure,
|
||||||
@ -377,6 +387,7 @@ type pluginRegistryServiceClient struct {
|
|||||||
getVersion *connect.Client[v1.GetVersionRequest, v1.GetVersionResponse]
|
getVersion *connect.Client[v1.GetVersionRequest, v1.GetVersionResponse]
|
||||||
resolveInstall *connect.Client[v1.ResolveInstallRequest, v1.ResolveInstallResponse]
|
resolveInstall *connect.Client[v1.ResolveInstallRequest, v1.ResolveInstallResponse]
|
||||||
listCategories *connect.Client[v1.ListCategoriesRequest, v1.ListCategoriesResponse]
|
listCategories *connect.Client[v1.ListCategoriesRequest, v1.ListCategoriesResponse]
|
||||||
|
listTags *connect.Client[v1.ListTagsRequest, v1.ListTagsResponse]
|
||||||
submitForReview *connect.Client[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse]
|
submitForReview *connect.Client[v1.SubmitForReviewRequest, v1.SubmitForReviewResponse]
|
||||||
listPrivatePlugins *connect.Client[v1.ListPrivatePluginsRequest, v1.ListPrivatePluginsResponse]
|
listPrivatePlugins *connect.Client[v1.ListPrivatePluginsRequest, v1.ListPrivatePluginsResponse]
|
||||||
deletePrivatePlugin *connect.Client[v1.DeletePrivatePluginRequest, v1.DeletePrivatePluginResponse]
|
deletePrivatePlugin *connect.Client[v1.DeletePrivatePluginRequest, v1.DeletePrivatePluginResponse]
|
||||||
@ -414,6 +425,11 @@ func (c *pluginRegistryServiceClient) ListCategories(ctx context.Context, req *c
|
|||||||
return c.listCategories.CallUnary(ctx, req)
|
return c.listCategories.CallUnary(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListTags calls orchestrator.v1.PluginRegistryService.ListTags.
|
||||||
|
func (c *pluginRegistryServiceClient) ListTags(ctx context.Context, req *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error) {
|
||||||
|
return c.listTags.CallUnary(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
// SubmitForReview calls orchestrator.v1.PluginRegistryService.SubmitForReview.
|
// SubmitForReview calls orchestrator.v1.PluginRegistryService.SubmitForReview.
|
||||||
func (c *pluginRegistryServiceClient) SubmitForReview(ctx context.Context, req *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error) {
|
func (c *pluginRegistryServiceClient) SubmitForReview(ctx context.Context, req *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error) {
|
||||||
return c.submitForReview.CallUnary(ctx, req)
|
return c.submitForReview.CallUnary(ctx, req)
|
||||||
@ -450,6 +466,7 @@ type PluginRegistryServiceHandler interface {
|
|||||||
GetVersion(context.Context, *connect.Request[v1.GetVersionRequest]) (*connect.Response[v1.GetVersionResponse], error)
|
GetVersion(context.Context, *connect.Request[v1.GetVersionRequest]) (*connect.Response[v1.GetVersionResponse], error)
|
||||||
ResolveInstall(context.Context, *connect.Request[v1.ResolveInstallRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
|
ResolveInstall(context.Context, *connect.Request[v1.ResolveInstallRequest]) (*connect.Response[v1.ResolveInstallResponse], error)
|
||||||
ListCategories(context.Context, *connect.Request[v1.ListCategoriesRequest]) (*connect.Response[v1.ListCategoriesResponse], error)
|
ListCategories(context.Context, *connect.Request[v1.ListCategoriesRequest]) (*connect.Response[v1.ListCategoriesResponse], error)
|
||||||
|
ListTags(context.Context, *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error)
|
||||||
SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error)
|
SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error)
|
||||||
// Private-plugin RPCs. All require the caller to be a member of the target
|
// Private-plugin RPCs. All require the caller to be a member of the target
|
||||||
// account; the server resolves account membership from the bearer token.
|
// account; the server resolves account membership from the bearer token.
|
||||||
@ -502,6 +519,12 @@ func NewPluginRegistryServiceHandler(svc PluginRegistryServiceHandler, opts ...c
|
|||||||
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListCategories")),
|
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListCategories")),
|
||||||
connect.WithHandlerOptions(opts...),
|
connect.WithHandlerOptions(opts...),
|
||||||
)
|
)
|
||||||
|
pluginRegistryServiceListTagsHandler := connect.NewUnaryHandler(
|
||||||
|
PluginRegistryServiceListTagsProcedure,
|
||||||
|
svc.ListTags,
|
||||||
|
connect.WithSchema(pluginRegistryServiceMethods.ByName("ListTags")),
|
||||||
|
connect.WithHandlerOptions(opts...),
|
||||||
|
)
|
||||||
pluginRegistryServiceSubmitForReviewHandler := connect.NewUnaryHandler(
|
pluginRegistryServiceSubmitForReviewHandler := connect.NewUnaryHandler(
|
||||||
PluginRegistryServiceSubmitForReviewProcedure,
|
PluginRegistryServiceSubmitForReviewProcedure,
|
||||||
svc.SubmitForReview,
|
svc.SubmitForReview,
|
||||||
@ -546,6 +569,8 @@ func NewPluginRegistryServiceHandler(svc PluginRegistryServiceHandler, opts ...c
|
|||||||
pluginRegistryServiceResolveInstallHandler.ServeHTTP(w, r)
|
pluginRegistryServiceResolveInstallHandler.ServeHTTP(w, r)
|
||||||
case PluginRegistryServiceListCategoriesProcedure:
|
case PluginRegistryServiceListCategoriesProcedure:
|
||||||
pluginRegistryServiceListCategoriesHandler.ServeHTTP(w, r)
|
pluginRegistryServiceListCategoriesHandler.ServeHTTP(w, r)
|
||||||
|
case PluginRegistryServiceListTagsProcedure:
|
||||||
|
pluginRegistryServiceListTagsHandler.ServeHTTP(w, r)
|
||||||
case PluginRegistryServiceSubmitForReviewProcedure:
|
case PluginRegistryServiceSubmitForReviewProcedure:
|
||||||
pluginRegistryServiceSubmitForReviewHandler.ServeHTTP(w, r)
|
pluginRegistryServiceSubmitForReviewHandler.ServeHTTP(w, r)
|
||||||
case PluginRegistryServiceListPrivatePluginsProcedure:
|
case PluginRegistryServiceListPrivatePluginsProcedure:
|
||||||
@ -589,6 +614,10 @@ func (UnimplementedPluginRegistryServiceHandler) ListCategories(context.Context,
|
|||||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.ListCategories is not implemented"))
|
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.ListCategories is not implemented"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (UnimplementedPluginRegistryServiceHandler) ListTags(context.Context, *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error) {
|
||||||
|
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.ListTags is not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
func (UnimplementedPluginRegistryServiceHandler) SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error) {
|
func (UnimplementedPluginRegistryServiceHandler) SubmitForReview(context.Context, *connect.Request[v1.SubmitForReviewRequest]) (*connect.Response[v1.SubmitForReviewResponse], error) {
|
||||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.SubmitForReview is not implemented"))
|
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("orchestrator.v1.PluginRegistryService.SubmitForReview is not implemented"))
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
2
proto
2
proto
@ -1 +1 @@
|
|||||||
Subproject commit 6d6445f74ec8152c0458257adf1f406d8ce8e68a
|
Subproject commit cdb50a77f284f2ae124ddd777c688d352e63ed0c
|
||||||
Loading…
x
Reference in New Issue
Block a user