195 lines
5.4 KiB
Go
195 lines
5.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/anomalyco/opencode-provider-switch/internal/config"
|
|
)
|
|
|
|
func newAliasCmd() *cobra.Command {
|
|
c := &cobra.Command{
|
|
Use: "alias",
|
|
Short: "Manage logical aliases routed by olpx",
|
|
}
|
|
c.AddCommand(newAliasAddCmd(), newAliasListCmd(), newAliasBindCmd(), newAliasUnbindCmd(), newAliasRemoveCmd())
|
|
return c
|
|
}
|
|
|
|
func newAliasAddCmd() *cobra.Command {
|
|
var name, display string
|
|
var disabled bool
|
|
cmd := &cobra.Command{
|
|
Use: "add",
|
|
Short: "Create or update an alias (without targets)",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if name == "" {
|
|
return fmt.Errorf("--name is required")
|
|
}
|
|
cfg, err := loadCfg()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
existing := cfg.FindAlias(name)
|
|
a := config.Alias{Alias: name, DisplayName: display, Enabled: !disabled}
|
|
if existing != nil {
|
|
if display == "" {
|
|
a.DisplayName = existing.DisplayName
|
|
}
|
|
a.Enabled = existing.Enabled
|
|
if disabled {
|
|
a.Enabled = false
|
|
}
|
|
a.Targets = existing.Targets
|
|
}
|
|
cfg.UpsertAlias(a)
|
|
if err := cfg.Save(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), "saved alias %q (enabled=%v)\n", name, a.Enabled)
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().StringVar(&name, "name", "", "alias name exposed as olpx/<name> in OpenCode (required)")
|
|
cmd.Flags().StringVar(&display, "display-name", "", "human-friendly display name")
|
|
cmd.Flags().BoolVar(&disabled, "disabled", false, "create in disabled state")
|
|
return cmd
|
|
}
|
|
|
|
func newAliasListCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "list",
|
|
Short: "List aliases and their target chains",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
cfg, err := loadCfg()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
aliases := append([]config.Alias(nil), cfg.Aliases...)
|
|
sort.Slice(aliases, func(i, j int) bool { return aliases[i].Alias < aliases[j].Alias })
|
|
if len(aliases) == 0 {
|
|
fmt.Fprintln(cmd.OutOrStdout(), "(no aliases)")
|
|
return nil
|
|
}
|
|
for _, a := range aliases {
|
|
state := "enabled"
|
|
if !a.Enabled {
|
|
state = "disabled"
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), "%s [%s]\n", a.Alias, state)
|
|
for i, t := range a.Targets {
|
|
mark := "x"
|
|
if !t.Enabled {
|
|
mark = " "
|
|
}
|
|
note := ""
|
|
provider := cfg.FindProvider(t.Provider)
|
|
switch {
|
|
case provider == nil:
|
|
note = " (missing provider)"
|
|
case !provider.IsEnabled():
|
|
note = " (provider disabled)"
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), " [%s] %d. %s/%s%s\n", mark, i+1, t.Provider, t.Model, note)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func newAliasBindCmd() *cobra.Command {
|
|
var alias, provider, model string
|
|
var disabled bool
|
|
cmd := &cobra.Command{
|
|
Use: "bind",
|
|
Short: "Append a target (provider/model) to an alias in failover order",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if alias == "" || provider == "" || model == "" {
|
|
return fmt.Errorf("--alias, --provider and --model are required")
|
|
}
|
|
cfg, err := loadCfg()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if cfg.FindProvider(provider) == nil {
|
|
return fmt.Errorf("provider %q does not exist; add it first", provider)
|
|
}
|
|
if cfg.FindAlias(alias) == nil {
|
|
// auto-create enabled alias for ergonomics
|
|
cfg.UpsertAlias(config.Alias{Alias: alias, Enabled: true})
|
|
}
|
|
if err := cfg.AddTarget(alias, config.Target{Provider: provider, Model: model, Enabled: !disabled}); err != nil {
|
|
return err
|
|
}
|
|
if err := cfg.Save(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), "bound %s → %s/%s\n", alias, provider, model)
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().StringVar(&alias, "alias", "", "alias name (required)")
|
|
cmd.Flags().StringVar(&provider, "provider", "", "upstream provider id (required)")
|
|
cmd.Flags().StringVar(&model, "model", "", "upstream model id (required)")
|
|
cmd.Flags().BoolVar(&disabled, "disabled", false, "add target in disabled state")
|
|
return cmd
|
|
}
|
|
|
|
func newAliasUnbindCmd() *cobra.Command {
|
|
var alias, provider, model string
|
|
cmd := &cobra.Command{
|
|
Use: "unbind",
|
|
Short: "Remove a target from an alias",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if alias == "" || provider == "" || model == "" {
|
|
return fmt.Errorf("--alias, --provider and --model are required")
|
|
}
|
|
cfg, err := loadCfg()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := cfg.RemoveTarget(alias, provider, model); err != nil {
|
|
return err
|
|
}
|
|
if err := cfg.Save(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), "unbound %s → %s/%s\n", alias, provider, model)
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().StringVar(&alias, "alias", "", "alias name (required)")
|
|
cmd.Flags().StringVar(&provider, "provider", "", "upstream provider id (required)")
|
|
cmd.Flags().StringVar(&model, "model", "", "upstream model id (required)")
|
|
return cmd
|
|
}
|
|
|
|
func newAliasRemoveCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "remove <alias>",
|
|
Args: cobra.ExactArgs(1),
|
|
Short: "Delete an alias entirely",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
cfg, err := loadCfg()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !cfg.RemoveAlias(args[0]) {
|
|
return fmt.Errorf("alias %q not found", args[0])
|
|
}
|
|
if err := cfg.Save(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(cmd.OutOrStdout(), "removed alias %q\n", args[0])
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
// unused helper kept for clarity if future commands want to normalize lists
|
|
var _ = strings.TrimSpace
|