diff --git a/internal/provider/account_order.go b/internal/provider/account_order.go index c81059a2..a1aaf821 100644 --- a/internal/provider/account_order.go +++ b/internal/provider/account_order.go @@ -10,6 +10,11 @@ func SetAccountOrder(id string, order []string) error { if err != nil { return err } + if p.IsPlugin() { + // a plugin's accounts are listed and switched by the provider's id, + // and kept in logins.json as plugin: + return arrangeLoginsAs(p.ID, pluginAgent(*p.Account.plugin), order) + } if p.Account != nil { return arrangeLogins(p.Account.Agent, order) } @@ -39,6 +44,12 @@ func SetAccountOrder(id string, order []string) error { } func arrangeLogins(agent string, order []string) error { + return arrangeLoginsAs(agent, agent, order) +} + +// arrangeLoginsAs arranges the accounts agent lists and switches, saved in +// logins.json under stored. +func arrangeLoginsAs(agent, stored string, order []string) error { var available []string var first Login for _, l := range Logins(agent) { @@ -64,7 +75,7 @@ func arrangeLogins(agent string, order []string) error { rank[user] = i + 1 } for i := range ls { - if ls[i].Agent == agent { + if ls[i].Agent == stored { before[ls[i].User] = ls[i].Order ls[i].Order = rank[ls[i].User] } @@ -86,7 +97,7 @@ func arrangeLogins(agent string, order []string) error { loginsMu.Lock() ls = readLogins() for i := range ls { - if ls[i].Agent == agent { + if ls[i].Agent == stored { ls[i].Order = before[ls[i].User] } } diff --git a/internal/provider/account_order_plugin_test.go b/internal/provider/account_order_plugin_test.go new file mode 100644 index 00000000..8227ab6b --- /dev/null +++ b/internal/provider/account_order_plugin_test.go @@ -0,0 +1,57 @@ +package provider + +import ( + "context" + "os/exec" + "path/filepath" + "reflect" + "testing" + "time" + + "github.com/yetone/magpie/internal/plugin" +) + +// A plugin provider's accounts are arranged like a built-in's: the page +// names them by the provider's id, magpie keeps them as plugin:, and +// the gateway tries them in the order dragged. +func TestAccountOrderPluginAccounts(t *testing.T) { + bun, err := exec.LookPath("bun") + if err != nil { + t.Skip("no bun on PATH") + } + claudeHome(t) + t.Setenv("MAGPIE_BUN", bun) + t.Cleanup(plugin.Settle) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + abs, _ := filepath.Abs("../plugin/testdata/fake/index.js") + if _, err := plugin.Add(ctx, abs); err != nil { + t.Fatal(err) + } + var rows []savedLogin + users := []string{"a@fake", "b@fake", "c@fake"} + for _, user := range users { + k, err := plugin.Import(ctx, "fakeco", map[string]any{"type": "oauth", "refresh": "r-" + user, "access": "a", "expires": 9e15, "accountId": user}) + if err != nil { + t.Fatal(err) + } + rows = append(rows, savedLogin{Agent: "plugin:fakeco", User: user, Home: k, On: true}) + } + saveLogins(t, rows...) + if _, err := plugin.Providers(ctx); err != nil { + t.Fatal(err) + } + id := PluginID("fakeco") + order := []string{"c@fake", "a@fake", "b@fake"} + if err := SetAccountOrder(id, order); err != nil { + t.Fatal(err) + } + shown, _ := loginUsers(Logins(id)) + p, err := Find(id) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(shown, order) || !reflect.DeepEqual(loginRoutingUsers(p), order) { + t.Fatalf("display=%v routing=%v", shown, loginRoutingUsers(p)) + } +}