opencode-provider-switch/internal/cli/root.go
apale7 cf3dcec399 refactor(cli): rename tool to ocswitch
Avoid collision with the existing Opswitch product while keeping the repository name as opencode-provider-switch.

This aligns the CLI, provider key, config paths, examples, and Trellis history under one public-facing name.
2026-04-17 21:43:21 +08:00

68 lines
2.3 KiB
Go

// Package cli wires the ocswitch cobra command tree.
package cli
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/Apale7/opencode-provider-switch/internal/config"
)
// configPath is populated from the global --config flag.
var configPath string
// loadCfg opens the active ocswitch config, with the selected path.
func loadCfg() (*config.Config, error) {
return config.Load(configPath)
}
// NewRootCmd builds the root ocswitch command.
func NewRootCmd(version string) *cobra.Command {
root := &cobra.Command{
Use: config.AppName,
Short: "OpenCode Provider Switch CLI: local alias + failover proxy for OpenCode",
Long: `ocswitch is a local OpenCode proxy that exposes stable aliases as ocswitch/<alias>
while routing each alias to one or more upstream provider/model targets.
Typical workflow:
1. add or import upstream providers into local ocswitch config
2. create aliases and bind ordered targets
3. run doctor for static validation
4. run opencode sync to write provider.ocswitch into OpenCode config
5. run serve to accept local /v1/responses traffic
ocswitch writes only its own local config unless a command explicitly says it also
writes OpenCode config. For exact command behavior, defaults, and side effects,
prefer command-local --help over README summaries.`,
Example: ` ocswitch provider add --id su8 --base-url https://cn2.su8.codes/v1 --api-key sk-example
ocswitch alias add --name gpt-5.4 --display-name "GPT 5.4"
ocswitch alias bind --alias gpt-5.4 --provider su8 --model gpt-5.4
ocswitch doctor
ocswitch opencode sync
ocswitch serve
ocswitch provider import-opencode
ocswitch provider list
ocswitch opencode sync --dry-run`,
SilenceUsage: true,
SilenceErrors: false,
Version: version,
}
root.PersistentFlags().StringVar(&configPath, "config", "", fmt.Sprintf("path to %s config.json (default: $%s, else $XDG_CONFIG_HOME/%s/config.json, else ~/.config/%s/config.json)", config.AppName, config.ConfigEnvVar, config.ConfigDirName, config.ConfigDirName))
root.AddCommand(newServeCmd())
root.AddCommand(newDoctorCmd())
root.AddCommand(newProviderCmd())
root.AddCommand(newAliasCmd())
root.AddCommand(newOpencodeCmd())
return root
}
// fail prints to stderr and exits 1.
func fail(format string, args ...any) {
fmt.Fprintf(os.Stderr, "error: "+format+"\n", args...)
os.Exit(1)
}