131 lines
3.4 KiB
Go
131 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/yetone/magpie/internal/provider"
|
|
)
|
|
|
|
// accountsCmd: `magpie accounts [agent]`, `magpie accounts add <agent>`,
|
|
// `magpie accounts switch|forget <agent> <email>`
|
|
// — the Claude Code and Codex subscriptions magpie remembers, and switching
|
|
// the agent between them.
|
|
func accountsCmd(args []string) error {
|
|
const usage = "usage: magpie accounts [claude|codex] | magpie accounts add <claude|codex> | magpie accounts switch|forget <claude|codex> <email>"
|
|
agentID := func(s string) (string, error) {
|
|
switch strings.ToLower(s) {
|
|
case "claude", "cc":
|
|
return "claude", nil
|
|
case "codex":
|
|
return "codex", nil
|
|
}
|
|
return "", fmt.Errorf("%q: only Claude Code and Codex accounts can be switched\n%s", s, usage)
|
|
}
|
|
if len(args) > 1 && args[1] == "add" {
|
|
if len(args) != 3 {
|
|
return fmt.Errorf("%s", usage)
|
|
}
|
|
id, err := agentID(args[2])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return addAccount(id)
|
|
}
|
|
if len(args) > 1 && (args[1] == "switch" || args[1] == "forget") {
|
|
if len(args) != 4 {
|
|
return fmt.Errorf("%s", usage)
|
|
}
|
|
id, err := agentID(args[2])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if args[1] == "forget" {
|
|
if err := provider.ForgetLogin(id, args[3]); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(green.Render("✓"), "forgot", args[3])
|
|
return nil
|
|
}
|
|
if err := provider.SwitchLogin(id, args[3]); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(green.Render("✓"), id, "is now signed in as", args[3], muted.Render("· sessions already running keep their account until restarted"))
|
|
return nil
|
|
}
|
|
which := ""
|
|
if len(args) > 1 {
|
|
id, err := agentID(args[1])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
which = id
|
|
}
|
|
ls := provider.Logins(which)
|
|
if len(ls) == 0 {
|
|
fmt.Println(muted.Render("no accounts yet ·"), "add one: magpie accounts add <claude|codex>")
|
|
return nil
|
|
}
|
|
for _, l := range ls {
|
|
mark := " "
|
|
if l.Active {
|
|
mark = green.Render("● ")
|
|
}
|
|
plan := ""
|
|
if l.Plan != "" {
|
|
plan = muted.Render(" · " + l.Plan)
|
|
}
|
|
fmt.Printf("%s%-7s %s%s\n", mark, l.Agent, l.User, plan)
|
|
}
|
|
fmt.Println(faint.Render(" add one: magpie accounts add <agent> · switch: magpie accounts switch <agent> <email>"))
|
|
return nil
|
|
}
|
|
|
|
// addAccount signs in to one more subscription in the browser, the way the
|
|
// window's "Add account" does.
|
|
func addAccount(agentID string) error {
|
|
st, err := provider.StartSignIn(agentID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("Finish signing in in your browser. If it didn't open, go to:")
|
|
fmt.Println(faint.Render(st.URL))
|
|
openInBrowser(st.URL)
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
defer stop()
|
|
st, err = provider.WaitSignIn(ctx, st.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
switch st.State {
|
|
case "done":
|
|
if st.Using {
|
|
fmt.Println(green.Render("✓"), agentID, "is signed in as", st.User)
|
|
} else {
|
|
fmt.Println(green.Render("✓"), "added", st.User, muted.Render("· use it: magpie accounts switch "+agentID+" "+st.User))
|
|
}
|
|
return nil
|
|
case "failed":
|
|
return fmt.Errorf("sign-in didn't finish: %s", st.Error)
|
|
}
|
|
return fmt.Errorf("sign-in canceled")
|
|
}
|
|
|
|
func openInBrowser(url string) {
|
|
var cmd *exec.Cmd
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
cmd = exec.Command("open", url)
|
|
case "windows":
|
|
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
|
|
default:
|
|
cmd = exec.Command("xdg-open", url)
|
|
}
|
|
_ = cmd.Start()
|
|
}
|