fix: read tokens from .env file, clean up debug logs
- token-rotation reads from readEnvFile() (systemd doesn't load .env) - fetchAllClaudeUsage polling log demoted to debug level - Remove verbose dashboard send/create logs
This commit is contained in:
@@ -7,7 +7,10 @@ describe('ClaudeUsageData', () => {
|
||||
const data: ClaudeUsageData = {
|
||||
five_hour: { utilization: 45.2, resets_at: '2026-03-23T17:00:00Z' },
|
||||
seven_day: { utilization: 72.1, resets_at: '2026-03-29T00:00:00Z' },
|
||||
seven_day_sonnet: { utilization: 60.0, resets_at: '2026-03-29T00:00:00Z' },
|
||||
seven_day_sonnet: {
|
||||
utilization: 60.0,
|
||||
resets_at: '2026-03-29T00:00:00Z',
|
||||
},
|
||||
seven_day_opus: { utilization: 80.0, resets_at: '2026-03-29T00:00:00Z' },
|
||||
};
|
||||
|
||||
|
||||
@@ -25,9 +25,10 @@ interface UsageApiResponse {
|
||||
seven_day_opus?: { utilization: number; resets_at?: string };
|
||||
}
|
||||
|
||||
function mapWindow(
|
||||
w?: { utilization: number; resets_at?: string },
|
||||
): { utilization: number; resets_at: string } | undefined {
|
||||
function mapWindow(w?: {
|
||||
utilization: number;
|
||||
resets_at?: string;
|
||||
}): { utilization: number; resets_at: string } | undefined {
|
||||
if (!w) return undefined;
|
||||
return { utilization: w.utilization, resets_at: w.resets_at || '' };
|
||||
}
|
||||
@@ -77,10 +78,7 @@ async function fetchUsageForToken(
|
||||
if ((err as Error).name === 'AbortError') {
|
||||
logger.warn('Claude usage API: request timed out');
|
||||
} else {
|
||||
logger.warn(
|
||||
{ err },
|
||||
'Claude usage API: fetch failed',
|
||||
);
|
||||
logger.warn({ err }, 'Claude usage API: fetch failed');
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
@@ -93,8 +91,7 @@ async function fetchUsageForToken(
|
||||
* Uses the current active token from rotation.
|
||||
*/
|
||||
export async function fetchClaudeUsage(): Promise<ClaudeUsageData | null> {
|
||||
const token =
|
||||
getCurrentToken() || process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
||||
const token = getCurrentToken() || process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
||||
if (!token) {
|
||||
logger.debug('No Claude OAuth token available for usage check');
|
||||
return null;
|
||||
@@ -116,18 +113,21 @@ export interface ClaudeAccountUsage {
|
||||
*/
|
||||
export async function fetchAllClaudeUsage(): Promise<ClaudeAccountUsage[]> {
|
||||
const allTokens = getAllTokens();
|
||||
logger.debug({ tokenCount: allTokens.length }, 'fetchAllClaudeUsage called');
|
||||
if (allTokens.length === 0) {
|
||||
// Single token fallback
|
||||
const token = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
||||
if (!token) return [];
|
||||
const usage = await fetchUsageForToken(token);
|
||||
return [{
|
||||
index: 0,
|
||||
masked: `${token.slice(0, 20)}...${token.slice(-4)}`,
|
||||
isActive: true,
|
||||
isRateLimited: false,
|
||||
usage,
|
||||
}];
|
||||
return [
|
||||
{
|
||||
index: 0,
|
||||
masked: `${token.slice(0, 20)}...${token.slice(-4)}`,
|
||||
isActive: true,
|
||||
isRateLimited: false,
|
||||
usage,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const results: ClaudeAccountUsage[] = [];
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* All exhausted: fall through to provider fallback (Kimi etc.)
|
||||
*/
|
||||
|
||||
import { readEnvFile } from './env.js';
|
||||
import { logger } from './logger.js';
|
||||
|
||||
interface TokenState {
|
||||
@@ -25,8 +26,16 @@ export function initTokenRotation(): void {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
const multi = process.env.CLAUDE_CODE_OAUTH_TOKENS;
|
||||
const single = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
||||
const envFile = readEnvFile([
|
||||
'CLAUDE_CODE_OAUTH_TOKENS',
|
||||
'CLAUDE_CODE_OAUTH_TOKEN',
|
||||
]);
|
||||
const multi =
|
||||
process.env.CLAUDE_CODE_OAUTH_TOKENS ||
|
||||
envFile.CLAUDE_CODE_OAUTH_TOKENS;
|
||||
const single =
|
||||
process.env.CLAUDE_CODE_OAUTH_TOKEN ||
|
||||
envFile.CLAUDE_CODE_OAUTH_TOKEN;
|
||||
|
||||
const raw = multi
|
||||
? multi
|
||||
@@ -103,7 +112,13 @@ export function getTokenCount(): number {
|
||||
}
|
||||
|
||||
/** Get all configured tokens (masked for display, raw for API calls). */
|
||||
export function getAllTokens(): { index: number; token: string; masked: string; isActive: boolean; isRateLimited: boolean }[] {
|
||||
export function getAllTokens(): {
|
||||
index: number;
|
||||
token: string;
|
||||
masked: string;
|
||||
isActive: boolean;
|
||||
isRateLimited: boolean;
|
||||
}[] {
|
||||
const now = Date.now();
|
||||
return tokens.map((t, i) => ({
|
||||
index: i,
|
||||
|
||||
@@ -551,17 +551,31 @@ async function buildUsageContent(): Promise<string> {
|
||||
};
|
||||
const rows: UsageRow[] = [];
|
||||
|
||||
const claudeAccounts = liveClaudeAccounts
|
||||
|| (cachedClaudeUsageData ? [{ index: 0, masked: '', isActive: true, isRateLimited: false, usage: cachedClaudeUsageData }] : []);
|
||||
const claudeAccounts =
|
||||
liveClaudeAccounts ||
|
||||
(cachedClaudeUsageData
|
||||
? [
|
||||
{
|
||||
index: 0,
|
||||
masked: '',
|
||||
isActive: true,
|
||||
isRateLimited: false,
|
||||
usage: cachedClaudeUsageData,
|
||||
},
|
||||
]
|
||||
: []);
|
||||
|
||||
for (const account of claudeAccounts) {
|
||||
const u = account.usage;
|
||||
if (!u) continue;
|
||||
const h5 = u.five_hour;
|
||||
const d7 = u.seven_day;
|
||||
const label = claudeAccounts.length > 1
|
||||
? `Claude${account.index + 1}${account.isActive ? '⚡' : ''}${account.isRateLimited ? '🚫' : ''}`
|
||||
: claudeUsageIsCached ? 'Claude*' : 'Claude';
|
||||
const label =
|
||||
claudeAccounts.length > 1
|
||||
? `Claude${account.index + 1}${account.isActive ? '⚡' : ''}${account.isRateLimited ? '🚫' : ''}`
|
||||
: claudeUsageIsCached
|
||||
? 'Claude*'
|
||||
: 'Claude';
|
||||
rows.push({
|
||||
name: label,
|
||||
h5pct: h5
|
||||
@@ -717,6 +731,10 @@ export async function startUnifiedDashboard(
|
||||
await refreshChannelMeta(opts);
|
||||
const content = buildUnifiedDashboardContent();
|
||||
if (!content) {
|
||||
logger.warn(
|
||||
{ cachedUsageLength: cachedUsageContent.length, statusShowRooms: STATUS_SHOW_ROOMS },
|
||||
'Dashboard content empty, skipping render',
|
||||
);
|
||||
statusMessageId = null;
|
||||
return;
|
||||
}
|
||||
@@ -728,7 +746,7 @@ export async function startUnifiedDashboard(
|
||||
if (id) statusMessageId = id;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.debug({ err }, 'Dashboard update failed');
|
||||
logger.warn({ err }, 'Dashboard update failed');
|
||||
statusMessageId = null;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user