Move first-party, sponsor and relay presets to current model IDs so a
pasted Key works without editing the model list.
- Claude: opus/sonnet 5 -> 5.5, haiku 4.5 -> 5.5, fable 5 -> 5.1
- GPT: gpt-5.6-sol / gpt-6-sol -> gpt-6.1-sol; add gpt-6-astra/luna
- Gemini 3.6 Flash -> 3.8 Flash, 3.1 Pro preview -> 4 Argon;
Grok 4.5 -> 4.7; GLM 5.1/5.2 -> 5.3 (+5.3 Flash);
DeepSeek V4 Flash -> V4.1 Flash; Doubao 2.1 Pro 260628 -> 260915;
StepFun Step Plan -> step-5-preview; add Kimi K3.1 Pro, Qwen3.8 Max,
MiniMax M3.1 Flash where the site serves them
- Drop retired models: NVIDIA moonshotai/kimi-k3 (EOL 2026-10-15,
now kimi-k2.6 without unverified Codex reasoning levels),
MiMo V2.5 / V2.5 Pro, Claude Sonnet 4.5, MiniMax M2.7 on Tencent
Token Plan Enterprise Pro
- Relay presets follow each site's own ID spelling and catalog;
DIT.ai, BuyToken and hao.ai are left as configured from their docs;
Soshow, SiliconFlow CN, OpenCode Zen and the Ark rolling alias stay
- MoArk Codex keeps the tested Kimi-K2.7-Code; K3.1 Pro and Qwen3.8
Max stay out of its Codex catalog until their levels are verified
Tests updated to the new IDs; cross-app invariants unchanged.
Tab counts were only queried for the active tab, so the model count stayed
blank until that tab was opened. Placeholder data was also hidden, so
switching apps made all three counts vanish and reappear, shifting the tab
bar. Query all three counts and keep the previous numbers until new data
arrives.
Request headers, omp model discovery and compat options now sit in a
collapsed "Advanced Options" section below the model list, matching the
Claude Code and Codex forms. It stays collapsed even when a preset fills
compat values.
The compat and discovery hints are rewritten in plain language, and the
discovery types get readable labels instead of raw omp identifiers. The
discovery select ignores an empty value, which Radix can report when it
mounts inside a form.
Checked against omp 18.12.6 with real DeepSeek and PackyCode requests:
- Usage queries sent an omp apiKey verbatim. omp reads it as an
environment variable name first (process environment, then .env in the
agent dir, the config root and home) and falls back to the literal, with
no $NAME syntax, so "apiKey: DEEPSEEK_API_KEY" reached the balance API as
"Bearer DEEPSEEK_API_KEY" and got 401. Resolve it the same way; names
match exactly, and "!command" values are still never run.
- With only a legacy models.json present, adding a provider created
models.yml, which stops omp from migrating models.json and drops the
user's providers. Refuse instead and ask the user to run omp once.
- omp disables every custom provider when one models.yml node fails its
schema. Reject the enum values it rejects before writing: compat
thinkingFormat, maxTokensField and the other enumerated fields
(including whenThinking), reasoningEffortMap levels, auth, authHeader,
and discovery type, injectV1 and timeoutMs.
- The form kept discovery.injectV1 when switching away from
openai-models-list, which omp allows only there. Drop it on switch.
Anthropic-protocol presets still omit auth on purpose: omp then shapes
requests like Claude Code, which relays such as PackyCode require (they
answer 403 to auth: apiKey).
The Pi form is shared with omp, but its duplicate-key check always
queried Pi's providers. Adding an omp provider whose key already
existed in Pi was flagged as a duplicate and blocked, even though the
backend keeps the two apps apart (each checks only its own rows and
its own models file). The check now follows the current app.
The Pi form (also used by omp) only filled a per-row dropdown after
"Fetch models", so models had to be added one row at a time, unlike the
OpenCode, Codex and Kimi Code forms. Use the shared FetchedModelPicker:
a successful fetch opens the dialog, checked models are added as rows
and filled from presets or models.dev (thinking level maps only for Pi),
and unchecking a configured model removes its row. Fetched IDs are
de-duplicated and the success toast is dropped since the dialog opens.
The per-row dropdown stays.
Oh My Pi also discovers MCP servers and skills from other agents'
directories, so what it loads can differ from what the matrix shows.
The note about this sat on the apps page, where it showed even before
Oh My Pi was installed and the "Docs: context-files" link did not say
what it was for.
Show the note in the Oh My Pi column popover of the MCP and Skills
matrices instead, and reword the link to say what it explains. The
apps page row now looks like every other app.
Claude Desktop was grouped by whether it was connected to CC Switch, so
an installed but unconnected Desktop showed up under "Not installed".
`get_claude_desktop_status` now reports `installed`. Desktop has no
command to probe, so it is inferred: connected, or Desktop's own data
directory (`Claude`, created on its first launch; `Claude-3p` is not
counted because CC Switch writes it too) exists, or on macOS a
Claude.app bundle is in /Applications or ~/Applications. The apps page
groups the Desktop row by it; the row still says whether it is connected.
Installed apps on the apps page can be reordered by dragging the handle
that appears at the start of a row on hover, the same way provider cards
are sorted. Only the installed section is sortable: where a missing app
sits does not matter, and while the first probe has not finished it is
not yet known which section a row belongs to.
There is a single order for all apps, saved as `appOrder` in the
device-level settings.json next to `visibleApps` (not cloud-synced). The
sidebar and the app opened by default follow it. Each section shows the
order filtered by install state, so an app keeps its relative position
when it moves between sections. Apps missing from a saved order, such as
ones added in a later version, are inserted after their default
predecessor; unknown ids are ignored.
The dragged row is kept inside its section's list box, which clips
overflow for the rounded corners, so it cannot disappear mid-drag.
The Simplified and Traditional Chinese copy for a failed quota query,
"额度没查到" / "額度沒查到", read as a casual remark rather than a status.
Use "额度查询失败" / "額度查詢失敗" on the provider card, in the auth
center's account quota column (including its defaultValue fallback) and
in the tray, where the two variants with a reason now read
"额度查询失败:登录已过期" and "额度查询失败:令牌待刷新".
English, Japanese and Turkish are unchanged. Tests and comments that
quoted the old wording are updated.
A balance at or below zero used to be replaced with "Balance used up" on
the provider card and in the tray. That hid how far an account was in
debt (DeepSeek reports -24.96 the same way as 0.00), and the red
sentence read like the red "quota unavailable" line, so a spent balance
and a failed query were hard to tell apart.
Always write "Balance <amount> <unit>"; at or below zero the whole line
turns red on the card and amber in the tray, as before. A negative zero
or a tiny negative amount that rounds to zero is written as 0.00 rather
than -0.00. The balanceUsedUp copy and the tray's balance_used_up text
are removed. Currency units stay as they are.
Refs #8812
The apps page listed every client in one table, so the few that are not
installed were mixed in with the ones in daily use. It now splits the
rows into "Installed · N" and "Not installed · N", like the added /
available sections of additive providers. The first section's title
takes the column header row; later sections get their own title row,
and empty sections are hidden.
A CLI counts as installed when a version was detected, it is installed
but not runnable, or the install report found a location -- the same
check that decides whether Uninstall is offered, now shared as
isToolPresent. Claude Desktop cannot be detected, so it is grouped by
whether it is connected to CC Switch.
Until the first detection has a result for every row, the page keeps a
single ungrouped table so rows do not jump one by one; later re-checks
reuse the cached results and rows stay put. The action column width is
re-measured when rows move between sections, since they remount.
Some managed ChatGPT workspaces disable device-code authentication, so those accounts could not be added to CC Switch. Add browser login (authorization code + PKCE with a loopback callback on port 1455) to the Auth Center and the Codex provider form, including reauthentication; device-code login stays available in a method selector.
Fixes#8284
Drop EveryAPI from the four README sponsor tables along with its banner,
remove its presets from the seven apps that carried them and its partner
promotion copy. The everyapi icon stays in the icon index because
providers users already added still reference it.
Kimi's /usages endpoint answers HTTP 200 with an empty object for an
account that has no Kimi Code subscription. The quota query succeeds
with no tiers, so both the account row in the auth center and the
official card's quota footer used to stay blank, which looked like a
failed lookup.
When the query succeeds but yields no tiers, the account row now writes
"No subscription" in the value column and the card footer writes it in
the quota column, keeping the refresh control. SubscriptionQuotaView
takes an optional emptyText for this; other callers are unchanged.
Official Kimi accounts added in the Authorization Center were written
straight into config.toml with the model list discovered at sign-in.
Kimi Code only refreshes its own managed:kimi-code node, so separate
accounts kept that snapshot forever, and their cards could neither be
edited nor removed.
Official cards can now be edited. The editor hides the connection and
fetches the account's own catalog through a new kimi_oauth_models
command (token refreshed under Kimi's lock, aliases keyed by the
credential slot), so picked models carry the official context window,
capabilities and efforts. apply_provider pins an official node's
connection to the signed-in one, and ProviderService::update rejects
edits that would turn another card into an official account.
Official cards can also be removed from config.toml like other Kimi
providers: the card and credential stay, services pointing at a
separate account move to Kimi's own login, and "Add" restores it.
Deleting one still requires removing it first or using the
Authorization Center.
Drop the copied OmpProviderForm and the YAML editor; Oh My Pi now uses
PiProviderForm with an omp mode (no provider-level name, no
thinkingLevelMap, plus a discovery type selector). Presets are derived
from the Pi catalog. Pi-family helpers (isPiFamilyApp, parametrized
current-state queries and usage-script command) replace the scattered
pi/omp branches, and omp error keys reuse the Pi error translator.
Co-authored-by: allenxu09 <s23372.xu@stu.scie.com.cn>
Match the binary name, the Apps page tool id and the i18n keys that
already used omp. The app is unreleased, so nothing persisted needs a
migration; ohmypi stays accepted as an alias when parsing app ids.
Show the app by default like Pi and Kimi Code.
Squashed from #6747 (head 50c3cec1d) onto current main: providers in
models.yml, MCP in mcp.json, Skills, sessions, app visibility and
directory override for Oh My Pi. Conflicts with the Kimi Code refresh
refactor in App.tsx and the locale files were resolved by keeping both
sides and routing Oh My Pi through refreshAdditiveLiveState.
Co-authored-by: allenxu09 <s23372.xu@stu.scie.com.cn>
While provider link A was still importing (awaiting the backend import or
the follow-up cache refresh), a second link B could arrive, replace the
displayed request and be acknowledged in the backend. When A's import
completed, handleImport unconditionally called setIsOpen(false), closing
B's confirmation even though B was never imported and could no longer be
fetched again.
Track the request currently shown in a ref (set together with setRequest
in showPending) and close the dialog after an import only if it still
shows the request that import started with. Add a regression test that
holds A's import, delivers B, then checks B stays open and still imports
and closes on its own.
Refs #8696
Add V-API (gpt.ge) as a full sponsor placed after BuyToken: README rows
and banner in all four languages, the partner promotion copy, an inline
tile icon, and presets for Claude Code, Claude Desktop, Codex, Gemini
CLI, Grok Build, OpenCode, OpenClaw, Hermes and Pi. The gateway prices
and gates models per token group, so each preset notes which group it
needs. It has no undated claude-haiku-4-5, so the Desktop Haiku tier is
mapped to claude-haiku-5-5.
Add BuyToken as a full sponsor placed after DIT.ai: README rows and
banner in all four languages, the partner promotion copy, an inline tile
icon, and presets for Claude Code, Claude Desktop, Codex, Grok Build,
OpenCode, OpenClaw, Hermes and Pi. Keys are bound to a model group, so
each preset notes which group's key it needs. The gateway only accepts
the dated claude-haiku-4-5-20251001 ID, so the Haiku tier is mapped to
it. There is no Gemini preset because /v1beta is not served.
The provider key, the model ID and display name column headings, and
the context window and max output labels now use REQUIRED_LABEL like
the rest of the provider forms, instead of a hand-written "*" span.
The asterisk is drawn by CSS, so it no longer becomes part of the
label text that screen readers and tests read.
The provider key names the provider node in models.json, so it is now
shown for presets too (prefilled, editable) instead of only for custom
and edited providers, matching Kimi Code. A key that is already used
by another Pi card is flagged under the field and blocks saving, so
adding the same preset twice no longer fails only at the backend.
Models are now one row each (expand arrow, model ID, display name,
delete) with capabilities and the context window in the expanded
details, instead of one large card per model. Fields follow the same
order as Pi and OpenCode (API format, API key, base URL), the API
format menu shows readable protocol names, request headers are shown
inline, and required fields use the shared asterisk style.
The new display name column writes the model's display_name, which
Kimi Code shows in /model; clearing it removes the field. The model
selection hint moves into a "?" beside the models heading, and the
Kimi-only labels that duplicated OpenCode's are removed from all
locales.
Custom headers are rarely needed for Kimi Code providers, so keep them
under an "Advanced options" section like the Claude and Codex forms.
It opens by itself when headers are already set, from an existing card
or a preset that carries them.
The Kimi Code form only let users type model IDs and context windows by
hand, unlike the other apps' forms. Add the same "Fetch models" picker
and per-row dropdown: picking models adds them with tool use enabled,
then fills the context window, thinking and image input from the
matching preset or models.dev entry (the endpoint decides which). A
window the user typed is never overwritten; rows still on the
placeholder window take the looked-up value. Anthropic and Gemini
providers fetch with their own auth header.
When the user sat on page 2+ and the total dropped (the "today" window
rolled over, Codex usage was rebuilt), the page index stayed out of
range. With a single page the pagination bar is hidden, leaving an
empty table with no way back. Pull the page back to the last valid one
once real (non-placeholder) data arrives.
Each FullScreenPanel adds its own keydown listener on window, and
stopPropagation does not stop other listeners on the same target, so
stacked panels (pricing -> pricing editor, edit provider -> endpoint
speed test) all closed on a single Escape. Track open panels in a
module-level stack and only let the top one react.
The default provider in OpenCode, OpenClaw, Hermes and Kimi used a gray
card and dot. Use the same blue as an in-use switch-mode card instead,
and drop the now-unused neutral card tone.
Kimi is additive, but both card groups only offered "Switch", which
wrote the provider into config.toml and changed default_model at once,
so the Added / Available split did nothing.
- Available cards get "Add": a new add_provider_to_live_config command
writes the provider and its models into config.toml without changing
default_model, so they show up in Kimi's /model list. A node already in
config.toml belongs to Kimi and is never overwritten from the archive.
- Added cards get a "Remove" button; "Set as default" (select the
provider's model) moves into the more menu, as for OpenCode/OpenClaw.
- The provider owning default_model is marked with the gray "Default"
status like OpenCode, and cannot be removed.
Kimi's account list drew its own layout (inline description, a permanent
region picker, highlighted current row, extra badges). It now uses the
same ManagedAccountsGroup as Copilot, ChatGPT, xAI and Antigravity:
help behind "?", region chosen when adding an account, "In use by Kimi"
badge, nickname and avatar, shared pending/error blocks, and a
"needs re-login" state for signed-out accounts.
The shared group gains optional per-row remove label and disabled
reason, an optional "remove all" action, and a looser device-code type.
Account action failures now toast instead of reusing the login error
block. Unused Kimi strings are removed from all locales.
The icon-only star on added OpenCode/OpenClaw cards was hard to read and
had no selected state. "Set as default" now sits at the top of the card's
more menu, like the aggregation page; providers with several models open
a submenu to pick the default model. The card keeps only the remove
button, and the primary button no longer needs its own dropdown.
Follow-up to #8726, which lets the Authorization Center hold several Kimi
official subscriptions, each with its own provider and credential slot.
Identity: after sign-in (and for logins found on disk) read /me to show
the account's nickname on its row and card. Signing in to an account that
is already listed writes back to its slot instead of adding a duplicate,
and the slot is chosen when the login completes, so a native Kimi login
made meanwhile is never overwritten. New separate slots are named from a
hash of region and user id, stable across devices. Opening the Kimi page
reads identities too, so card names carry the nickname without a visit to
the Authorization Center first.
Remove instead of sign out: a separate account is deleted together with
its provider node, models, credential and card (refused while in use);
web search/fetch pointing at it moves to Kimi's own default login. Kimi's
own login is only hidden from the list - CC Switch never logs Kimi out -
and stays hidden across Kimi's token rotations until the user signs in to
it again here. An empty list caused by that says so instead of "signed
out".
Quota: each account row and official card shows its quota. Tokens close
to expiry are refreshed under the same proper-lockfile-compatible lock
Kimi uses (mkdir <slot>.lock, 5 s stale takeover), with Kimi's revoked
token recovery. Windows, where Kimi takes no lock, only reads.
Also: re-login keeps custom fields such as custom_headers on the node;
deleting a card whose node was removed elsewhere deletes the leftover
CC Switch-owned credential; the card's switch button works for official
accounts after checking they are signed in on this machine; account rows
use the same compact layout as the other Authorization Center groups.
Picking a model from the fetched list fills its empty catalog fields from
known metadata (same-endpoint preset, models.dev). For a model the lookup
reported as text-only, the Codex fill wrote inputModalities ["text"].
For Codex an absent inputModalities is not "unknown = text": the backend
checks the exact text-only registry and otherwise fails open to
["text", "image"]. Writing ["text"] therefore switched image input off,
against the fill rule that modalities are only ever turned toward
"supported", and the Codex form has no control to switch it back, so
Codex kept refusing image attachments for that model.
Only fill inputModalities when the metadata includes image; otherwise
leave it absent and let the registry and fail-open default decide.
Refs #8682
* feat(usage): restructure the usage page layout
- Header: one sync button that shows when it last synced, next to a settings
button; the settings sheet now holds data sources, display and pricing.
- Scope bar: date first, app chips, and one cascading provider / model menu.
- Overview: a selectable metric strip drives the trend chart and heatmap; the
four token parts fold into an expandable second row. Hit-rate axis starts
near the lowest value; hourly labels are short; new terracotta chart color.
- Detail panel: tabs with counts; tables scroll sideways at natural column
widths, pin the time / app columns, group columns with wider gaps, and
animate rows that arrive on refresh.
- Request detail drawer: no per-row dividers, no duplicate session rows.
- Empty values show an em dash; dark-mode surfaces use one token per role.
* feat(usage): let people pick how many request logs fit on a page
The pagination bar gets a rows-per-page menu (10 / 20 / 50, default 20),
remembered on this device. It stays visible on a single page as long as
there are more rows than the smallest size, so a larger choice can still be
undone. Changing the size keeps the first visible row on screen, and the
rows it adds are not animated as newly arrived requests.
* fix(usage): polish details found in review
- New-row highlight keeps a pinned column's edge shadow instead of replacing it.
- Pinned cells only follow row hover on rows that can be clicked.
- Update a stale comment about the metric strip spacing.
* fix(usage): fix issues found in branch review
- Heatmap in hit-rate mode: a day with traffic but a 0% hit rate is now
shaded instead of looking idle, and the tooltip shows the hit rate.
The heatmap reuses the trend chart's hitRateOf instead of its own copy.
- Turkish: add the request log column labels and the columns menu title.
- Sync button: when auto scan is off, the tooltip says so.
- Columns menu: concurrent saves no longer drop later toggles; a failed
save reverts only once the last save returns.
- Tab counts query only the open tab; other tabs show their cached count.
- UsageDashboard uses the shared useElementWidth instead of its own copy.
- Note the two-column limit of the pinned-column offset.
* fix(usage): keep heatmap tooltip rows on one line
The added hit-rate row made the label column wider, so the card near
the right edge wrapped values like "7640.5 万" and the label itself.
* fix(usage): shorten the auto-scan-off sync tooltip to one line
The longer sentence wrapped inside the pill-shaped tooltip and broke
mid-word.
* fix(usage): open pricing as a sub-page so its editor can be used
Pricing lived in a modal Dialog, but the add/edit pricing editor is a
FullScreenPanel portaled into #content-area. The dialog's overlay sat
above it and Radix set pointer-events: none on body while the dialog was
open, so the editor's fields and save button could not be used. Pricing
is now a FullScreenPanel too, the same pattern as other nested panels.
* fix(usage): show exact metric values in the app tooltip
The metric strip used native title attributes for the exact numbers.
Use HoverTip instead, anchored to the number and opening to the right,
so it does not cover the expanded token row. No tip while the cell
shows a placeholder.
* feat(kimi): manage multiple official accounts in auth center
Isolate account credentials, providers and model aliases; preserve native logins and protect official OAuth nodes. Fix session image access, drop unpublished usage repair paths and the kimi-cli alias, and synchronize all four READMEs.
* fix(kimi): address account compatibility review feedback
Restore the native default credential slot for the first account, stop rewriting tool services on account switches, allow deleting profiles removed from native config, and fix official-account test fixtures and documentation.
* fix(kimi): pin OAuth endpoints to the login region
Use fixed official hosts for mainland and global sign-ins, keep existing account regions and credential slots during reauthentication, and preserve sanitized transport error causes. Add regional routing and network-error regression coverage.
Add Kimi Code as the 12th managed app (additive mode): native multi-provider config in ~/.kimi-code/config.toml (honors KIMI_CODE_HOME), presets derived from the Pi catalog, MCP (stdio/HTTP/SSE), Skills with native-directory protection, global prompts, session browsing/resume, and session-log usage import. Local routing and aggregation do not apply; official OAuth stays managed by Kimi Code. Schema v21 -> v22 adds enabled_kimi columns.
Add hao.ai as a full sponsor placed above Fenno: README rows and banner
in all four languages, the partner promotion copy, an inline tile icon,
and presets for Claude Code, Claude Desktop, Codex, Grok Build, OpenCode,
OpenClaw, Hermes and Pi. hao.ai serves Anthropic Messages under
/anthropic, OpenAI-compatible APIs under /v1 and xAI under /x-ai/v1, and
its catalog IDs carry a provider prefix. There is no Gemini preset since
the catalog has no Gemini models.
DIT.ai (dit.ai), an AI token exchange routing each request across
competing providers, joins as a sponsor, placed directly below GrooRoute
Pro in the sponsor order (OpenModel in the Gemini file, which has no
GrooRoute preset).
- One key on api.dit.ai serves Chat Completions, Responses, Anthropic
Messages and native Gemini (protocol docs at dit.ai/docs, catalog at
dit.ai/models, checked 2026-10-21).
- The gateway has no Haiku 5.5 and only the dated
claude-haiku-4-5-20251001, so Claude Code overrides the Haiku tier with
it and Claude Desktop maps Sonnet 5.5 / Opus 5.5 / that Haiku.
- OpenCode, OpenClaw, Hermes and Pi use Anthropic Messages with Claude
Opus 5.5 and Sonnet 5.5; Codex uses Responses with gpt-5.6-sol, Grok
Build grok-4.7, Gemini CLI gemini-3.8-flash.
- Four-locale README sponsor rows with a banner, four-locale promo copy
with the "ccswitch" coupon, and an inline icon from the official logo.
- Claude preset rows in the selector test go from 105 to 106.
ZetaAPI is no longer a sponsor; its presets go too.
- Drop the four-locale README sponsor rows and the banner.
- Remove the ZetaAPI presets from Claude Code, Claude Desktop, Codex,
Grok Build, OpenCode, OpenClaw, Hermes and Pi.
- Remove partnerPromotion.zetaapi from every locale, Turkish included.
- Keep the zetaapi icon: existing providers saved from the preset still
reference that icon key.
The frontend map of session placeholder names missed
"Antigravity (Session)", so the provider column showed the raw English
name and truncated it. Add the entry and a test that every placeholder
name in usage_stats.rs is translated.
The card keeps one line per group (Gemini, Claude/GPT) to fit, so the
5-hour and weekly windows could not both be seen anywhere on it. On
Antigravity cards the quota column is now one dropdown, like the resets
dropdown on Codex official cards, listing every window with its own
reset time. Refreshing moves to the ↻ button that appears on hover.
Other cards keep click-to-refresh.
An official Antigravity card bound to an Auth Center account showed the
quota of whatever account agy was signed in with, which is a different
account until the card's terminal is opened. It now shows the bound
account's quota, shared with that account's row in the Auth Center, and
like Codex account cards it shows even when the card is not current.
Cards that follow agy's sign-in, and platforms that cannot switch
accounts, keep the signed-in quota.
Every Antigravity row in the Auth Center now has a quota column, the
same one Copilot, ChatGPT and xAI rows use: Gemini and Claude/GPT, each
with a 5-hour and a weekly window. It is queried once when the page
opens and on the refresh button, through agy_account_quota, so accounts
agy is not signed in with show quota too. Accounts that need to sign in
again get no quota column.
An official Antigravity card can now pick one of the Auth Center accounts
(macOS only). With an account picked, Open Terminal first switches agy's
global sign-in to it; when it is already signed in, nothing is written.
Without one, the card keeps following whatever agy is signed in with.
The binding is stored as authBinding with authProvider "agy_oauth". The
account id is the Google subject, so a card synced to another computer
works once the same account is added there; if it is missing, opening the
terminal stops with a message instead of launching under another account.
Platforms that cannot switch ignore the binding and keep it on the card.
The Open Terminal dialog says when opening will switch agy's sign-in, and
warns when agy is already running. The Auth Center counts bound cards as
users of an account, so the removal dialog lists them.
On macOS the Auth Center now lists Antigravity accounts next to Copilot,
ChatGPT and xAI. The account agy is signed in with is tagged "In use by
agy", and "Switch agy to this account" in the row menu replaces agy's
sign-in. After switching, CC Switch checks whether agy is running and
warns that open sessions keep the old account and may write it back.
Adding an account opens Google's sign-in page in the browser. The shared
login hook treats a response without a user code as this browser flow: it
leaves the clipboard alone, polls the local result every 1.5 seconds and
cancels the backend flow so the callback port is released. The pending
block shows a "reopen sign-in page" button instead of a device code.
Removing an Antigravity account says that agy stays signed in.
The backend now records the sign-in time in seconds, which is what the
Auth Center formats.