@cortexkit/opencode-antigravity-auth 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +24 -8
  2. package/dist/index.js +1299 -431
  3. package/dist/index.js.map +4 -4
  4. package/dist/src/plugin/accounts.d.ts +29 -9
  5. package/dist/src/plugin/accounts.d.ts.map +1 -1
  6. package/dist/src/plugin/accounts.js +253 -52
  7. package/dist/src/plugin/accounts.js.map +1 -1
  8. package/dist/src/plugin/agy-request-metadata.d.ts +2 -0
  9. package/dist/src/plugin/agy-request-metadata.d.ts.map +1 -0
  10. package/dist/src/plugin/agy-request-metadata.js +2 -0
  11. package/dist/src/plugin/agy-request-metadata.js.map +1 -0
  12. package/dist/src/plugin/auth-doctor.d.ts +1 -1
  13. package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
  14. package/dist/src/plugin/auth-doctor.js +9 -0
  15. package/dist/src/plugin/auth-doctor.js.map +1 -1
  16. package/dist/src/plugin/image-saver.d.ts +2 -21
  17. package/dist/src/plugin/image-saver.d.ts.map +1 -1
  18. package/dist/src/plugin/image-saver.js +29 -63
  19. package/dist/src/plugin/image-saver.js.map +1 -1
  20. package/dist/src/plugin/request-helpers.d.ts +1 -0
  21. package/dist/src/plugin/request-helpers.d.ts.map +1 -1
  22. package/dist/src/plugin/request-helpers.js +9 -4
  23. package/dist/src/plugin/request-helpers.js.map +1 -1
  24. package/dist/src/plugin/request.d.ts +6 -0
  25. package/dist/src/plugin/request.d.ts.map +1 -1
  26. package/dist/src/plugin/request.js +230 -57
  27. package/dist/src/plugin/request.js.map +1 -1
  28. package/dist/src/plugin/session-context.d.ts +21 -0
  29. package/dist/src/plugin/session-context.d.ts.map +1 -0
  30. package/dist/src/plugin/session-context.js +63 -0
  31. package/dist/src/plugin/session-context.js.map +1 -0
  32. package/dist/src/plugin/storage.d.ts +6 -0
  33. package/dist/src/plugin/storage.d.ts.map +1 -1
  34. package/dist/src/plugin/storage.js +14 -3
  35. package/dist/src/plugin/storage.js.map +1 -1
  36. package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
  37. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  38. package/dist/src/plugin/ui/auth-menu.js +3 -1
  39. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  40. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  41. package/dist/src/plugin/ui/quota-status.js +2 -1
  42. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  43. package/dist/src/plugin.d.ts +16 -0
  44. package/dist/src/plugin.d.ts.map +1 -1
  45. package/dist/src/plugin.js +261 -101
  46. package/dist/src/plugin.js.map +1 -1
  47. package/package.json +2 -2
@@ -42,6 +42,10 @@ export interface ManagedAccount {
42
42
  verificationRequiredAt?: number;
43
43
  verificationRequiredReason?: string;
44
44
  verificationUrl?: string;
45
+ accountIneligible?: boolean;
46
+ accountIneligibleAt?: number;
47
+ accountIneligibleReason?: string;
48
+ eligibilityStateUpdatedAt?: number;
45
49
  /** Daily request counts per model family */
46
50
  dailyRequestCounts?: {
47
51
  date: string;
@@ -63,6 +67,10 @@ export interface ManagedAccount {
63
67
  */
64
68
  export declare function resolveQuotaGroup(family: ModelFamily, model?: string | null): QuotaGroup;
65
69
  export declare function computeSoftQuotaCacheTtlMs(ttlConfig: "auto" | number, refreshIntervalMinutes: number): number;
70
+ export interface AccountSessionIdentity {
71
+ id: string;
72
+ parentId?: string | null;
73
+ }
66
74
  /**
67
75
  * In-memory multi-account manager with sticky account selection.
68
76
  *
@@ -85,22 +93,33 @@ export declare class AccountManager {
85
93
  private sessionStartTime;
86
94
  private sessionRequestCounts;
87
95
  private sessionUsedAccounts;
96
+ private requestSessionStates;
88
97
  static loadFromDisk(authFallback?: OAuthAuthDetails): Promise<AccountManager>;
89
98
  constructor(authFallback?: OAuthAuthDetails, stored?: AccountStorageV4 | null);
90
99
  getAccountCount(): number;
91
100
  getTotalAccountCount(): number;
92
101
  getEnabledAccounts(): ManagedAccount[];
102
+ private getEffectiveSoftQuotaThreshold;
93
103
  getAccountsSnapshot(): ManagedAccount[];
94
- getCurrentAccountForFamily(family: ModelFamily): ManagedAccount | null;
95
- markSwitched(account: ManagedAccount, reason: "rate-limit" | "initial" | "rotation", family: ModelFamily): void;
104
+ private getRequestSessionState;
105
+ private pruneRequestSessionStates;
106
+ private getActiveIndex;
107
+ private setActiveIndex;
108
+ private getCursor;
109
+ private advanceCursor;
110
+ private getUsedAccounts;
111
+ private preferAccountOutsideParent;
112
+ deleteSessionState(sessionId: string): void;
113
+ getCurrentAccountForFamily(family: ModelFamily, identity?: AccountSessionIdentity): ManagedAccount | null;
114
+ markSwitched(account: ManagedAccount, reason: "rate-limit" | "initial" | "rotation", family: ModelFamily, identity?: AccountSessionIdentity): void;
96
115
  /**
97
116
  * Check if we should show an account switch toast.
98
117
  * Debounces repeated toasts for the same account.
99
118
  */
100
119
  shouldShowAccountToast(accountIndex: number, debounceMs?: number): boolean;
101
120
  markToastShown(accountIndex: number): void;
102
- getCurrentOrNextForFamily(family: ModelFamily, model?: string | null, strategy?: AccountSelectionStrategy, headerStyle?: HeaderStyle, pidOffsetEnabled?: boolean, softQuotaThresholdPercent?: number, softQuotaCacheTtlMs?: number): ManagedAccount | null;
103
- getNextForFamily(family: ModelFamily, model?: string | null, headerStyle?: HeaderStyle, softQuotaThresholdPercent?: number, softQuotaCacheTtlMs?: number): ManagedAccount | null;
121
+ getCurrentOrNextForFamily(family: ModelFamily, model?: string | null, strategy?: AccountSelectionStrategy, headerStyle?: HeaderStyle, pidOffsetEnabled?: boolean, softQuotaThresholdPercent?: number, softQuotaCacheTtlMs?: number, identity?: AccountSessionIdentity): ManagedAccount | null;
122
+ getNextForFamily(family: ModelFamily, model?: string | null, headerStyle?: HeaderStyle, softQuotaThresholdPercent?: number, softQuotaCacheTtlMs?: number, identity?: AccountSessionIdentity): ManagedAccount | null;
104
123
  markRateLimited(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, headerStyle?: HeaderStyle, model?: string | null): void;
105
124
  /**
106
125
  * Mark an account as used after a successful API request.
@@ -108,10 +127,10 @@ export declare class AccountManager {
108
127
  * Should be called AFTER request completion, not during account selection.
109
128
  */
110
129
  markAccountUsed(accountIndex: number): void;
111
- recordSessionUsage(accountIndex: number): void;
112
- wasUsedInSession(accountIndex: number): boolean;
113
- shouldProactivelyRotate(family: ModelFamily, model: string | null | undefined, thresholdPercent: number, cacheTtlMs: number): boolean;
114
- proactivelyRotateForFamily(family: ModelFamily, model: string | null | undefined, headerStyle: HeaderStyle, softQuotaThresholdPercent: number, softQuotaCacheTtlMs: number): ManagedAccount | null;
130
+ recordSessionUsage(accountIndex: number, identity?: AccountSessionIdentity): void;
131
+ wasUsedInSession(accountIndex: number, identity?: AccountSessionIdentity): boolean;
132
+ shouldProactivelyRotate(family: ModelFamily, model: string | null | undefined, thresholdPercent: number, cacheTtlMs: number, identity?: AccountSessionIdentity): boolean;
133
+ proactivelyRotateForFamily(family: ModelFamily, model: string | null | undefined, headerStyle: HeaderStyle, softQuotaThresholdPercent: number, softQuotaCacheTtlMs: number, identity?: AccountSessionIdentity): ManagedAccount | null;
115
134
  markRateLimitedWithReason(account: ManagedAccount, family: ModelFamily, headerStyle: HeaderStyle, model: string | null | undefined, reason: RateLimitReason, retryAfterMs?: number | null, failureTtlMs?: number): number;
116
135
  markRequestSuccess(account: ManagedAccount): void;
117
136
  clearAllRateLimitsForFamily(family: ModelFamily, model?: string | null): void;
@@ -140,7 +159,8 @@ export declare class AccountManager {
140
159
  hasOtherAccountWithAntigravityAvailable(currentAccountIndex: number, family: ModelFamily, model?: string | null): boolean;
141
160
  setAccountEnabled(accountIndex: number, enabled: boolean): boolean;
142
161
  markAccountVerificationRequired(accountIndex: number, reason?: string, verifyUrl?: string): boolean;
143
- clearAccountVerificationRequired(accountIndex: number, enableAccount?: boolean): boolean;
162
+ markAccountIneligible(accountIndex: number, reason?: string): boolean;
163
+ clearAccountAccessBlocks(accountIndex: number, enableAccount?: boolean): boolean;
144
164
  removeAccountByIndex(accountIndex: number): boolean;
145
165
  removeAccount(account: ManagedAccount): boolean;
146
166
  updateFromAuth(account: ManagedAccount, auth: OAuthAuthDetails): void;
@@ -1 +1 @@
1
- {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../../src/plugin/accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../../src/plugin/accounts.ts"],"names":[],"mappings":"AACA,OAAO,EAAmD,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3M,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAiD,KAAK,WAAW,EAAE,KAAK,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAClJ,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAM7D,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1E,YAAY,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAGhE,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,qBAAqB,GACrB,0BAA0B,GAC1B,cAAc,GACd,SAAS,CAAC;AAEd,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;CACzB;AAwBD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,CAAC,EAAE,MAAM,GACd,eAAe,CA4CjB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,mBAAmB,EAAE,MAAM,EAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CAuBR;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,oBAAoB,GAAG,YAAY,CAAC;AAC1E,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,GAAG,YAAY,IAAI,MAAM,EAAE,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,gBAAgB,CAAC;IACtC,gBAAgB,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,CAAC;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,eAAe,EAAE,WAAW,CAAC;IAClD,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAsED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU,CAKxF;AAmCD,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,sBAAsB,EAAE,MAAM,GAC7B,MAAM,CAKR;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAcD;;;;;;;;GAQG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,cAAc,CAAyD;IAC/E,OAAO,CAAC,2BAA2B,CAGjC;IACF,OAAO,CAAC,oBAAoB,CAG1B;IACF,OAAO,CAAC,qBAAqB,CAAM;IACnC,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAA8C;IACjE,OAAO,CAAC,oBAAoB,CAAsE;IAElG,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,oBAAoB,CAA6D;IACzF,OAAO,CAAC,mBAAmB,CAAyB;IACpD,OAAO,CAAC,oBAAoB,CAAyC;WAExD,YAAY,CAAC,YAAY,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC;gBAKvE,YAAY,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,IAAI;IA0I7E,eAAe,IAAI,MAAM;IAIzB,oBAAoB,IAAI,MAAM;IAI9B,kBAAkB,IAAI,cAAc,EAAE;IAItC,OAAO,CAAC,8BAA8B;IAMtC,mBAAmB,IAAI,cAAc,EAAE;IAIvC,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,0BAA0B;IAqBlC,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI3C,0BAA0B,CACxB,MAAM,EAAE,WAAW,EACnB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,cAAc,GAAG,IAAI;IAYxB,YAAY,CACV,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,EAC7C,MAAM,EAAE,WAAW,EACnB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,IAAI;IAKP;;;OAGG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,SAAQ,GAAG,OAAO;IAQzE,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAK1C,yBAAyB,CACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,QAAQ,GAAE,wBAAmC,EAC7C,WAAW,GAAE,WAA2B,EACxC,gBAAgB,GAAE,OAAe,EACjC,yBAAyB,GAAE,MAAY,EACvC,mBAAmB,GAAE,MAAuB,EAC5C,QAAQ,CAAC,EAAE,sBAAsB,GAChC,cAAc,GAAG,IAAI;IA8GxB,gBAAgB,CACd,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,WAAW,GAAE,WAA2B,EACxC,yBAAyB,GAAE,MAAY,EACvC,mBAAmB,GAAE,MAAuB,EAC5C,QAAQ,CAAC,EAAE,sBAAsB,GAChC,cAAc,GAAG,IAAI;IA4BxB,eAAe,CACb,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,WAAW,EACnB,WAAW,GAAE,WAA2B,EACxC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,IAAI;IAKP;;;;OAIG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAO3C,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,sBAAsB,GAAG,IAAI;IAIjF,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,sBAAsB,GAAG,OAAO;IAIlF,uBAAuB,CACrB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,OAAO;IAiBV,0BAA0B,CACxB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,WAAW,EAAE,WAAW,EACxB,yBAAyB,EAAE,MAAM,EACjC,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,CAAC,EAAE,sBAAsB,GAChC,cAAc,GAAG,IAAI;IAoCxB,yBAAyB,CAAK,OAAO,EAAE,cAAc,EACnD,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,eAAe,EACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,EAC5B,YAAY,GAAE,MAAiB,GAC9B,MAAM;IAmBT,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAMjD,2BAA2B,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAc7E,wBAAwB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAK7E,sBAAsB,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI;IAKjG,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;IAWtD,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAKnD,wBAAwB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,GAAG,SAAS;IAI7E,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIpE,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAUnE,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,EAAE;IAUxG,2BAA2B,CACzB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,WAAW,EACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO;IAIV,uBAAuB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI;IAchH;;;;;;;;;;;OAWG;IACH,uCAAuC,CACrC,mBAAmB,EAAE,MAAM,EAC3B,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO;IA2BV,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO;IAuBlE,+BAA+B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAmCnG,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IAwBrE,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,OAAO;IAmC9E,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAWnD,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;IAyD/C,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYrE,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,gBAAgB;IASxD,uBAAuB,CACrB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,WAAW,CAAC,EAAE,WAAW,EACzB,MAAM,CAAC,EAAE,OAAO,GACf,MAAM;IAuCT,WAAW,IAAI,cAAc,EAAE;IAI/B,OAAO,CAAC,oBAAoB;IAqCtB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxC,iBAAiB,IAAI,IAAI;IAUnB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAQxB,WAAW;IA6BzB;;;;OAIG;IACH,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAgCtE;;;;;OAKG;IACH,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAoCzF;;;;OAIG;IACH,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAQxE,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC,GAAG,IAAI;IAQzG;;;OAGG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAiB9D;;OAEG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAUpG;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM;IAWlD;;;OAGG;IACH,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBpG;;OAEG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAOrE;;OAEG;IACH,iBAAiB,IAAI;QACnB,eAAe,EAAE,MAAM,CAAA;QACvB,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;QACnB,eAAe,EAAE,MAAM,CAAA;QACvB,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KACrF;IAgCD,sBAAsB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAUlJ,wBAAwB,IAAI,iBAAiB,EAAE;IAY/C,sBAAsB,IAAI,MAAM,GAAG,IAAI;IAWvC,2BAA2B,CAAC,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAO9H;;;;;OAKG;IACH,0BAA0B,CACxB,MAAM,EAAE,WAAW,EACnB,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,GAAG,IAAI;CAkCjB"}
@@ -193,6 +193,8 @@ export function computeSoftQuotaCacheTtlMs(ttlConfig, refreshIntervalMinutes) {
193
193
  }
194
194
  return ttlConfig * 60 * 1000;
195
195
  }
196
+ const ACCOUNT_SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1000;
197
+ const MAX_ACCOUNT_SESSION_STATES = 256;
196
198
  /**
197
199
  * In-memory multi-account manager with sticky account selection.
198
200
  *
@@ -221,6 +223,7 @@ export class AccountManager {
221
223
  sessionStartTime = Date.now();
222
224
  sessionRequestCounts = new Map();
223
225
  sessionUsedAccounts = new Set();
226
+ requestSessionStates = new Map();
224
227
  static async loadFromDisk(authFallback) {
225
228
  const stored = await loadAccounts();
226
229
  return new AccountManager(authFallback, stored);
@@ -266,9 +269,14 @@ export class AccountManager {
266
269
  cachedQuota: acc.cachedQuota,
267
270
  cachedQuotaUpdatedAt: acc.cachedQuotaUpdatedAt,
268
271
  dailyRequestCounts: acc.dailyRequestCounts,
269
- verificationRequired: acc.verificationRequired, verificationRequiredAt: acc.verificationRequiredAt,
272
+ verificationRequired: acc.verificationRequired,
273
+ verificationRequiredAt: acc.verificationRequiredAt,
270
274
  verificationRequiredReason: acc.verificationRequiredReason,
271
275
  verificationUrl: acc.verificationUrl,
276
+ accountIneligible: acc.accountIneligible,
277
+ accountIneligibleAt: acc.accountIneligibleAt,
278
+ accountIneligibleReason: acc.accountIneligibleReason,
279
+ eligibilityStateUpdatedAt: acc.eligibilityStateUpdatedAt,
272
280
  };
273
281
  })
274
282
  .filter((a) => a !== null);
@@ -350,11 +358,111 @@ export class AccountManager {
350
358
  getEnabledAccounts() {
351
359
  return this.accounts.filter((account) => account.enabled !== false);
352
360
  }
361
+ getEffectiveSoftQuotaThreshold(thresholdPercent) {
362
+ // Soft-quota protection only has a purpose when another enabled account
363
+ // exists to rotate to. Never block the sole usable account.
364
+ return this.getEnabledAccounts().length > 1 ? thresholdPercent : 100;
365
+ }
353
366
  getAccountsSnapshot() {
354
367
  return this.accounts.map((a) => ({ ...a, parts: { ...a.parts }, rateLimitResetTimes: { ...a.rateLimitResetTimes } }));
355
368
  }
356
- getCurrentAccountForFamily(family) {
357
- const currentIndex = this.currentAccountIndexByFamily[family];
369
+ getRequestSessionState(identity) {
370
+ const now = nowMs();
371
+ this.pruneRequestSessionStates(now, identity.id);
372
+ const existing = this.requestSessionStates.get(identity.id);
373
+ if (existing) {
374
+ existing.lastAccessedAt = now;
375
+ if (identity.parentId) {
376
+ existing.parentId = identity.parentId;
377
+ }
378
+ return existing;
379
+ }
380
+ const state = {
381
+ parentId: identity.parentId ?? null,
382
+ currentAccountIndexByFamily: { claude: -1, gemini: -1 },
383
+ cursorByFamily: { ...this.cursorByFamily },
384
+ offsetAppliedByFamily: { claude: false, gemini: false },
385
+ usedAccounts: new Set(),
386
+ lastAccessedAt: now,
387
+ };
388
+ this.requestSessionStates.set(identity.id, state);
389
+ return state;
390
+ }
391
+ pruneRequestSessionStates(now, preservedId) {
392
+ const expiry = now - ACCOUNT_SESSION_STATE_TTL_MS;
393
+ for (const [id, state] of this.requestSessionStates) {
394
+ if (id !== preservedId && state.lastAccessedAt < expiry) {
395
+ this.requestSessionStates.delete(id);
396
+ }
397
+ }
398
+ if (this.requestSessionStates.size < MAX_ACCOUNT_SESSION_STATES || this.requestSessionStates.has(preservedId)) {
399
+ return;
400
+ }
401
+ let oldestId = null;
402
+ let oldestAccess = Number.POSITIVE_INFINITY;
403
+ for (const [id, state] of this.requestSessionStates) {
404
+ if (id !== preservedId && state.lastAccessedAt < oldestAccess) {
405
+ oldestId = id;
406
+ oldestAccess = state.lastAccessedAt;
407
+ }
408
+ }
409
+ if (oldestId) {
410
+ this.requestSessionStates.delete(oldestId);
411
+ }
412
+ }
413
+ getActiveIndex(family, identity) {
414
+ return identity
415
+ ? this.getRequestSessionState(identity).currentAccountIndexByFamily[family]
416
+ : this.currentAccountIndexByFamily[family];
417
+ }
418
+ setActiveIndex(family, index, identity) {
419
+ if (!identity) {
420
+ this.currentAccountIndexByFamily[family] = index;
421
+ return;
422
+ }
423
+ const state = this.getRequestSessionState(identity);
424
+ state.currentAccountIndexByFamily[family] = index;
425
+ if (!state.parentId) {
426
+ // Preserve a useful persisted starting point without coupling active root sessions.
427
+ this.currentAccountIndexByFamily[family] = index;
428
+ }
429
+ }
430
+ getCursor(family, identity) {
431
+ return identity
432
+ ? this.getRequestSessionState(identity).cursorByFamily[family]
433
+ : this.cursorByFamily[family];
434
+ }
435
+ advanceCursor(family, identity) {
436
+ const nextGlobalCursor = this.cursorByFamily[family] + 1;
437
+ this.cursorByFamily[family] = nextGlobalCursor;
438
+ if (identity) {
439
+ this.getRequestSessionState(identity).cursorByFamily[family] += 1;
440
+ }
441
+ }
442
+ getUsedAccounts(identity) {
443
+ return identity ? this.getRequestSessionState(identity).usedAccounts : this.sessionUsedAccounts;
444
+ }
445
+ preferAccountOutsideParent(accounts, family, identity) {
446
+ if (!identity) {
447
+ return accounts;
448
+ }
449
+ const parentId = this.getRequestSessionState(identity).parentId;
450
+ if (!parentId) {
451
+ return accounts;
452
+ }
453
+ const parentState = this.requestSessionStates.get(parentId);
454
+ const parentIndex = parentState?.currentAccountIndexByFamily[family] ?? -1;
455
+ if (parentIndex < 0) {
456
+ return accounts;
457
+ }
458
+ const isolated = accounts.filter((account) => account.index !== parentIndex);
459
+ return isolated.length > 0 ? isolated : accounts;
460
+ }
461
+ deleteSessionState(sessionId) {
462
+ this.requestSessionStates.delete(sessionId);
463
+ }
464
+ getCurrentAccountForFamily(family, identity) {
465
+ const currentIndex = this.getActiveIndex(family, identity);
358
466
  if (currentIndex >= 0 && currentIndex < this.accounts.length) {
359
467
  const account = this.accounts[currentIndex] ?? null;
360
468
  // Only return account if it's enabled - disabled accounts should not be selected
@@ -364,9 +472,9 @@ export class AccountManager {
364
472
  }
365
473
  return null;
366
474
  }
367
- markSwitched(account, reason, family) {
475
+ markSwitched(account, reason, family, identity) {
368
476
  account.lastSwitchReason = reason;
369
- this.currentAccountIndexByFamily[family] = account.index;
477
+ this.setActiveIndex(family, account.index, identity);
370
478
  }
371
479
  /**
372
480
  * Check if we should show an account switch toast.
@@ -383,41 +491,56 @@ export class AccountManager {
383
491
  this.lastToastAccountIndex = accountIndex;
384
492
  this.lastToastTime = nowMs();
385
493
  }
386
- getCurrentOrNextForFamily(family, model, strategy = 'sticky', headerStyle = 'antigravity', pidOffsetEnabled = false, softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1000) {
494
+ getCurrentOrNextForFamily(family, model, strategy = 'sticky', headerStyle = 'antigravity', pidOffsetEnabled = false, softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1000, identity) {
387
495
  const quotaKey = getQuotaKey(family, headerStyle, model);
496
+ const effectiveSoftQuotaThreshold = this.getEffectiveSoftQuotaThreshold(softQuotaThresholdPercent);
497
+ // OpenCode may run many root and child sessions concurrently in one plugin
498
+ // process. Pin each exact session until its account becomes unavailable.
499
+ if (identity) {
500
+ const pinned = this.getCurrentAccountForFamily(family, identity);
501
+ if (pinned) {
502
+ clearExpiredRateLimits(pinned);
503
+ const unavailable = isRateLimitedForHeaderStyle(pinned, family, headerStyle, model) ||
504
+ isOverSoftQuotaThreshold(pinned, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model) ||
505
+ this.isAccountCoolingDown(pinned);
506
+ if (!unavailable) {
507
+ this.markTouchedForQuota(pinned, quotaKey);
508
+ return pinned;
509
+ }
510
+ }
511
+ }
388
512
  if (strategy === 'round-robin') {
389
- const next = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);
513
+ const next = this.getNextForFamily(family, model, headerStyle, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, identity);
390
514
  if (next) {
391
515
  this.markTouchedForQuota(next, quotaKey);
392
- this.currentAccountIndexByFamily[family] = next.index;
516
+ this.setActiveIndex(family, next.index, identity);
393
517
  }
394
518
  return next;
395
519
  }
396
520
  if (strategy === 'hybrid') {
397
521
  const healthTracker = getHealthTracker();
398
522
  const tokenTracker = getTokenTracker();
399
- const accountsWithMetrics = this.accounts
400
- .filter(acc => acc.enabled !== false)
401
- .map(acc => {
523
+ const eligibleAccounts = this.preferAccountOutsideParent(this.accounts.filter(acc => acc.enabled !== false), family, identity);
524
+ const accountsWithMetrics = eligibleAccounts.map(acc => {
402
525
  clearExpiredRateLimits(acc);
403
526
  return {
404
527
  index: acc.index,
405
528
  lastUsed: acc.lastUsed,
406
529
  healthScore: healthTracker.getScore(acc.index),
407
530
  isRateLimited: isRateLimitedForFamily(acc, family, model) ||
408
- isOverSoftQuotaThreshold(acc, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model),
531
+ isOverSoftQuotaThreshold(acc, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model),
409
532
  isCoolingDown: this.isAccountCoolingDown(acc),
410
533
  };
411
534
  });
412
535
  // Get current account index for stickiness
413
- const currentIndex = this.currentAccountIndexByFamily[family] ?? null;
536
+ const currentIndex = this.getActiveIndex(family, identity);
414
537
  const selectedIndex = selectHybridAccount(accountsWithMetrics, tokenTracker, currentIndex);
415
538
  if (selectedIndex !== null) {
416
539
  const selected = this.accounts[selectedIndex];
417
540
  if (selected) {
418
541
  selected.lastUsed = nowMs();
419
542
  this.markTouchedForQuota(selected, quotaKey);
420
- this.currentAccountIndexByFamily[family] = selected.index;
543
+ this.setActiveIndex(family, selected.index, identity);
421
544
  return selected;
422
545
  }
423
546
  }
@@ -425,50 +548,57 @@ export class AccountManager {
425
548
  // Fallback: sticky selection (used when hybrid finds no candidates)
426
549
  // PID-based offset for multi-session distribution (opt-in)
427
550
  // Different sessions (PIDs) will prefer different starting accounts
428
- if (pidOffsetEnabled && !this.sessionOffsetApplied[family] && this.accounts.length > 1) {
551
+ const offsetApplied = identity
552
+ ? this.getRequestSessionState(identity).offsetAppliedByFamily
553
+ : this.sessionOffsetApplied;
554
+ if (pidOffsetEnabled && !offsetApplied[family] && this.accounts.length > 1) {
429
555
  const pidOffset = process.pid % this.accounts.length;
430
- const baseIndex = this.currentAccountIndexByFamily[family] ?? 0;
556
+ const activeIndex = this.getActiveIndex(family, identity);
557
+ const baseIndex = activeIndex >= 0 ? activeIndex : this.getCursor(family, identity);
431
558
  const newIndex = (baseIndex + pidOffset) % this.accounts.length;
432
559
  debugLogToFile(`[Account] Applying PID offset: pid=${process.pid} offset=${pidOffset} family=${family} index=${baseIndex}->${newIndex}`);
433
- this.currentAccountIndexByFamily[family] = newIndex;
434
- this.sessionOffsetApplied[family] = true;
560
+ this.setActiveIndex(family, newIndex, identity);
561
+ offsetApplied[family] = true;
435
562
  }
436
- const current = this.getCurrentAccountForFamily(family);
563
+ const current = this.getCurrentAccountForFamily(family, identity);
437
564
  if (current) {
438
565
  clearExpiredRateLimits(current);
439
566
  const isLimitedForRequestedStyle = isRateLimitedForHeaderStyle(current, family, headerStyle, model);
440
- const isOverThreshold = isOverSoftQuotaThreshold(current, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model);
567
+ const isOverThreshold = isOverSoftQuotaThreshold(current, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model);
441
568
  if (!isLimitedForRequestedStyle && !isOverThreshold && !this.isAccountCoolingDown(current)) {
442
569
  this.markTouchedForQuota(current, quotaKey);
443
570
  return current;
444
571
  }
445
572
  }
446
- const next = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);
573
+ const next = this.getNextForFamily(family, model, headerStyle, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, identity);
447
574
  if (next) {
448
575
  this.markTouchedForQuota(next, quotaKey);
449
- this.currentAccountIndexByFamily[family] = next.index;
576
+ this.setActiveIndex(family, next.index, identity);
450
577
  }
451
578
  return next;
452
579
  }
453
- getNextForFamily(family, model, headerStyle = "antigravity", softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1000) {
454
- const available = this.accounts.filter((a) => {
455
- clearExpiredRateLimits(a);
456
- return a.enabled !== false &&
457
- !isRateLimitedForHeaderStyle(a, family, headerStyle, model) &&
458
- !isOverSoftQuotaThreshold(a, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model) &&
459
- !this.isAccountCoolingDown(a);
580
+ getNextForFamily(family, model, headerStyle = "antigravity", softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1000, identity) {
581
+ const effectiveSoftQuotaThreshold = this.getEffectiveSoftQuotaThreshold(softQuotaThresholdPercent);
582
+ const allAvailable = this.accounts.filter((account) => {
583
+ clearExpiredRateLimits(account);
584
+ return account.enabled !== false &&
585
+ !isRateLimitedForHeaderStyle(account, family, headerStyle, model) &&
586
+ !isOverSoftQuotaThreshold(account, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model) &&
587
+ !this.isAccountCoolingDown(account);
460
588
  });
589
+ const available = this.preferAccountOutsideParent(allAvailable, family, identity);
461
590
  if (available.length === 0) {
462
591
  return null;
463
592
  }
464
- const sessionUsed = available.filter(a => this.sessionUsedAccounts.has(a.index));
593
+ const usedAccounts = this.getUsedAccounts(identity);
594
+ const sessionUsed = available.filter(account => usedAccounts.has(account.index));
465
595
  const candidates = sessionUsed.length > 0 ? sessionUsed : available;
466
- const cursor = this.cursorByFamily[family];
596
+ const cursor = this.getCursor(family, identity);
467
597
  const account = candidates[cursor % candidates.length];
468
598
  if (!account) {
469
599
  return null;
470
600
  }
471
- this.cursorByFamily[family] = cursor + 1;
601
+ this.advanceCursor(family, identity);
472
602
  return account;
473
603
  }
474
604
  markRateLimited(account, retryAfterMs, family, headerStyle = "antigravity", model) {
@@ -486,16 +616,16 @@ export class AccountManager {
486
616
  account.lastUsed = nowMs();
487
617
  }
488
618
  }
489
- recordSessionUsage(accountIndex) {
490
- this.sessionUsedAccounts.add(accountIndex);
619
+ recordSessionUsage(accountIndex, identity) {
620
+ this.getUsedAccounts(identity).add(accountIndex);
491
621
  }
492
- wasUsedInSession(accountIndex) {
493
- return this.sessionUsedAccounts.has(accountIndex);
622
+ wasUsedInSession(accountIndex, identity) {
623
+ return this.getUsedAccounts(identity).has(accountIndex);
494
624
  }
495
- shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs) {
625
+ shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs, identity) {
496
626
  if (thresholdPercent <= 0)
497
627
  return false;
498
- const current = this.getCurrentAccountForFamily(family);
628
+ const current = this.getCurrentAccountForFamily(family, identity);
499
629
  if (!current || !current.cachedQuota || current.cachedQuotaUpdatedAt == null)
500
630
  return false;
501
631
  const age = nowMs() - current.cachedQuotaUpdatedAt;
@@ -508,9 +638,9 @@ export class AccountManager {
508
638
  const remainingPercent = Math.max(0, Math.min(100, groupData.remainingFraction * 100));
509
639
  return remainingPercent < thresholdPercent;
510
640
  }
511
- proactivelyRotateForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs) {
512
- const currentIndex = this.currentAccountIndexByFamily[family];
513
- const candidates = this.accounts.filter(acc => {
641
+ proactivelyRotateForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs, identity) {
642
+ const currentIndex = this.getActiveIndex(family, identity);
643
+ const candidates = this.preferAccountOutsideParent(this.accounts.filter(acc => {
514
644
  if (acc.enabled === false)
515
645
  return false;
516
646
  if (acc.index === currentIndex)
@@ -523,10 +653,11 @@ export class AccountManager {
523
653
  if (this.isAccountCoolingDown(acc))
524
654
  return false;
525
655
  return true;
526
- });
656
+ }), family, identity);
527
657
  if (candidates.length === 0)
528
658
  return null;
529
- const warmCandidates = candidates.filter(a => this.sessionUsedAccounts.has(a.index));
659
+ const usedAccounts = this.getUsedAccounts(identity);
660
+ const warmCandidates = candidates.filter(account => usedAccounts.has(account.index));
530
661
  const pool = warmCandidates.length > 0 ? warmCandidates : candidates;
531
662
  const quotaGroup = resolveQuotaGroup(family, model);
532
663
  pool.sort((a, b) => {
@@ -539,7 +670,7 @@ export class AccountManager {
539
670
  return null;
540
671
  const quotaKey = getQuotaKey(family, headerStyle, model);
541
672
  this.markTouchedForQuota(selected, quotaKey);
542
- this.currentAccountIndexByFamily[family] = selected.index;
673
+ this.setActiveIndex(family, selected.index, identity);
543
674
  return selected;
544
675
  }
545
676
  markRateLimitedWithReason(account, family, headerStyle, model, reason, retryAfterMs, failureTtlMs = 3600_000) {
@@ -679,6 +810,9 @@ export class AccountManager {
679
810
  if (!account) {
680
811
  return false;
681
812
  }
813
+ if (enabled && account.accountIneligible) {
814
+ return false;
815
+ }
682
816
  account.enabled = enabled;
683
817
  if (!enabled) {
684
818
  for (const family of Object.keys(this.currentAccountIndexByFamily)) {
@@ -696,9 +830,18 @@ export class AccountManager {
696
830
  if (!account) {
697
831
  return false;
698
832
  }
833
+ const timestamp = nowMs();
699
834
  account.verificationRequired = true;
700
- account.verificationRequiredAt = nowMs();
835
+ account.verificationRequiredAt = timestamp;
701
836
  account.verificationRequiredReason = reason?.trim() || undefined;
837
+ if (account.accountIneligible === true ||
838
+ account.accountIneligibleAt !== undefined ||
839
+ account.accountIneligibleReason !== undefined) {
840
+ account.accountIneligible = false;
841
+ account.accountIneligibleAt = undefined;
842
+ account.accountIneligibleReason = undefined;
843
+ account.eligibilityStateUpdatedAt = timestamp;
844
+ }
702
845
  const normalizedVerifyUrl = verifyUrl?.trim();
703
846
  if (normalizedVerifyUrl) {
704
847
  account.verificationUrl = normalizedVerifyUrl;
@@ -711,23 +854,56 @@ export class AccountManager {
711
854
  }
712
855
  return true;
713
856
  }
714
- clearAccountVerificationRequired(accountIndex, enableAccount = false) {
857
+ markAccountIneligible(accountIndex, reason) {
858
+ const account = this.accounts[accountIndex];
859
+ if (!account) {
860
+ return false;
861
+ }
862
+ const timestamp = nowMs();
863
+ account.accountIneligible = true;
864
+ account.accountIneligibleAt = timestamp;
865
+ account.accountIneligibleReason = reason?.trim() || "Google marked this account as ineligible.";
866
+ account.eligibilityStateUpdatedAt = timestamp;
867
+ account.verificationRequired = false;
868
+ account.verificationRequiredAt = undefined;
869
+ account.verificationRequiredReason = undefined;
870
+ account.verificationUrl = undefined;
871
+ if (account.enabled !== false) {
872
+ this.setAccountEnabled(accountIndex, false);
873
+ }
874
+ else {
875
+ this.requestSaveToDisk();
876
+ }
877
+ return true;
878
+ }
879
+ clearAccountAccessBlocks(accountIndex, enableAccount = false) {
715
880
  const account = this.accounts[accountIndex];
716
881
  if (!account) {
717
882
  return false;
718
883
  }
719
884
  const wasVerificationRequired = account.verificationRequired === true;
720
- const hadMetadata = (account.verificationRequiredAt !== undefined ||
885
+ const wasIneligible = account.accountIneligible === true;
886
+ const hadMetadata = wasVerificationRequired || wasIneligible ||
887
+ account.verificationRequiredAt !== undefined ||
721
888
  account.verificationRequiredReason !== undefined ||
722
- account.verificationUrl !== undefined);
889
+ account.verificationUrl !== undefined ||
890
+ account.accountIneligibleAt !== undefined ||
891
+ account.accountIneligibleReason !== undefined ||
892
+ account.eligibilityStateUpdatedAt !== undefined;
723
893
  account.verificationRequired = false;
724
894
  account.verificationRequiredAt = undefined;
725
895
  account.verificationRequiredReason = undefined;
726
896
  account.verificationUrl = undefined;
727
- if (enableAccount && wasVerificationRequired && account.enabled === false) {
897
+ account.accountIneligible = false;
898
+ account.accountIneligibleAt = undefined;
899
+ account.accountIneligibleReason = undefined;
900
+ if (wasIneligible || account.eligibilityStateUpdatedAt !== undefined) {
901
+ account.eligibilityStateUpdatedAt = nowMs();
902
+ }
903
+ if (enableAccount && (wasVerificationRequired || wasIneligible) && account.enabled === false) {
728
904
  this.setAccountEnabled(accountIndex, true);
729
905
  }
730
- else if (wasVerificationRequired || hadMetadata) {
906
+ else if (hadMetadata) {
731
907
  this.requestSaveToDisk();
732
908
  }
733
909
  return true;
@@ -755,6 +931,7 @@ export class AccountManager {
755
931
  this.cursorByFamily = { claude: 0, gemini: 0 };
756
932
  this.currentAccountIndexByFamily.claude = -1;
757
933
  this.currentAccountIndexByFamily.gemini = -1;
934
+ this.requestSessionStates.clear();
758
935
  return true;
759
936
  }
760
937
  for (const family of ["claude", "gemini"]) {
@@ -768,6 +945,24 @@ export class AccountManager {
768
945
  if (this.currentAccountIndexByFamily[family] >= this.accounts.length) {
769
946
  this.currentAccountIndexByFamily[family] = -1;
770
947
  }
948
+ for (const state of this.requestSessionStates.values()) {
949
+ const currentIndex = state.currentAccountIndexByFamily[family];
950
+ if (currentIndex === idx) {
951
+ state.currentAccountIndexByFamily[family] = -1;
952
+ }
953
+ else if (currentIndex > idx) {
954
+ state.currentAccountIndexByFamily[family] -= 1;
955
+ }
956
+ if (state.cursorByFamily[family] > idx) {
957
+ state.cursorByFamily[family] -= 1;
958
+ }
959
+ state.cursorByFamily[family] %= this.accounts.length;
960
+ }
961
+ }
962
+ for (const state of this.requestSessionStates.values()) {
963
+ state.usedAccounts = new Set([...state.usedAccounts]
964
+ .filter((accountIndex) => accountIndex !== idx)
965
+ .map((accountIndex) => accountIndex > idx ? accountIndex - 1 : accountIndex));
771
966
  }
772
967
  return true;
773
968
  }
@@ -852,6 +1047,10 @@ export class AccountManager {
852
1047
  verificationRequiredAt: a.verificationRequiredAt,
853
1048
  verificationRequiredReason: a.verificationRequiredReason,
854
1049
  verificationUrl: a.verificationUrl,
1050
+ accountIneligible: a.accountIneligible,
1051
+ accountIneligibleAt: a.accountIneligibleAt,
1052
+ accountIneligibleReason: a.accountIneligibleReason,
1053
+ eligibilityStateUpdatedAt: a.eligibilityStateUpdatedAt,
855
1054
  })),
856
1055
  activeIndex: claudeIndex,
857
1056
  activeIndexByFamily: {
@@ -1097,7 +1296,7 @@ export class AccountManager {
1097
1296
  };
1098
1297
  }
1099
1298
  isAccountOverSoftQuota(account, family, thresholdPercent, cacheTtlMs, model) {
1100
- return isOverSoftQuotaThreshold(account, family, thresholdPercent, cacheTtlMs, model);
1299
+ return isOverSoftQuotaThreshold(account, family, this.getEffectiveSoftQuotaThreshold(thresholdPercent), cacheTtlMs, model);
1101
1300
  }
1102
1301
  getAccountsForQuotaCheck() {
1103
1302
  return this.accounts.map((a) => ({
@@ -1127,7 +1326,7 @@ export class AccountManager {
1127
1326
  if (thresholdPercent >= 100)
1128
1327
  return false;
1129
1328
  const enabled = this.accounts.filter(a => a.enabled !== false);
1130
- if (enabled.length === 0)
1329
+ if (enabled.length <= 1)
1131
1330
  return false;
1132
1331
  return enabled.every(a => isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
1133
1332
  }
@@ -1143,6 +1342,8 @@ export class AccountManager {
1143
1342
  const enabled = this.accounts.filter(a => a.enabled !== false);
1144
1343
  if (enabled.length === 0)
1145
1344
  return null;
1345
+ if (enabled.length === 1)
1346
+ return 0;
1146
1347
  // If any account is available (not over threshold), no wait needed
1147
1348
  const available = enabled.filter(a => !isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
1148
1349
  if (available.length > 0)