package main import ( "context" "fmt" "io" "os" tea "github.com/charmbracelet/bubbletea" "proxyctl/internal/app" "proxyctl/internal/profile" "proxyctl/internal/shell" "proxyctl/internal/target" "proxyctl/internal/tui" ) func main() { if err := run(os.Args[1:], os.Stdin, os.Stdout); err != nil { fmt.Fprintln(os.Stderr, "proxyctl:", err) os.Exit(1) } } func run(args []string, input io.Reader, output io.Writer) error { executable, err := os.Executable() if err != nil { return fmt.Errorf("locate proxyctl executable: %w", err) } return runWithEnvironment(args, input, output, processEnvironment{}, shell.OSFileSystem{}, executable) } type processEnvironment struct{} func (processEnvironment) CurrentUser() (profile.UserIdentity, error) { return profile.SystemCurrentUser() } func (processEnvironment) LookupUser(name string) (profile.UserIdentity, error) { return profile.SystemLookupUser(name) } func (processEnvironment) LookupEnv(name string) (string, bool) { return os.LookupEnv(name) } func runWithEnvironment(args []string, input io.Reader, output io.Writer, environment profile.IdentityEnvironment, files shell.FileSystem, executable string) error { profileConfiguration, err := profile.ResolveConfiguration(environment) if err != nil { return err } shellConfiguration, err := shell.ResolveConfiguration(environment) if err != nil { return err } shellTarget := shell.New(shellConfiguration, files, environment) if len(args) != 0 { if len(args) != 2 || args[0] != "shell" || (args[1] != "install" && args[1] != "uninstall") { return fmt.Errorf("usage: proxyctl [shell install|shell uninstall]") } availability := shellTarget.Availability(context.Background()) if !availability.Available { return fmt.Errorf("Shell Target unavailable: %s", availability.Evidence) } if args[1] == "install" { if err := shellTarget.Install(context.Background(), executable); err != nil { return err } fmt.Fprintln(output, "Shell integration installed; restart or source your Shell startup file once.") return nil } if err := shellTarget.Uninstall(context.Background()); err != nil { return err } fmt.Fprintln(output, "Shell integration uninstalled.") return nil } store := profile.NewOwnedFileStoreAt(profileConfiguration.Path, profileConfiguration.Owner, profileConfiguration.TrustedRoot) application, err := app.NewWithTargets(store, []target.Target{shellTarget}) if err != nil { return err } program := tea.NewProgram(tui.NewModel(application), tea.WithInput(input), tea.WithOutput(output)) _, err = program.Run() return err }