feat(ninja): prompt for tags in plugin init/edit flow
Add promptTagsWithDefault helper (mirrors promptCategoriesWithDefault) and wire it into the init flow so upsertPluginMod receives real user-entered tags instead of nil. ListTags RPC stub left with TODO(tags) marker for Task 12. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
6bc0f98979
commit
533632a3bb
@ -360,6 +360,10 @@ func newPluginInitCmd() *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tags, err := promptTagsWithDefault(ctx, cli, scanner, kind, existing.Plugin.Tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
createReq := &v1.CreatePluginRequest{
|
createReq := &v1.CreatePluginRequest{
|
||||||
ScopeSlug: scopeAPISlug(scope),
|
ScopeSlug: scopeAPISlug(scope),
|
||||||
@ -385,7 +389,7 @@ func newPluginInitCmd() *cobra.Command {
|
|||||||
if private {
|
if private {
|
||||||
modScope = ""
|
modScope = ""
|
||||||
}
|
}
|
||||||
if err := upsertPluginMod(modScope, name, displayName, description, kind, cats, nil, private); err != nil {
|
if err := upsertPluginMod(modScope, name, displayName, description, kind, cats, tags, private); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("plugin.mod updated")
|
fmt.Println("plugin.mod updated")
|
||||||
@ -600,6 +604,57 @@ func promptCategoriesWithDefault(ctx context.Context, cli *orchclient.Client, sc
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// promptTagsWithDefault prompts the user for free-form tags. Best-effort fetches
|
||||||
|
// the top-20 most-used tags via ListTags(kind) to surface popular suggestions;
|
||||||
|
// if that call fails (offline, etc.) it falls back to a plain prompt with a
|
||||||
|
// one-line warning. Empty input keeps `current`. Validates with NormalizeTags;
|
||||||
|
// on error, prints the issue and reprompts (one re-try, then bails).
|
||||||
|
func promptTagsWithDefault(ctx context.Context, cli *orchclient.Client, scanner *bufio.Scanner, kind string, current []string) ([]string, error) {
|
||||||
|
// Best-effort popular-tags lookup.
|
||||||
|
var popular string
|
||||||
|
// TODO(tags): re-enable once core regenerates proto bindings to expose v1.ListTagsRequest (plan Task 12).
|
||||||
|
// if resp, err := cli.Reg.ListTags(ctx, connect.NewRequest(&v1.ListTagsRequest{Kind: kind, Limit: 20})); err == nil {
|
||||||
|
// 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))
|
||||||
|
// }
|
||||||
|
// popular = strings.Join(parts, ", ")
|
||||||
|
// }
|
||||||
|
_ = ctx
|
||||||
|
_ = cli
|
||||||
|
|
||||||
|
for attempt := 0; attempt < 2; attempt++ {
|
||||||
|
if len(current) > 0 {
|
||||||
|
fmt.Printf("Tags (current: %s)\n", strings.Join(current, ", "))
|
||||||
|
} else {
|
||||||
|
fmt.Println("Tags (current: none)")
|
||||||
|
}
|
||||||
|
if popular != "" {
|
||||||
|
fmt.Printf("Popular: %s\n", popular)
|
||||||
|
} else if attempt == 0 {
|
||||||
|
fmt.Println("(could not fetch popular tags — offline or unauthenticated)")
|
||||||
|
}
|
||||||
|
fmt.Print("Enter comma-separated tags (blank to keep current): ")
|
||||||
|
if !scanner.Scan() {
|
||||||
|
return nil, fmt.Errorf("cancelled")
|
||||||
|
}
|
||||||
|
raw := strings.TrimSpace(scanner.Text())
|
||||||
|
if raw == "" {
|
||||||
|
return current, nil
|
||||||
|
}
|
||||||
|
parts := strings.Split(raw, ",")
|
||||||
|
out, err := core.NormalizeTags(parts)
|
||||||
|
if err == nil {
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
fmt.Printf(" %s\n", err.Error())
|
||||||
|
if attempt == 0 {
|
||||||
|
fmt.Println(" Try again:")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("tag input failed validation after 2 attempts")
|
||||||
|
}
|
||||||
|
|
||||||
// pickedSet returns a set of the given slugs for O(1) membership checks.
|
// pickedSet returns a set of the given slugs for O(1) membership checks.
|
||||||
func pickedSet(slugs []string) map[string]struct{} {
|
func pickedSet(slugs []string) map[string]struct{} {
|
||||||
s := make(map[string]struct{}, len(slugs))
|
s := make(map[string]struct{}, len(slugs))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user