feat(pool): one board of pools with split/merge by drag; plan names from tier and seat

- The Users page account pool is one board: a column per pool holding its
  Claude Code, Codex and Cursor accounts (plan, quota, live panes) and its
  members. Accounts sit in one pool; drag moves them. Drop on New pool to
  split one off; drag a pool's only account into another pool to merge
  (members follow, the emptied pool is deleted on Save). One password Save.
- Claude plan label (planLabel in cc-profiles.js) reads rateLimitTier and
  seatTier: Max 5x/20x, Team Standard/Premium — subscriptionType alone said
  'pro' after an upgrade and 'team' for both seats. Shown on profiles, the
  status bar quota badge and pool cards; Codex pool cards show the ChatGPT plan.
This commit is contained in:
2026-10-28 11:47:19 +07:00
parent 9d07f64154
commit 26aabd6660
18 changed files with 1638 additions and 642 deletions
+6
View File
@@ -810,6 +810,8 @@ export type PoolAccount = {
} | null;
quotaPercent: number | null;
full: boolean;
/** Readable plan of a login ("Max 5x", "Team Premium"); null for a setup-token. */
plan?: string | null;
};
/** One Codex pool account — an API key or a ChatGPT login, never the secret. */
export type CodexPoolAccount = {
@@ -828,6 +830,8 @@ export type CodexPoolAccount = {
} | null;
quotaPercent: number | null;
full: boolean;
/** A ChatGPT login's plan ("Plus", "Pro", "Team"); null for an API key. */
plan?: string | null;
};
/** A user an admin pinned to one pool account: their new sessions skip the balancer. */
export type AccountPin = {
@@ -4778,6 +4782,8 @@ export interface CcAccountIdentity {
organization: string | null;
seatTier: string | null;
subscriptionType: string | null;
/** Readable plan from tier + seat ("Max 5x", "Team Premium"); prefer it. */
plan?: string | null;
/** Access-token expiry, epoch ms; a switch still works past it (the refresh
* token is stored too). */
expiresAt: number | null;