package cli import ( "fmt" "github.com/spf13/cobra" "github.com/anomalyco/opencode-provider-switch/internal/opencode" ) func newOpencodeCmd() *cobra.Command { c := &cobra.Command{ Use: "opencode", Short: "OpenCode integration commands", } c.AddCommand(newOpencodeSyncCmd()) return c } func newOpencodeSyncCmd() *cobra.Command { var target string var setModel string var setSmallModel string var dryRun bool cmd := &cobra.Command{ Use: "sync", Short: "Update provider.olpx in the global OpenCode config to match current aliases", Long: `olpx opencode sync writes provider.olpx into the target OpenCode config. By default it targets the global user config (~/.config/opencode), picking the existing file in precedence order opencode.jsonc > opencode.json > config.json, or creating opencode.jsonc if none exists. It does NOT touch the top-level "model" or "small_model" unless --set-model / --set-small-model are given.`, RunE: func(cmd *cobra.Command, args []string) error { cfg, err := loadCfg() if err != nil { return err } if errs := cfg.Validate(); len(errs) > 0 { for _, e := range errs { cmd.PrintErrln("config error:", e) } return errs[0] } path := target if path == "" { p, _ := opencode.ResolveGlobalConfigPath() path = p } raw, err := opencode.Load(path) if err != nil { return err } aliasNames := cfg.AvailableAliasNames() baseURL := fmt.Sprintf("http://%s:%d/v1", cfg.Server.Host, cfg.Server.Port) changed := opencode.EnsureOLPXProvider(raw, baseURL, cfg.Server.APIKey, aliasNames) if setModel != "" { if raw["model"] != setModel { raw["model"] = setModel changed = true } } if setSmallModel != "" { if raw["small_model"] != setSmallModel { raw["small_model"] = setSmallModel changed = true } } if !changed { fmt.Fprintf(cmd.OutOrStdout(), "✓ no changes required at %s\n", path) return nil } if dryRun { fmt.Fprintf(cmd.OutOrStdout(), "would write %s (dry-run)\n", path) return nil } if err := opencode.Save(path, raw); err != nil { return err } fmt.Fprintf(cmd.OutOrStdout(), "synced provider.olpx into %s (%d alias(es))\n", path, len(aliasNames)) if setModel != "" { fmt.Fprintf(cmd.OutOrStdout(), " model = %s\n", setModel) } if setSmallModel != "" { fmt.Fprintf(cmd.OutOrStdout(), " small_model = %s\n", setSmallModel) } return nil }, } cmd.Flags().StringVar(&target, "target", "", "explicit opencode config file to write (default: global)") cmd.Flags().StringVar(&setModel, "set-model", "", "also set top-level model (opt-in only)") cmd.Flags().StringVar(&setSmallModel, "set-small-model", "", "also set top-level small_model (opt-in only)") cmd.Flags().BoolVar(&dryRun, "dry-run", false, "do not write, just report intent") return cmd }