sun1090's ZCode account has no GLM Coding Plan, only the Start Plan, whose buckets serve GLM-5.3 and GLM-5.3-Flash. The card counted GLM-5.3, but the plugin listed the Start Plan's config models (GLM-5.3-Flash, GLM-5.2, GLM-5-Turbo) and GLM-5.3 only as GLM-5.3-Trial. ZCode itself lists a Start Plan account's models as its balance's buckets name them, so 0.1.14 (magpie-community/plugins aca7c59) lists them by their own names too, and keeps the -Trial entries. keepMovedCurrent updates every moved ZCode user. The builtin check's note says the plugin now lists GLM-5.3 while a gift bucket serves it; the check itself is unchanged. 0.1.14 resolves with npm view and its publish run passed. The plugin's bun test (75) passes and its new test fails on 0.1.13. go test -tags nogui ./internal/provider under a temp HOME passes; GOOS=linux and GOOS=windows go vet pass. Not tried with a real Start Plan account here.
118 lines
4.8 KiB
Go
118 lines
4.8 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ZCode's accounts on @magpie-community/opencode-zcode-auth: the plan's
|
|
// key (else ZCode's session token) as the oauth entry's access, the rest
|
|
// the requests need as its refresh, as the plugin's own sign-in keeps
|
|
// them. Nothing here rotates: a key lasts until it is deleted.
|
|
//
|
|
// ZCode's own sign-in goes marked as ZCode's (source "zcode"), with a copy
|
|
// of what magpie reads now: the plugin, 0.1.2 on (the move installs no
|
|
// older), reads ZCode's own credentials in its place for each request, as
|
|
// the built-in does, so it follows ZCode's switches and the session token
|
|
// ZCode renews (the Start Plan).
|
|
func init() {
|
|
movers["zcode"] = &mover{
|
|
pkg: "@magpie-community/opencode-zcode-auth",
|
|
min: "0.1.14", // a gift-only account lists its gift's models by their own names, as ZCode does, so a Start Plan GLM-5.3 bucket's model is listed as GLM-5.3, not only GLM-5.3-Trial (#1261, plugins aca7c59); 0.1.13's claim line has one fixed name, which the GUI translates, so it no longer shares the "ZCode Trust Build" bucket window's name (plugins #43); 0.1.12's counted window carries its amount and limit, so the card's count follows used/left (#659, plugins #35); 0.1.11's gift plan ZCode holds but hasn't granted is named on the card, to claim in the ZCode app (plugins #30, #1001); 0.1.10's gift-only buckets and 0.1.9's trial entries (plugins #21) kept
|
|
agents: []string{"zcode"},
|
|
// the built-in never served GLM-5.3 to a Start Plan account, so
|
|
// its pick is no loss when the plugin doesn't list it (the plugin
|
|
// lists it, as ZCode does, only while a gift bucket serves it);
|
|
// its plan as its requests found it, else as it showed it, nothing
|
|
// asked of Z.ai
|
|
builtin: func(_ context.Context, a Moving, model string) bool {
|
|
for _, l := range zcodeLogins() {
|
|
if strings.EqualFold(l.User, a.User) {
|
|
return !zcodeOnStartAs(nil, l.key, l.Plan) || zcodeStartServes()(model)
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
out: func() ([]Moving, error) {
|
|
var out []Moving
|
|
for _, l := range zcodeLogins() {
|
|
// the own account's copy goes back to nothing: ZCode keeps it
|
|
out = append(out, Moving{User: l.User, First: l.Active, On: l.On, Lapsed: l.Lapsed != "", Plan: l.Plan, Own: l.Own, Auth: zcodeOut(l.User, l.Plan, l.key, l.Own)})
|
|
}
|
|
return out, nil
|
|
},
|
|
back: func(ls []savedLogin, user string, auth map[string]any) ([]savedLogin, string, error) {
|
|
var s struct {
|
|
Site, Device, Key, Base, JWT, Token, Org, Project, Plan, Source string
|
|
}
|
|
if json.Unmarshal([]byte(str(auth["refresh"])), &s) != nil {
|
|
// a key signed in to in the plugin
|
|
if str(auth["type"]) != "api" || str(auth["key"]) == "" {
|
|
return ls, "", errors.New("ZCode: an unreadable plugin sign-in")
|
|
}
|
|
s.Key = str(auth["key"])
|
|
if m, _ := auth["metadata"].(map[string]any); m != nil {
|
|
s.Site = str(m["site"])
|
|
}
|
|
} else if s.Key == "" && s.JWT == "" {
|
|
s.Key = str(auth["access"])
|
|
}
|
|
// ZCode's own goes back to nothing: ZCode keeps it
|
|
if _, _, ok := zcodeOwn(); ok && s.Source == "zcode" {
|
|
return ls, ownUser(ls, "zcode", firstNonEmpty(user, str(auth["accountId"]))), nil
|
|
}
|
|
k := zcodeKey{Key: s.Key, Base: s.Base, JWT: s.JWT, Token: s.Token, Org: s.Org, Project: s.Project}
|
|
if k.Base == "" {
|
|
k.Base = ZCodeZaiBase
|
|
if s.Site == "bigmodel" {
|
|
k.Base = ZCodeBigModelBase
|
|
}
|
|
}
|
|
if k.Key == "" && k.JWT == "" && !k.team() {
|
|
return ls, "", errors.New("ZCode: an unreadable plugin sign-in")
|
|
}
|
|
if user == "" {
|
|
user = firstNonEmpty(str(auth["accountId"]), "ZCode")
|
|
}
|
|
i := backInto(&ls, "zcode", user)
|
|
b, err := json.Marshal(k)
|
|
if err != nil {
|
|
return ls, "", err
|
|
}
|
|
ls[i].Auth, ls[i].Lapsed, ls[i].Seen = b, "", time.Now().UTC().Truncate(time.Second)
|
|
if s.Plan != "" {
|
|
ls[i].Plan = s.Plan
|
|
}
|
|
return ls, ls[i].User, nil
|
|
},
|
|
}
|
|
}
|
|
|
|
// zcodeOut is a ZCode account as the plugin's sign-in keeps one;
|
|
// ZCode's own is marked as ZCode's, for the plugin to follow.
|
|
func zcodeOut(user, plan string, k zcodeKey, own bool) map[string]any {
|
|
site := "zai"
|
|
if strings.Contains(k.Base, "bigmodel.cn") {
|
|
site = "bigmodel"
|
|
}
|
|
state := map[string]any{"site": site, "device": zcodeDeviceMid(), "base": k.Base}
|
|
if own {
|
|
state["source"] = "zcode"
|
|
}
|
|
for name, v := range map[string]string{"key": k.Key, "jwt": k.JWT, "token": k.Token, "org": k.Org, "project": k.Project, "plan": plan} {
|
|
if v != "" {
|
|
state[name] = v
|
|
}
|
|
}
|
|
expires := int64(0)
|
|
if k.Key == "" && !k.team() && !own { // ZCode's own is read anew each time
|
|
if exp, _ := jwtClaims(k.JWT)["exp"].(float64); exp > 0 {
|
|
expires = int64(exp) * 1000
|
|
}
|
|
}
|
|
return map[string]any{"type": "oauth", "access": firstNonEmpty(k.Key, k.JWT), "refresh": jsonText(state), "expires": expires, "accountId": user}
|
|
}
|