diff --git a/packages/web/src/components/AccountCard.tsx b/packages/web/src/components/AccountCard.tsx
index 4270098..3e68351 100644
--- a/packages/web/src/components/AccountCard.tsx
+++ b/packages/web/src/components/AccountCard.tsx
@@ -93,10 +93,14 @@ export type AccountData = {
};
export function AccountCard({ account }: { account: AccountData }) {
+ const hasWarning = account.credentialsValid && !account.isExhausted && account.error;
+
const statusIcon = !account.credentialsValid ? (
) : account.isExhausted ? (
+ ) : hasWarning ? (
+
) : (
);
@@ -105,7 +109,9 @@ export function AccountCard({ account }: { account: AccountData }) {
? "Invalid credentials"
: account.isExhausted
? `Exhausted until ${account.exhaustedUntil ? new Date(account.exhaustedUntil).toLocaleTimeString() : "unknown"}`
- : "Available";
+ : hasWarning
+ ? "Setup incomplete"
+ : "Available";
const usage = account.usage;
@@ -189,9 +195,11 @@ export function AccountCard({ account }: { account: AccountData }) {
)}
- {/* Error message */}
+ {/* Error / warning message */}
{account.error && (
-
{account.error}
+
+ {account.error}
+
)}
diff --git a/src/agent/accounts/usage.ts b/src/agent/accounts/usage.ts
index 0fc2a7f..d75c761 100644
--- a/src/agent/accounts/usage.ts
+++ b/src/agent/accounts/usage.ts
@@ -149,7 +149,12 @@ async function refreshToken(
}
}
-async function fetchUsage(accessToken: string): Promise {
+type FetchUsageResult =
+ | { ok: true; usage: AccountUsage }
+ | { ok: false; status: number; statusText: string }
+ | { ok: false; status: 0; statusText: string };
+
+async function fetchUsage(accessToken: string): Promise {
try {
const response = await fetch(USAGE_API_URL, {
method: 'GET',
@@ -159,17 +164,22 @@ async function fetchUsage(accessToken: string): Promise {
'Content-Type': 'application/json',
},
});
- if (!response.ok) return null;
+ if (!response.ok) {
+ return { ok: false, status: response.status, statusText: response.statusText };
+ }
const data = await response.json();
return {
- five_hour: data.five_hour ?? null,
- seven_day: data.seven_day ?? null,
- seven_day_sonnet: data.seven_day_sonnet ?? null,
- seven_day_opus: data.seven_day_opus ?? null,
- extra_usage: data.extra_usage ?? null,
+ ok: true,
+ usage: {
+ five_hour: data.five_hour ?? null,
+ seven_day: data.seven_day ?? null,
+ seven_day_sonnet: data.seven_day_sonnet ?? null,
+ seven_day_opus: data.seven_day_opus ?? null,
+ extra_usage: data.extra_usage ?? null,
+ },
};
- } catch {
- return null;
+ } catch (err) {
+ return { ok: false, status: 0, statusText: err instanceof Error ? err.message : 'Network error' };
}
}
@@ -280,12 +290,30 @@ export async function checkAccountHealth(
}
}
- const usage = await fetchUsage(accessToken);
- if (!usage) {
+ const isSetupToken = !currentExpiresAt;
+ const usageResult = await fetchUsage(accessToken);
+
+ if (!usageResult.ok) {
+ const statusDetail = usageResult.status > 0
+ ? `HTTP ${usageResult.status} ${usageResult.statusText}`
+ : usageResult.statusText;
+
+ if (isSetupToken) {
+ // Setup tokens often can't query the usage API — not a hard error
+ return {
+ ...base,
+ credentialsValid: true,
+ tokenValid: true,
+ tokenExpiresAt: null,
+ subscriptionType,
+ error: `Usage API unavailable for setup token (${statusDetail}). Run \`claude\` with this account to complete OAuth setup.`,
+ };
+ }
+
return {
...base,
credentialsValid: true,
- error: 'Usage API request failed',
+ error: `Usage API request failed: ${statusDetail}`,
};
}
@@ -295,7 +323,7 @@ export async function checkAccountHealth(
tokenValid: true,
tokenExpiresAt: currentExpiresAt ? new Date(currentExpiresAt).toISOString() : null,
subscriptionType,
- usage,
+ usage: usageResult.usage,
};
} catch (err) {
return {