Repository navigation
zcode-cli 3.8.1-27
Treat official-slot API key sign-in as login (vault token first, key second), clear official-slot keys on logout, and force-collect a user name on BigModel login bound to the key mapping
- API key sign-in counts as signed-in: sign-in detection upgrades from "vault OAuth token only" to a two-layer check (vault token first, official-slot key second), and logout clears official-slot keys as well (src/identity.ts, src/launcher.ts, packages/zcode-tui/src/index.ts, test/identity.test.ts, test/login-identity.test.ts, README.md, README_zh_hans.md, README_zh_hant.md, docs/CONFIGURATION.md).
- Why: 3.8.1-26 anchored sign-in state solely to the vault
oauth:<provider>:access_token. A user who completed /login by pasting an API key (the wizard reported success, the key landed in the official slot, the model switched to the official slot) still saw a "Not signed in" banner and no identity field in the status bar — the login flow said success while the identity display said signed out, a contradiction; it was also a display regression versus 3.8.1-25 (an official slot holding a key already showed a key identity) and violated the 3.8.1-26 principle that "a user action must produce correct feedback". The product ruling: a key pasted via /login is a login; only access through a custom-provider file (env-slots) counts as signed out. - What changed: (1) layered sign-in detection (new
readSignedInProvider()in src/identity.ts): a vault OAuth token wins; with no token, a key in the officialzai/bigmodelslots also counts as signed in (the official slotmodel.mainpoints to is checked first, otherwise scan zai-first); (2) key identity restored for key sign-ins (readLoginIdentitySnapshot()): a key sign-in shows the key identity while an OAuth sign-in still shows the account name with absolute priority;signedOutnarrows toenv--slot-only access; (3) mapping names never impersonate account identity (a second same-day ruling): names inbigmodel-users.jsonare user-chosen key aliases and two accounts may share a name, so the "Signed in as " phrasing is reserved for OAuth account sign-ins (the account name the system actually read); key sign-ins always use the "API key" phrasing — with a mapping:API key <name> (<masked key>)(the snapshot carries a newkeyMaskedfield), without:API key <masked key>— switching accounts (changing keys) necessarily changes the display, with one consistent reading across the banner / status bar /zcode identity/ thezcode loginalready-signed-in notice; (4) the launcher adopts the new detection (two places in src/launcher.ts): the startup-syncskipModelBlock(a signed-in user'smodelblock is not taken over by the env file) and the barezcode login"already signed in" gate both cover key sign-ins — after pasting a key and restarting, the model is no longer pinned back to anenv-slot; (5) logout clears official-slot keys (clearOAuthLoginCredentials()extended): beyond the vault it also clears the config official slots' apiKey (env-slots are kept to serve the signed-out path) — a key sign-out now truly returns to signed-out instead of "logged out but the identity lingers"; (6) TUI status bar fix (index.ts): asignedOutidentity no longer emits a status-bar field (the old logic rendered a stray emptyuserlabel); a named identity's prefix changes fromusertokeyand carries the masked key; (7)zcode identity setis refused in a key sign-in state and points to thebigmodel-users.jsonmapping (a key's display name belongs to the mapping file; only OAuth account names belong to identity set); (8) BigModel login force-collects a user name (user ruling: "however you sign in, running /login first forces a user-name entry"): any TUI /login that goes through a BigModel option (OAuth or pasting a key) — whether picked from the plain /login menu or typed as the command — pops a name input before the login runs (non-empty enforced, Esc cancels the login; the placeholder previews the key's existing mapping name); on success the name is automatically upserted intobigmodel-users.jsonbound to the landed key (newwriteBigmodelUserName()in src/bigmodel-users.ts; hand-edited and login-collected entries are equivalent and freely mixable), and the display immediately refreshes toAPI key <name> (<masked key>). Z.AI sign-ins are not asked (the OAuth flow itself writes back the account name); a failed or cancelled login writes nothing; (9) docs synced (the sign-in permission sections of all three READMEs, the Sign-in identity and custom-provider sections, CONFIGURATION.md's login definition, logout behavior, and key-mapping sections). - Behavior map: /login with a pasted key → the key lands in the official slot + the model switches to the official slot + the banner immediately shows "API key ()" or "API key " + the status bar shows a
key <name> (<masked>)field; restarting in a key sign-in state keeps the model on the official slot (the env file no longer takes over); /logout → vault + official-slot keys fully cleared, the banner returns to "Not signed in", and the env file takes the model back on the next start. OAuth sign-ins keep showing "Signed in as " exactly as in 3.8.1-26. - Verification:
tsc --noEmitpasses; fullbun test689 pass / 0 fail (78 files; identity gains 4 key-sign-in identity + 3 readSignedInProvider + 1 identity-set-in-key-state + 2 writeBigmodelUserName cases, the logout cases now assert official-slot keys are cleared, login-identity gains 3 key sign-in + 2 shouldPromptForLoginUserName cases); the release build's TUI smoke (scripts/smoke-tui.ts) adds live coverage of the user-name prompt — in the BigModel paste-key flow it waits for the name prompt after the key enter, typessmoketo continue the login, and adds a bannerAPI key smoke (<masked>)assertion plus abigmodel-users.jsonbinding assertion (the mapping file is addressed by the raw key, permission 0600, sits beside config.json as a sanctioned key store, joins the smoke leak whitelist, and is positively asserted). - Upstream research (2026-09-05, no code changes): confirmed upstream 3.11.2 (the official stable, three minors ahead of this project's locked 3.8.1) still fails to obtain the BigModel login user name — reversing the 3.11.2 runtime shows the shared credential store is structurally identical to 3.8.1 (only zai has a user_info slot) and
loginBigmodelCodingPlanis structure-for-structure isomorphic (authorize → exchangeCode → exchange key → write config, never fetching a user name); the official changelog corroborates (the only login-related entries after 3.8.1 are three stability fixes: expired sign-in state / authorization callback failure / mcp oauth failure). Incidental finding: during the key exchange the runtime callsGET bigmodel.cn/api/biz/customer/getCustomerInfo, whose response carries account / organization info but only the ID is kept and then discarded, and the accessToken is never persisted nor callable outside the flow — this spawned two follow-ups (T3: evaluate upgrading the runtime to 3.11.2; T4: research the key → account info API).
- Why: 3.8.1-26 anchored sign-in state solely to the vault
Install
npm install -g https://github.com/xhqing/zcode-cli/releases/download/v3.8.1-27/zcode-cli-3.8.1-27.tgz