diff --git a/packages/cli/src/config/footerItems.test.ts b/packages/cli/src/config/footerItems.test.ts
index 0f784c5517..c43ea7be0e 100644
--- a/packages/cli/src/config/footerItems.test.ts
+++ b/packages/cli/src/config/footerItems.test.ts
@@ -19,7 +19,7 @@ describe('deriveItemsFromLegacySettings', () => {
'git-branch',
'sandbox-status',
'model-name',
- 'usage-limit',
+ 'quota',
]);
});
@@ -39,14 +39,14 @@ describe('deriveItemsFromLegacySettings', () => {
expect(items).not.toContain('sandbox-status');
});
- it('removes model-name, context-remaining, and usage-limit when hideModelInfo is true', () => {
+ it('removes model-name, context-remaining, and quota when hideModelInfo is true', () => {
const settings = createMockSettings({
ui: { footer: { hideModelInfo: true, hideContextPercentage: true } },
}).merged;
const items = deriveItemsFromLegacySettings(settings);
expect(items).not.toContain('model-name');
expect(items).not.toContain('context-remaining');
- expect(items).not.toContain('usage-limit');
+ expect(items).not.toContain('quota');
});
it('includes context-remaining when hideContextPercentage is false', () => {
diff --git a/packages/cli/src/config/footerItems.ts b/packages/cli/src/config/footerItems.ts
index ba3c4a1307..0716478eb5 100644
--- a/packages/cli/src/config/footerItems.ts
+++ b/packages/cli/src/config/footerItems.ts
@@ -33,7 +33,7 @@ export const ALL_ITEMS = [
description: 'Percentage of context window remaining',
},
{
- id: 'usage-limit',
+ id: 'quota',
header: '/stats',
description: 'Remaining usage on daily limit (not shown when unavailable)',
},
@@ -67,7 +67,7 @@ export const DEFAULT_ORDER = [
'sandbox-status',
'model-name',
'context-remaining',
- 'usage-limit',
+ 'quota',
'memory-usage',
'session-id',
'code-changes',
@@ -82,7 +82,7 @@ export function deriveItemsFromLegacySettings(
'git-branch',
'sandbox-status',
'model-name',
- 'usage-limit',
+ 'quota',
];
const items = [...defaults];
@@ -96,7 +96,7 @@ export function deriveItemsFromLegacySettings(
if (settings.ui.footer.hideModelInfo) {
remove(items, 'model-name');
remove(items, 'context-remaining');
- remove(items, 'usage-limit');
+ remove(items, 'quota');
}
if (
!settings.ui.footer.hideContextPercentage &&
diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx
index d3b3bb5c31..c153f8e86a 100644
--- a/packages/cli/src/ui/components/Footer.tsx
+++ b/packages/cli/src/ui/components/Footer.tsx
@@ -17,10 +17,7 @@ import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js';
import process from 'node:process';
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
import { ContextUsageDisplay } from './ContextUsageDisplay.js';
-import {
- QUOTA_THRESHOLD_HIGH,
- QUOTA_THRESHOLD_MEDIUM,
-} from '../utils/displayUtils.js';
+import { QuotaDisplay } from './QuotaDisplay.js';
import { DebugProfiler } from './DebugProfiler.js';
import { useUIState } from '../contexts/UIStateContext.js';
import { useConfig } from '../contexts/ConfigContext.js';
@@ -312,24 +309,22 @@ export const Footer: React.FC = () => {
);
break;
}
- case 'usage-limit': {
+ case 'quota': {
if (quotaStats?.remaining !== undefined && quotaStats.limit) {
- const percentage = (quotaStats.remaining / quotaStats.limit) * 100;
- let color = itemColor;
- if (percentage < QUOTA_THRESHOLD_MEDIUM) {
- color = theme.status.error;
- } else if (percentage < QUOTA_THRESHOLD_HIGH) {
- color = theme.status.warning;
- }
- const text =
- quotaStats.remaining === 0
- ? 'limit reached'
- : `daily ${percentage.toFixed(0)}%`;
addCol(
id,
header,
- () => {text},
- text.length,
+ () => (
+
+ ),
+ 10, // "daily 100%" is 10 chars, but terse is "100%" (4 chars)
);
}
break;
@@ -375,18 +370,16 @@ export const Footer: React.FC = () => {
for (const m of Object.values(uiState.sessionStats.metrics.models))
total += m.tokens.total;
if (total > 0) {
- const formatted =
- new Intl.NumberFormat('en-US', {
- notation: 'compact',
- maximumFractionDigits: 1,
- })
- .format(total)
- .toLowerCase() + ' tokens';
+ const formatter = new Intl.NumberFormat('en-US', {
+ notation: 'compact',
+ maximumFractionDigits: 1,
+ });
+ const formatted = formatter.format(total).toLowerCase();
addCol(
id,
header,
- () => {formatted},
- formatted.length,
+ () => {formatted} tokens,
+ formatted.length + 7,
);
}
break;
diff --git a/packages/cli/src/ui/components/FooterConfigDialog.tsx b/packages/cli/src/ui/components/FooterConfigDialog.tsx
index 7652e01973..4a9ca3d55f 100644
--- a/packages/cli/src/ui/components/FooterConfigDialog.tsx
+++ b/packages/cli/src/ui/components/FooterConfigDialog.tsx
@@ -285,9 +285,7 @@ export const FooterConfigDialog: React.FC = ({
'context-remaining': (
85% left
),
- 'usage-limit': (
- daily 97%
- ),
+ quota: 97%,
'memory-usage': (
260 MB
),
diff --git a/packages/cli/src/ui/components/QuotaDisplay.tsx b/packages/cli/src/ui/components/QuotaDisplay.tsx
index d20291580a..881f4c77fd 100644
--- a/packages/cli/src/ui/components/QuotaDisplay.tsx
+++ b/packages/cli/src/ui/components/QuotaDisplay.tsx
@@ -18,6 +18,8 @@ interface QuotaDisplayProps {
limit: number | undefined;
resetTime?: string;
terse?: boolean;
+ forceShow?: boolean;
+ lowercase?: boolean;
}
export const QuotaDisplay: React.FC = ({
@@ -25,6 +27,8 @@ export const QuotaDisplay: React.FC = ({
limit,
resetTime,
terse = false,
+ forceShow = false,
+ lowercase = false,
}) => {
if (remaining === undefined || limit === undefined || limit === 0) {
return null;
@@ -32,7 +36,7 @@ export const QuotaDisplay: React.FC = ({
const percentage = (remaining / limit) * 100;
- if (percentage > QUOTA_THRESHOLD_HIGH) {
+ if (!forceShow && percentage > QUOTA_THRESHOLD_HIGH) {
return null;
}
@@ -45,20 +49,17 @@ export const QuotaDisplay: React.FC = ({
!terse && resetTime ? `, ${formatResetTime(resetTime)}` : '';
if (remaining === 0) {
- return (
-
- {terse
- ? 'Limit reached'
- : `/stats Limit reached${resetInfo}${!terse && '. /auth to continue.'}`}
-
- );
+ let text = terse
+ ? 'Limit reached'
+ : `/stats Limit reached${resetInfo}${!terse && '. /auth to continue.'}`;
+ if (lowercase) text = text.toLowerCase();
+ return {text};
}
- return (
-
- {terse
- ? `${percentage.toFixed(0)}%`
- : `/stats ${percentage.toFixed(0)}% usage remaining${resetInfo}`}
-
- );
+ let text = terse
+ ? `${percentage.toFixed(0)}%`
+ : `/stats ${percentage.toFixed(0)}% usage remaining${resetInfo}`;
+ if (lowercase) text = text.toLowerCase();
+
+ return {text};
};
diff --git a/packages/cli/src/ui/components/__snapshots__/Footer.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/Footer.test.tsx.snap
index 6a59ce6dfc..f5090725ef 100644
--- a/packages/cli/src/ui/components/__snapshots__/Footer.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/Footer.test.tsx.snap
@@ -8,7 +8,7 @@ exports[` > displays "Limit reached" message when remaining is 0 1`] =
exports[` > displays the usage indicator when usage is low 1`] = `
" workspace (/directory) sandbox /model /stats
- ~/project/foo/bar/and/some/more/directories/to/make/it/long no sandbox gemini-pro daily 15%
+ ~/project/foo/bar/and/some/more/directories/to/make/it/long no sandbox gemini-pro 15%
"
`;
@@ -40,6 +40,6 @@ exports[` > footer configuration filtering (golden snapshots) > render
exports[` > hides the usage indicator when usage is not near limit 1`] = `
" workspace (/directory) sandbox /model /stats
- ~/project/foo/bar/and/some/more/directories/to/make/it/long no sandbox gemini-pro daily 85%
+ ~/project/foo/bar/and/some/more/directories/to/make/it/long no sandbox gemini-pro 85%
"
`;
diff --git a/packages/cli/src/ui/components/__snapshots__/FooterConfigDialog.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/FooterConfigDialog.test.tsx.snap
index a1bb87f9db..7786aa338b 100644
--- a/packages/cli/src/ui/components/__snapshots__/FooterConfigDialog.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/FooterConfigDialog.test.tsx.snap
@@ -26,7 +26,7 @@ exports[` > renders correctly with default settings 1`] =
│ ┌────────────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Preview: │ │
│ │ workspace (/directory) branch sandbox /model /stats │ │
-│ │ ~/project/path main docker gemini-2.5-pro daily 97% │ │
+│ │ ~/project/path main docker gemini-2.5-pro 97% │ │
│ └────────────────────────────────────────────────────────────────────────────────────────────┘ │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯