mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
- 新增 providerUsage 服务(anthropic/bedrock/openai 适配器) - 新增余额查询(deepseek/generic poller) - StatusLine 保留原有 rateLimits 接口不变 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
import { setProviderBalance } from '../store.js'
|
|
import { deepseekBalanceProvider } from './deepseek.js'
|
|
import { genericBalanceProvider } from './generic.js'
|
|
import type { BalanceProvider } from './types.js'
|
|
|
|
const DEFAULT_INTERVAL_MIN = 10
|
|
|
|
// Registration order = priority. First enabled wins. Generic (user-supplied
|
|
// URL) comes first so operators can override the built-in DeepSeek detection.
|
|
const PROVIDERS: BalanceProvider[] = [
|
|
genericBalanceProvider,
|
|
deepseekBalanceProvider,
|
|
]
|
|
|
|
function selectProvider(): BalanceProvider | null {
|
|
if (process.env.CLAUDE_CODE_BALANCE_PROVIDER === 'none') return null
|
|
return PROVIDERS.find(p => p.isEnabled()) ?? null
|
|
}
|
|
|
|
function intervalMs(): number {
|
|
const raw = process.env.CLAUDE_CODE_BALANCE_POLL_INTERVAL_MINUTES
|
|
const n = raw ? Number(raw) : DEFAULT_INTERVAL_MIN
|
|
if (!Number.isFinite(n) || n <= 0) return DEFAULT_INTERVAL_MIN * 60_000
|
|
return Math.floor(n * 60_000)
|
|
}
|
|
|
|
let timer: ReturnType<typeof setInterval> | null = null
|
|
let inflight: AbortController | null = null
|
|
let active: BalanceProvider | null = null
|
|
|
|
const FETCH_TIMEOUT_MS = 10_000
|
|
|
|
async function tick(): Promise<void> {
|
|
if (!active) return
|
|
inflight?.abort()
|
|
inflight = new AbortController()
|
|
const timeout = setTimeout(() => inflight?.abort(), FETCH_TIMEOUT_MS)
|
|
try {
|
|
const balance = await active.fetchBalance(inflight.signal)
|
|
setProviderBalance(active.providerId, balance)
|
|
} catch {
|
|
// Never bubble into the host process.
|
|
} finally {
|
|
clearTimeout(timeout)
|
|
}
|
|
}
|
|
|
|
/** Start polling if a provider is configured. Idempotent. */
|
|
export function startBalancePolling(): void {
|
|
if (timer !== null) return
|
|
active = selectProvider()
|
|
if (!active) return
|
|
// Kick off immediately, then on interval.
|
|
void tick()
|
|
timer = setInterval(() => {
|
|
void tick()
|
|
}, intervalMs())
|
|
// Don't keep the event loop alive just for the poller.
|
|
if (
|
|
typeof (timer as unknown as { unref?: () => void }).unref === 'function'
|
|
) {
|
|
;(timer as unknown as { unref: () => void }).unref()
|
|
}
|
|
}
|
|
|
|
export function stopBalancePolling(): void {
|
|
if (timer !== null) {
|
|
clearInterval(timer)
|
|
timer = null
|
|
}
|
|
inflight?.abort()
|
|
inflight = null
|
|
active = null
|
|
}
|
|
|
|
export function getActiveBalanceProviderId(): string | null {
|
|
return active?.providerId ?? null
|
|
}
|