@omnicross/daemon 0.3.1 → 0.4.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.
package/dist/index.d.cts CHANGED
@@ -6,7 +6,7 @@ import { RouteLeaseManager, ProviderProxy } from '@omnicross/core/provider-proxy
6
6
  import { UsageRecorder, PricingEngine } from '@omnicross/core/usage';
7
7
  import { SubscriptionCredentialStore, FetchLike, CodexImageCapabilityEvidenceSource, CodexImageCapabilityEvidenceRequest, CodexImageCapabilityEvidence, CodexImageCapabilityObservation, ImageExecutionScheduler, ImageExecutionAccountKey, ImageExecutionSchedulerRequest, ImageExecutionSchedulerGrant, SubscriptionAccountService, SubscriptionProviderRegistry } from '@omnicross/subscriptions';
8
8
  import { AccountAllowanceSnapshot, AllowanceWindow } from '@omnicross/contracts/account-allowance-types';
9
- import { ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, KimiTokenConfig, AccountTokensConfig, ProxyConfig, SubscriptionAccountSanitized, AccountClientIdentity, SubscriptionAccountEntry } from '@omnicross/contracts/account-tokens-types';
9
+ import { ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, KimiTokenConfig, GrokTokenConfig, CopilotTokenConfig, AccountTokensConfig, ProxyConfig, SubscriptionAccountSanitized, AccountClientIdentity, SubscriptionAccountEntry } from '@omnicross/contracts/account-tokens-types';
10
10
  import * as _omnicross_contracts_subscription_types from '@omnicross/contracts/subscription-types';
11
11
  import { OpenCodeGoTokenConfig, SubscriptionProviderId } from '@omnicross/contracts/subscription-types';
12
12
  import { AccountAllowanceStore } from '@omnicross/core/pipeline/AccountAllowanceStore';
@@ -536,6 +536,18 @@ interface DaemonProviderConfig {
536
536
  * round-trips verbatim on GET. Management-UI only.
537
537
  */
538
538
  modelsEndpoint?: string;
539
+ /**
540
+ * OPTIONAL static extra request headers merged into every BYO request for
541
+ * this row — identity/attribution contracts some gateways hard-gate on
542
+ * (e.g. the Cline client-identity set). Additive + back-compat: absent
543
+ * reads as undefined. NON-SECRET — round-trips verbatim on GET; values may
544
+ * carry `{{platform}}` (resolved to `process.platform` at request time).
545
+ * ENFORCED: the outbound header funnel (`getProviderHeaders`) +
546
+ * discover-models + test-model merge them; auth/content header NAMES are
547
+ * dropped by the load guard (`validateExtraHeaders`) so credentials stay
548
+ * key-field-only.
549
+ */
550
+ extraHeaders?: Record<string, string>;
539
551
  /**
540
552
  * OPTIONAL provider transformer config (app-parity child 5). Additive +
541
553
  * back-compat: absent reads as the prior default (undefined). NON-SECRET —
@@ -666,7 +678,7 @@ type AtomicFileReplace = (targetPath: string, contents: string) => void;
666
678
  */
667
679
 
668
680
  /** Provider id → owned contract field names. */
669
- type DaemonProvider = 'claude' | 'codex' | 'gemini' | 'opencodego' | 'kimi';
681
+ type DaemonProvider = 'claude' | 'codex' | 'gemini' | 'opencodego' | 'kimi' | 'grok' | 'copilot';
670
682
  interface AccountMetadataPatch {
671
683
  label?: string;
672
684
  enabled?: boolean;
@@ -795,7 +807,7 @@ type ExternalCliReader = (provider: ExternalCliProvider) => ExternalCliCredentia
795
807
  * shapes), keyed by `SubscriptionProviderId` the daemon admin layer validates
796
808
  * the wire body to one of these before calling the writer.
797
809
  */
798
- type SubscriptionTokenBlock = ClaudeTokenConfig | CodexTokenConfig | GeminiTokenConfig | OpenCodeGoTokenConfig | KimiTokenConfig;
810
+ type SubscriptionTokenBlock = ClaudeTokenConfig | CodexTokenConfig | GeminiTokenConfig | OpenCodeGoTokenConfig | KimiTokenConfig | GrokTokenConfig | CopilotTokenConfig;
799
811
  declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialStore {
800
812
  private readonly tokensPath;
801
813
  private readonly box;
@@ -907,13 +919,28 @@ declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialS
907
919
  * `false` when no refresh_token.
908
920
  */
909
921
  refreshKimiToken(): Promise<boolean>;
922
+ /**
923
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
924
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
925
+ * flow module) so a rotated endpoint document is picked up without a daemon
926
+ * restart. HONEST `false` when no refresh_token.
927
+ */
928
+ refreshGrokToken(): Promise<boolean>;
929
+ /**
930
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
931
+ * tokens are long-lived with no exchange endpoint). A call here means the
932
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
933
+ * with a re-authenticate message and return `false` (the proxy then declines
934
+ * the retry instead of looping on a dead token).
935
+ */
936
+ refreshCopilotToken(): Promise<boolean>;
910
937
  /**
911
938
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
912
939
  * account-pool resolution). It uses only that account's stored refresh
913
940
  * token. Coalesced per `provider:id`; on failure flags ONLY that account
914
941
  * `expired`.
915
942
  */
916
- refreshAccountById(provider: 'claude' | 'codex' | 'gemini' | 'kimi', id: string): Promise<boolean>;
943
+ refreshAccountById(provider: 'claude' | 'codex' | 'gemini' | 'kimi' | 'grok' | 'copilot', id: string): Promise<boolean>;
917
944
  /**
918
945
  * Resolve a SPECIFIC account's access token by id (design D6). Mirrors each
919
946
  * provider's ACTIVE-getter policy, keyed by id: claude returns the stored token
@@ -1510,6 +1537,105 @@ declare class KimiAllowanceCollector {
1510
1537
  private unsupportedSnapshot;
1511
1538
  }
1512
1539
 
1540
+ /**
1541
+ * Grok (xAI SuperGrok) OAuth usage collector.
1542
+ *
1543
+ * Polls the Grok CLI billing proxy (`cli-chat-proxy.grok.com/v1/billing` —
1544
+ * NOT `*.x.ai`, and it REJECTS paid API keys: OAuth bearer only) per grok
1545
+ * account, mirroring the Claude/Codex/Kimi collectors' cache contract:
1546
+ * 5-minute cache, per-account in-flight merging, one 401→refresh→retry.
1547
+ *
1548
+ * Dual shape (mirrors the audit source's semantics):
1549
+ * - WEEKLY credits (`?format=credits`): `config.creditUsagePercent` +
1550
+ * `config.currentPeriod{start,end,type}` (+ per-product rows and an
1551
+ * on-demand cap, both optional). A missing `creditUsagePercent` on an
1552
+ * ACTIVE weekly period reads as 0 (a fresh period has no usage row).
1553
+ * - UNIFIED monthly (default URL): `config.{billingPeriodStart,
1554
+ * billingPeriodEnd, monthlyLimit{val}, used{val}}` — accounts flagged
1555
+ * `isUnifiedBillingUser` omit the weekly percentage and meter a monthly
1556
+ * included quota instead.
1557
+ *
1558
+ * Probe policy: always probe weekly first; probe monthly when weekly is
1559
+ * missing OR the account is flagged unified. An INFERRED weekly percentage
1560
+ * (field absent) on a unified account is only kept when the monthly probe
1561
+ * positively confirms there is no monthly quota — otherwise the monthly
1562
+ * window wins (an inferred 0% weekly on a unified account is a lie), and a
1563
+ * failed monthly probe falls through to a failure snapshot so the store
1564
+ * retains the last good one.
1565
+ *
1566
+ * Every request carries `X-XAI-Token-Auth: xai-grok-cli` — the same product
1567
+ * gate the official CLI uses on this host.
1568
+ */
1569
+
1570
+ interface GrokAllowanceCredentialReader {
1571
+ getAccessTokenForAccount(providerId: 'grok', accountId: string): Promise<string | null>;
1572
+ refreshAccountToken(providerId: 'grok', accountId: string): Promise<boolean>;
1573
+ }
1574
+ type GrokAllowanceFetch = (url: string, init: RequestInit, accountId: string) => Promise<Response>;
1575
+ interface GrokAllowanceCollectOptions {
1576
+ force?: boolean;
1577
+ refreshAheadMs?: number;
1578
+ }
1579
+ declare class GrokAllowanceCollector {
1580
+ private readonly credentials;
1581
+ private readonly store;
1582
+ private readonly fetchImpl;
1583
+ private readonly now;
1584
+ private readonly inFlight;
1585
+ constructor(credentials: GrokAllowanceCredentialReader, store?: AccountAllowanceStore, fetchImpl?: GrokAllowanceFetch, now?: () => number);
1586
+ collectMany(accounts: readonly SubscriptionAccountEntry<GrokTokenConfig>[], options?: GrokAllowanceCollectOptions): Promise<AccountAllowanceSnapshot[]>;
1587
+ collect(account: SubscriptionAccountEntry<GrokTokenConfig>, options?: GrokAllowanceCollectOptions): Promise<AccountAllowanceSnapshot>;
1588
+ private isCacheValid;
1589
+ private fetchAccount;
1590
+ private failureSnapshot;
1591
+ private unsupportedSnapshot;
1592
+ }
1593
+
1594
+ /**
1595
+ * CopilotAllowanceCollector — GitHub Copilot quota via the internal user API.
1596
+ *
1597
+ * Polls `GET api.github.com/copilot_internal/user` per copilot account
1598
+ * (Bearer ghu_ + the mirrored Copilot CLI user-agent), reading
1599
+ * `quota_snapshots`:
1600
+ * - `premium_interactions` — the plan's premium-request monthly window
1601
+ * (`{entitlement, remaining, percent_remaining, unlimited}` + the
1602
+ * account-level `quota_reset_date`). Reported as a single `thirty-day`
1603
+ * window; an `unlimited` entitlement reports 0% (never blocks).
1604
+ * - `chat` — the legacy chat-completions quota, reported only when it is
1605
+ * NOT unlimited (newer plans fold it into premium).
1606
+ *
1607
+ * Mirrors the Claude/Codex/Kimi/Grok collectors' cache contract: 5-minute
1608
+ * cache, per-account in-flight merging, one 401→refresh→retry (for copilot a
1609
+ * "refresh" marks the account expired — ghu_ tokens cannot be refreshed — so
1610
+ * the retry path is exercised only by transient upstream 401 flaps and never
1611
+ * loops). The GitHub API base honors the account's `enterpriseUrl` (GHE).
1612
+ */
1613
+
1614
+ interface CopilotAllowanceCredentialReader {
1615
+ getAccessTokenForAccount(providerId: 'copilot', accountId: string): Promise<string | null>;
1616
+ refreshAccountToken(providerId: 'copilot', accountId: string): Promise<boolean>;
1617
+ }
1618
+ type CopilotAllowanceFetch = (url: string, init: RequestInit, accountId: string) => Promise<Response>;
1619
+ interface CopilotAllowanceCollectOptions {
1620
+ force?: boolean;
1621
+ refreshAheadMs?: number;
1622
+ }
1623
+ declare class CopilotAllowanceCollector {
1624
+ private readonly credentials;
1625
+ private readonly store;
1626
+ private readonly fetchImpl;
1627
+ private readonly now;
1628
+ private readonly inFlight;
1629
+ constructor(credentials: CopilotAllowanceCredentialReader, store?: AccountAllowanceStore, fetchImpl?: CopilotAllowanceFetch, now?: () => number);
1630
+ collectMany(accounts: readonly SubscriptionAccountEntry<CopilotTokenConfig>[], options?: CopilotAllowanceCollectOptions): Promise<AccountAllowanceSnapshot[]>;
1631
+ collect(account: SubscriptionAccountEntry<CopilotTokenConfig>, options?: CopilotAllowanceCollectOptions): Promise<AccountAllowanceSnapshot>;
1632
+ private isCacheValid;
1633
+ private fetchAccount;
1634
+ private request;
1635
+ private failureSnapshot;
1636
+ private unsupportedSnapshot;
1637
+ }
1638
+
1513
1639
  /**
1514
1640
  * OpenCodeGo usage collector.
1515
1641
  *
@@ -1557,8 +1683,8 @@ declare class OpenCodeGoAllowanceCollector {
1557
1683
  * literals — extending them all would make the overloads conflict.
1558
1684
  */
1559
1685
  interface AccountAllowanceCredentialReader {
1560
- getAccessTokenForAccount(providerId: 'claude' | 'codex' | 'kimi' | 'opencodego', accountId: string): Promise<string | null>;
1561
- refreshAccountToken(providerId: 'claude' | 'codex' | 'kimi', accountId: string): Promise<boolean>;
1686
+ getAccessTokenForAccount(providerId: 'claude' | 'codex' | 'kimi' | 'opencodego' | 'grok' | 'copilot', accountId: string): Promise<string | null>;
1687
+ refreshAccountToken(providerId: 'claude' | 'codex' | 'kimi' | 'grok' | 'copilot', accountId: string): Promise<boolean>;
1562
1688
  getFullConfig(): Promise<AccountTokensConfig>;
1563
1689
  }
1564
1690
  interface AccountAllowanceFilter {
@@ -1576,8 +1702,10 @@ declare class AccountAllowanceService {
1576
1702
  readonly claudeCollector: ClaudeAllowanceCollector;
1577
1703
  readonly codexCollector: CodexAllowanceCollector;
1578
1704
  readonly kimiCollector: KimiAllowanceCollector;
1705
+ readonly grokCollector: GrokAllowanceCollector;
1706
+ readonly copilotCollector: CopilotAllowanceCollector;
1579
1707
  readonly opencodegoCollector: OpenCodeGoAllowanceCollector;
1580
- constructor(credentials: AccountAllowanceCredentialReader, store?: AccountAllowanceStore, collector?: ClaudeAllowanceCollector, codexCollector?: CodexAllowanceCollector, kimiCollector?: KimiAllowanceCollector, opencodegoCollector?: OpenCodeGoAllowanceCollector, now?: () => number);
1708
+ constructor(credentials: AccountAllowanceCredentialReader, store?: AccountAllowanceStore, collector?: ClaudeAllowanceCollector, codexCollector?: CodexAllowanceCollector, kimiCollector?: KimiAllowanceCollector, opencodegoCollector?: OpenCodeGoAllowanceCollector, grokCollector?: GrokAllowanceCollector, copilotCollector?: CopilotAllowanceCollector, now?: () => number);
1581
1709
  /**
1582
1710
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1583
1711
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -1597,6 +1725,10 @@ declare class AccountAllowanceService {
1597
1725
  refreshOpenCodeGo(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1598
1726
  /** Force-refresh Kimi usage (`/coding/v1/usages`) for one/all accounts. */
1599
1727
  refreshKimi(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1728
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
1729
+ refreshCopilot(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1730
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
1731
+ refreshGrok(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1600
1732
  /**
1601
1733
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1602
1734
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -1988,6 +2120,12 @@ type BillingStatusReader = () => BillingDeliveryStatus;
1988
2120
  * .status_code === 0` is the real success gate. `model_remains[]` buckets
1989
2121
  * each carry a rolling interval + weekly window as REMAINING percent
1990
2122
  * (0-100); the `"general"` bucket is the plan-wide shared quota.
2123
+ * - Cline Pass:
2124
+ * GET {origin}/api/v1/users/me/plan/usage-limits
2125
+ * `Authorization: Bearer <key>` PLUS the Cline client-identity header set
2126
+ * (the row's `extraHeaders` — the gateway 403s without the full mirror).
2127
+ * `limits[]` rows carry `{type: five_hour|weekly|monthly, percentUsed,
2128
+ * resetsAt}` — pure percentage windows, no absolute meters.
1991
2129
  *
1992
2130
  * Everything here is pure; the fetch/cache lifecycle lives in
1993
2131
  * `ProviderKeyQuotaService`. Windows reuse the subscription `AllowanceWindow`
@@ -1995,7 +2133,7 @@ type BillingStatusReader = () => BillingDeliveryStatus;
1995
2133
  */
1996
2134
 
1997
2135
  /** Which quota adapter applies to a provider row (by resolved endpoint). */
1998
- type ProviderKeyQuotaAdapter = 'zai' | 'minimax-token-plan' | 'umans' | 'synthetic';
2136
+ type ProviderKeyQuotaAdapter = 'zai' | 'minimax-token-plan' | 'umans' | 'synthetic' | 'cline-pass';
1999
2137
 
2000
2138
  /**
2001
2139
  * ProviderKeyQuotaService — read-through quota cache for BYO provider-row keys.
@@ -2797,6 +2935,10 @@ interface AccountAllowanceAdminReader {
2797
2935
  refreshKimi?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2798
2936
  /** Optional: OpenCodeGo `/v1/usage` refresh (absent on older daemons). */
2799
2937
  refreshOpenCodeGo?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2938
+ /** Optional: Grok CLI-billing refresh (absent on older daemons). */
2939
+ refreshGrok?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2940
+ /** Optional: Copilot user-quota refresh (absent on older daemons). */
2941
+ refreshCopilot?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2800
2942
  removeAccountSnapshot?(providerId: SubscriptionProviderId, accountId: string): void;
2801
2943
  removeProviderSnapshots?(providerId: SubscriptionProviderId): void;
2802
2944
  getSchedulingStatus?(): AccountAllowanceSchedulingStatus;
@@ -2946,6 +3088,16 @@ interface AdminApiDeps {
2946
3088
  * shape as codex; one sign-in at a time. Wired in `bootstrap.ts`.
2947
3089
  */
2948
3090
  readonly kimiSessions: CodexOAuthSessionStore;
3091
+ /**
3092
+ * Grok interactive-OAuth flow store (device code). Same token-free polled
3093
+ * shape as codex; one sign-in at a time. Wired in `bootstrap.ts`.
3094
+ */
3095
+ readonly grokSessions: CodexOAuthSessionStore;
3096
+ /**
3097
+ * Copilot interactive-OAuth flow store (device code). Same token-free
3098
+ * polled shape; one sign-in at a time. Wired in `bootstrap.ts`.
3099
+ */
3100
+ readonly copilotSessions: CodexOAuthSessionStore;
2949
3101
  /**
2950
3102
  * Codex loopback listener (app-parity-2 child 5) — defaults to `awaitLoopbackCode`
2951
3103
  * (binds 127.0.0.1:1455) in `bootstrap.ts`; tests inject a mock so no real port
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { RouteLeaseManager, ProviderProxy } from '@omnicross/core/provider-proxy
6
6
  import { UsageRecorder, PricingEngine } from '@omnicross/core/usage';
7
7
  import { SubscriptionCredentialStore, FetchLike, CodexImageCapabilityEvidenceSource, CodexImageCapabilityEvidenceRequest, CodexImageCapabilityEvidence, CodexImageCapabilityObservation, ImageExecutionScheduler, ImageExecutionAccountKey, ImageExecutionSchedulerRequest, ImageExecutionSchedulerGrant, SubscriptionAccountService, SubscriptionProviderRegistry } from '@omnicross/subscriptions';
8
8
  import { AccountAllowanceSnapshot, AllowanceWindow } from '@omnicross/contracts/account-allowance-types';
9
- import { ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, KimiTokenConfig, AccountTokensConfig, ProxyConfig, SubscriptionAccountSanitized, AccountClientIdentity, SubscriptionAccountEntry } from '@omnicross/contracts/account-tokens-types';
9
+ import { ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, KimiTokenConfig, GrokTokenConfig, CopilotTokenConfig, AccountTokensConfig, ProxyConfig, SubscriptionAccountSanitized, AccountClientIdentity, SubscriptionAccountEntry } from '@omnicross/contracts/account-tokens-types';
10
10
  import * as _omnicross_contracts_subscription_types from '@omnicross/contracts/subscription-types';
11
11
  import { OpenCodeGoTokenConfig, SubscriptionProviderId } from '@omnicross/contracts/subscription-types';
12
12
  import { AccountAllowanceStore } from '@omnicross/core/pipeline/AccountAllowanceStore';
@@ -536,6 +536,18 @@ interface DaemonProviderConfig {
536
536
  * round-trips verbatim on GET. Management-UI only.
537
537
  */
538
538
  modelsEndpoint?: string;
539
+ /**
540
+ * OPTIONAL static extra request headers merged into every BYO request for
541
+ * this row — identity/attribution contracts some gateways hard-gate on
542
+ * (e.g. the Cline client-identity set). Additive + back-compat: absent
543
+ * reads as undefined. NON-SECRET — round-trips verbatim on GET; values may
544
+ * carry `{{platform}}` (resolved to `process.platform` at request time).
545
+ * ENFORCED: the outbound header funnel (`getProviderHeaders`) +
546
+ * discover-models + test-model merge them; auth/content header NAMES are
547
+ * dropped by the load guard (`validateExtraHeaders`) so credentials stay
548
+ * key-field-only.
549
+ */
550
+ extraHeaders?: Record<string, string>;
539
551
  /**
540
552
  * OPTIONAL provider transformer config (app-parity child 5). Additive +
541
553
  * back-compat: absent reads as the prior default (undefined). NON-SECRET —
@@ -666,7 +678,7 @@ type AtomicFileReplace = (targetPath: string, contents: string) => void;
666
678
  */
667
679
 
668
680
  /** Provider id → owned contract field names. */
669
- type DaemonProvider = 'claude' | 'codex' | 'gemini' | 'opencodego' | 'kimi';
681
+ type DaemonProvider = 'claude' | 'codex' | 'gemini' | 'opencodego' | 'kimi' | 'grok' | 'copilot';
670
682
  interface AccountMetadataPatch {
671
683
  label?: string;
672
684
  enabled?: boolean;
@@ -795,7 +807,7 @@ type ExternalCliReader = (provider: ExternalCliProvider) => ExternalCliCredentia
795
807
  * shapes), keyed by `SubscriptionProviderId` the daemon admin layer validates
796
808
  * the wire body to one of these before calling the writer.
797
809
  */
798
- type SubscriptionTokenBlock = ClaudeTokenConfig | CodexTokenConfig | GeminiTokenConfig | OpenCodeGoTokenConfig | KimiTokenConfig;
810
+ type SubscriptionTokenBlock = ClaudeTokenConfig | CodexTokenConfig | GeminiTokenConfig | OpenCodeGoTokenConfig | KimiTokenConfig | GrokTokenConfig | CopilotTokenConfig;
799
811
  declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialStore {
800
812
  private readonly tokensPath;
801
813
  private readonly box;
@@ -907,13 +919,28 @@ declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialS
907
919
  * `false` when no refresh_token.
908
920
  */
909
921
  refreshKimiToken(): Promise<boolean>;
922
+ /**
923
+ * Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
924
+ * resolved through OIDC discovery on every refresh (process-cached 1h by the
925
+ * flow module) so a rotated endpoint document is picked up without a daemon
926
+ * restart. HONEST `false` when no refresh_token.
927
+ */
928
+ refreshGrokToken(): Promise<boolean>;
929
+ /**
930
+ * "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
931
+ * tokens are long-lived with no exchange endpoint). A call here means the
932
+ * strategy saw a 401 (the token was revoked); mark the account `expired`
933
+ * with a re-authenticate message and return `false` (the proxy then declines
934
+ * the retry instead of looping on a dead token).
935
+ */
936
+ refreshCopilotToken(): Promise<boolean>;
910
937
  /**
911
938
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
912
939
  * account-pool resolution). It uses only that account's stored refresh
913
940
  * token. Coalesced per `provider:id`; on failure flags ONLY that account
914
941
  * `expired`.
915
942
  */
916
- refreshAccountById(provider: 'claude' | 'codex' | 'gemini' | 'kimi', id: string): Promise<boolean>;
943
+ refreshAccountById(provider: 'claude' | 'codex' | 'gemini' | 'kimi' | 'grok' | 'copilot', id: string): Promise<boolean>;
917
944
  /**
918
945
  * Resolve a SPECIFIC account's access token by id (design D6). Mirrors each
919
946
  * provider's ACTIVE-getter policy, keyed by id: claude returns the stored token
@@ -1510,6 +1537,105 @@ declare class KimiAllowanceCollector {
1510
1537
  private unsupportedSnapshot;
1511
1538
  }
1512
1539
 
1540
+ /**
1541
+ * Grok (xAI SuperGrok) OAuth usage collector.
1542
+ *
1543
+ * Polls the Grok CLI billing proxy (`cli-chat-proxy.grok.com/v1/billing` —
1544
+ * NOT `*.x.ai`, and it REJECTS paid API keys: OAuth bearer only) per grok
1545
+ * account, mirroring the Claude/Codex/Kimi collectors' cache contract:
1546
+ * 5-minute cache, per-account in-flight merging, one 401→refresh→retry.
1547
+ *
1548
+ * Dual shape (mirrors the audit source's semantics):
1549
+ * - WEEKLY credits (`?format=credits`): `config.creditUsagePercent` +
1550
+ * `config.currentPeriod{start,end,type}` (+ per-product rows and an
1551
+ * on-demand cap, both optional). A missing `creditUsagePercent` on an
1552
+ * ACTIVE weekly period reads as 0 (a fresh period has no usage row).
1553
+ * - UNIFIED monthly (default URL): `config.{billingPeriodStart,
1554
+ * billingPeriodEnd, monthlyLimit{val}, used{val}}` — accounts flagged
1555
+ * `isUnifiedBillingUser` omit the weekly percentage and meter a monthly
1556
+ * included quota instead.
1557
+ *
1558
+ * Probe policy: always probe weekly first; probe monthly when weekly is
1559
+ * missing OR the account is flagged unified. An INFERRED weekly percentage
1560
+ * (field absent) on a unified account is only kept when the monthly probe
1561
+ * positively confirms there is no monthly quota — otherwise the monthly
1562
+ * window wins (an inferred 0% weekly on a unified account is a lie), and a
1563
+ * failed monthly probe falls through to a failure snapshot so the store
1564
+ * retains the last good one.
1565
+ *
1566
+ * Every request carries `X-XAI-Token-Auth: xai-grok-cli` — the same product
1567
+ * gate the official CLI uses on this host.
1568
+ */
1569
+
1570
+ interface GrokAllowanceCredentialReader {
1571
+ getAccessTokenForAccount(providerId: 'grok', accountId: string): Promise<string | null>;
1572
+ refreshAccountToken(providerId: 'grok', accountId: string): Promise<boolean>;
1573
+ }
1574
+ type GrokAllowanceFetch = (url: string, init: RequestInit, accountId: string) => Promise<Response>;
1575
+ interface GrokAllowanceCollectOptions {
1576
+ force?: boolean;
1577
+ refreshAheadMs?: number;
1578
+ }
1579
+ declare class GrokAllowanceCollector {
1580
+ private readonly credentials;
1581
+ private readonly store;
1582
+ private readonly fetchImpl;
1583
+ private readonly now;
1584
+ private readonly inFlight;
1585
+ constructor(credentials: GrokAllowanceCredentialReader, store?: AccountAllowanceStore, fetchImpl?: GrokAllowanceFetch, now?: () => number);
1586
+ collectMany(accounts: readonly SubscriptionAccountEntry<GrokTokenConfig>[], options?: GrokAllowanceCollectOptions): Promise<AccountAllowanceSnapshot[]>;
1587
+ collect(account: SubscriptionAccountEntry<GrokTokenConfig>, options?: GrokAllowanceCollectOptions): Promise<AccountAllowanceSnapshot>;
1588
+ private isCacheValid;
1589
+ private fetchAccount;
1590
+ private failureSnapshot;
1591
+ private unsupportedSnapshot;
1592
+ }
1593
+
1594
+ /**
1595
+ * CopilotAllowanceCollector — GitHub Copilot quota via the internal user API.
1596
+ *
1597
+ * Polls `GET api.github.com/copilot_internal/user` per copilot account
1598
+ * (Bearer ghu_ + the mirrored Copilot CLI user-agent), reading
1599
+ * `quota_snapshots`:
1600
+ * - `premium_interactions` — the plan's premium-request monthly window
1601
+ * (`{entitlement, remaining, percent_remaining, unlimited}` + the
1602
+ * account-level `quota_reset_date`). Reported as a single `thirty-day`
1603
+ * window; an `unlimited` entitlement reports 0% (never blocks).
1604
+ * - `chat` — the legacy chat-completions quota, reported only when it is
1605
+ * NOT unlimited (newer plans fold it into premium).
1606
+ *
1607
+ * Mirrors the Claude/Codex/Kimi/Grok collectors' cache contract: 5-minute
1608
+ * cache, per-account in-flight merging, one 401→refresh→retry (for copilot a
1609
+ * "refresh" marks the account expired — ghu_ tokens cannot be refreshed — so
1610
+ * the retry path is exercised only by transient upstream 401 flaps and never
1611
+ * loops). The GitHub API base honors the account's `enterpriseUrl` (GHE).
1612
+ */
1613
+
1614
+ interface CopilotAllowanceCredentialReader {
1615
+ getAccessTokenForAccount(providerId: 'copilot', accountId: string): Promise<string | null>;
1616
+ refreshAccountToken(providerId: 'copilot', accountId: string): Promise<boolean>;
1617
+ }
1618
+ type CopilotAllowanceFetch = (url: string, init: RequestInit, accountId: string) => Promise<Response>;
1619
+ interface CopilotAllowanceCollectOptions {
1620
+ force?: boolean;
1621
+ refreshAheadMs?: number;
1622
+ }
1623
+ declare class CopilotAllowanceCollector {
1624
+ private readonly credentials;
1625
+ private readonly store;
1626
+ private readonly fetchImpl;
1627
+ private readonly now;
1628
+ private readonly inFlight;
1629
+ constructor(credentials: CopilotAllowanceCredentialReader, store?: AccountAllowanceStore, fetchImpl?: CopilotAllowanceFetch, now?: () => number);
1630
+ collectMany(accounts: readonly SubscriptionAccountEntry<CopilotTokenConfig>[], options?: CopilotAllowanceCollectOptions): Promise<AccountAllowanceSnapshot[]>;
1631
+ collect(account: SubscriptionAccountEntry<CopilotTokenConfig>, options?: CopilotAllowanceCollectOptions): Promise<AccountAllowanceSnapshot>;
1632
+ private isCacheValid;
1633
+ private fetchAccount;
1634
+ private request;
1635
+ private failureSnapshot;
1636
+ private unsupportedSnapshot;
1637
+ }
1638
+
1513
1639
  /**
1514
1640
  * OpenCodeGo usage collector.
1515
1641
  *
@@ -1557,8 +1683,8 @@ declare class OpenCodeGoAllowanceCollector {
1557
1683
  * literals — extending them all would make the overloads conflict.
1558
1684
  */
1559
1685
  interface AccountAllowanceCredentialReader {
1560
- getAccessTokenForAccount(providerId: 'claude' | 'codex' | 'kimi' | 'opencodego', accountId: string): Promise<string | null>;
1561
- refreshAccountToken(providerId: 'claude' | 'codex' | 'kimi', accountId: string): Promise<boolean>;
1686
+ getAccessTokenForAccount(providerId: 'claude' | 'codex' | 'kimi' | 'opencodego' | 'grok' | 'copilot', accountId: string): Promise<string | null>;
1687
+ refreshAccountToken(providerId: 'claude' | 'codex' | 'kimi' | 'grok' | 'copilot', accountId: string): Promise<boolean>;
1562
1688
  getFullConfig(): Promise<AccountTokensConfig>;
1563
1689
  }
1564
1690
  interface AccountAllowanceFilter {
@@ -1576,8 +1702,10 @@ declare class AccountAllowanceService {
1576
1702
  readonly claudeCollector: ClaudeAllowanceCollector;
1577
1703
  readonly codexCollector: CodexAllowanceCollector;
1578
1704
  readonly kimiCollector: KimiAllowanceCollector;
1705
+ readonly grokCollector: GrokAllowanceCollector;
1706
+ readonly copilotCollector: CopilotAllowanceCollector;
1579
1707
  readonly opencodegoCollector: OpenCodeGoAllowanceCollector;
1580
- constructor(credentials: AccountAllowanceCredentialReader, store?: AccountAllowanceStore, collector?: ClaudeAllowanceCollector, codexCollector?: CodexAllowanceCollector, kimiCollector?: KimiAllowanceCollector, opencodegoCollector?: OpenCodeGoAllowanceCollector, now?: () => number);
1708
+ constructor(credentials: AccountAllowanceCredentialReader, store?: AccountAllowanceStore, collector?: ClaudeAllowanceCollector, codexCollector?: CodexAllowanceCollector, kimiCollector?: KimiAllowanceCollector, opencodegoCollector?: OpenCodeGoAllowanceCollector, grokCollector?: GrokAllowanceCollector, copilotCollector?: CopilotAllowanceCollector, now?: () => number);
1581
1709
  /**
1582
1710
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1583
1711
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -1597,6 +1725,10 @@ declare class AccountAllowanceService {
1597
1725
  refreshOpenCodeGo(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1598
1726
  /** Force-refresh Kimi usage (`/coding/v1/usages`) for one/all accounts. */
1599
1727
  refreshKimi(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1728
+ /** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
1729
+ refreshCopilot(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1730
+ /** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
1731
+ refreshGrok(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
1600
1732
  /**
1601
1733
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
1602
1734
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -1988,6 +2120,12 @@ type BillingStatusReader = () => BillingDeliveryStatus;
1988
2120
  * .status_code === 0` is the real success gate. `model_remains[]` buckets
1989
2121
  * each carry a rolling interval + weekly window as REMAINING percent
1990
2122
  * (0-100); the `"general"` bucket is the plan-wide shared quota.
2123
+ * - Cline Pass:
2124
+ * GET {origin}/api/v1/users/me/plan/usage-limits
2125
+ * `Authorization: Bearer <key>` PLUS the Cline client-identity header set
2126
+ * (the row's `extraHeaders` — the gateway 403s without the full mirror).
2127
+ * `limits[]` rows carry `{type: five_hour|weekly|monthly, percentUsed,
2128
+ * resetsAt}` — pure percentage windows, no absolute meters.
1991
2129
  *
1992
2130
  * Everything here is pure; the fetch/cache lifecycle lives in
1993
2131
  * `ProviderKeyQuotaService`. Windows reuse the subscription `AllowanceWindow`
@@ -1995,7 +2133,7 @@ type BillingStatusReader = () => BillingDeliveryStatus;
1995
2133
  */
1996
2134
 
1997
2135
  /** Which quota adapter applies to a provider row (by resolved endpoint). */
1998
- type ProviderKeyQuotaAdapter = 'zai' | 'minimax-token-plan' | 'umans' | 'synthetic';
2136
+ type ProviderKeyQuotaAdapter = 'zai' | 'minimax-token-plan' | 'umans' | 'synthetic' | 'cline-pass';
1999
2137
 
2000
2138
  /**
2001
2139
  * ProviderKeyQuotaService — read-through quota cache for BYO provider-row keys.
@@ -2797,6 +2935,10 @@ interface AccountAllowanceAdminReader {
2797
2935
  refreshKimi?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2798
2936
  /** Optional: OpenCodeGo `/v1/usage` refresh (absent on older daemons). */
2799
2937
  refreshOpenCodeGo?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2938
+ /** Optional: Grok CLI-billing refresh (absent on older daemons). */
2939
+ refreshGrok?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2940
+ /** Optional: Copilot user-quota refresh (absent on older daemons). */
2941
+ refreshCopilot?(accountId?: string): Promise<AccountAllowanceSnapshot[]>;
2800
2942
  removeAccountSnapshot?(providerId: SubscriptionProviderId, accountId: string): void;
2801
2943
  removeProviderSnapshots?(providerId: SubscriptionProviderId): void;
2802
2944
  getSchedulingStatus?(): AccountAllowanceSchedulingStatus;
@@ -2946,6 +3088,16 @@ interface AdminApiDeps {
2946
3088
  * shape as codex; one sign-in at a time. Wired in `bootstrap.ts`.
2947
3089
  */
2948
3090
  readonly kimiSessions: CodexOAuthSessionStore;
3091
+ /**
3092
+ * Grok interactive-OAuth flow store (device code). Same token-free polled
3093
+ * shape as codex; one sign-in at a time. Wired in `bootstrap.ts`.
3094
+ */
3095
+ readonly grokSessions: CodexOAuthSessionStore;
3096
+ /**
3097
+ * Copilot interactive-OAuth flow store (device code). Same token-free
3098
+ * polled shape; one sign-in at a time. Wired in `bootstrap.ts`.
3099
+ */
3100
+ readonly copilotSessions: CodexOAuthSessionStore;
2949
3101
  /**
2950
3102
  * Codex loopback listener (app-parity-2 child 5) — defaults to `awaitLoopbackCode`
2951
3103
  * (binds 127.0.0.1:1455) in `bootstrap.ts`; tests inject a mock so no real port