From 01768d7759b81a0f1483c751206f6afcae6fc505 Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Fri, 30 May 2025 22:18:01 +0000 Subject: feat: add --show_memory_usage flag to display memory usage in status bar (#606) --- packages/cli/src/ui/App.tsx | 3 ++ packages/cli/src/ui/components/Footer.tsx | 5 +++ .../cli/src/ui/components/MemoryUsageDisplay.tsx | 40 ++++++++++++++++++++++ .../cli/src/ui/hooks/slashCommandProcessor.test.ts | 35 +++++++++++++++++-- packages/cli/src/ui/hooks/slashCommandProcessor.ts | 4 +++ packages/cli/src/ui/utils/formatters.ts | 16 +++++++++ 6 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/ui/components/MemoryUsageDisplay.tsx create mode 100644 packages/cli/src/ui/utils/formatters.ts (limited to 'packages/cli/src/ui') diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index dcd4d490..7b1eb2cb 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -442,6 +442,9 @@ export const App = ({ corgiMode={corgiMode} errorCount={errorCount} showErrorDetails={showErrorDetails} + showMemoryUsage={ + config.getDebugMode() || config.getShowMemoryUsage() + } /> diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx index 04a2f96f..22615779 100644 --- a/packages/cli/src/ui/components/Footer.tsx +++ b/packages/cli/src/ui/components/Footer.tsx @@ -9,6 +9,8 @@ import { Box, Text } from 'ink'; import { Colors } from '../colors.js'; import { shortenPath, tildeifyPath } from '@gemini-code/server'; import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js'; +import process from 'node:process'; +import { MemoryUsageDisplay } from './MemoryUsageDisplay.js'; interface FooterProps { model: string; @@ -20,6 +22,7 @@ interface FooterProps { corgiMode: boolean; errorCount: number; showErrorDetails: boolean; + showMemoryUsage?: boolean; } export const Footer: React.FC = ({ @@ -31,6 +34,7 @@ export const Footer: React.FC = ({ corgiMode, errorCount, showErrorDetails, + showMemoryUsage, }) => ( @@ -86,6 +90,7 @@ export const Footer: React.FC = ({ )} + {showMemoryUsage && } ); diff --git a/packages/cli/src/ui/components/MemoryUsageDisplay.tsx b/packages/cli/src/ui/components/MemoryUsageDisplay.tsx new file mode 100644 index 00000000..5d9a7c49 --- /dev/null +++ b/packages/cli/src/ui/components/MemoryUsageDisplay.tsx @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { Box, Text } from 'ink'; +import { Colors } from '../colors.js'; +import process from 'node:process'; +import { formatMemoryUsage } from '../utils/formatters.js'; + +export const MemoryUsageDisplay: React.FC = () => { + const [memoryUsage, setMemoryUsage] = useState(''); + const [memoryUsageColor, setMemoryUsageColor] = useState( + Colors.SubtleComment, + ); + + useEffect(() => { + const updateMemory = () => { + const usage = process.memoryUsage().rss; + setMemoryUsage(formatMemoryUsage(usage)); + setMemoryUsageColor( + usage >= 2 * 1024 * 1024 * 1024 + ? Colors.AccentRed + : Colors.SubtleComment, + ); + }; + const intervalId = setInterval(updateMemory, 2000); + updateMemory(); // Initial update + return () => clearInterval(intervalId); + }, []); + + return ( + + | + {memoryUsage} + + ); +}; diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts index 1f049658..7696c40d 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts @@ -9,9 +9,37 @@ const { mockProcessExit } = vi.hoisted(() => ({ })); vi.mock('node:process', () => ({ + default: { + exit: mockProcessExit, + cwd: vi.fn(() => '/mock/cwd'), + get env() { + return process.env; + }, // Use a getter to ensure current process.env is used + platform: 'test-platform', + version: 'test-node-version', + memoryUsage: vi.fn(() => ({ + rss: 12345678, + heapTotal: 23456789, + heapUsed: 10234567, + external: 1234567, + arrayBuffers: 123456, + })), + }, + // Provide top-level exports as well for compatibility exit: mockProcessExit, cwd: vi.fn(() => '/mock/cwd'), - env: { ...process.env }, + get env() { + return process.env; + }, // Use a getter here too + platform: 'test-platform', + version: 'test-node-version', + memoryUsage: vi.fn(() => ({ + rss: 12345678, + heapTotal: 23456789, + heapUsed: 10234567, + external: 1234567, + arrayBuffers: 123456, + })), })); vi.mock('node:fs/promises', () => ({ @@ -227,7 +255,7 @@ describe('useSlashCommandProcessor', () => { seatbeltProfileVar?: string, ) => { const cliVersion = 'test-version'; - const osVersion = `${process.platform} ${process.version}`; + const osVersion = 'test-platform test-node-version'; let sandboxEnvStr = 'no sandbox'; if (sandboxEnvVar && sandboxEnvVar !== 'sandbox-exec') { sandboxEnvStr = sandboxEnvVar.replace(/^gemini-(?:code-)?/, ''); @@ -235,6 +263,8 @@ describe('useSlashCommandProcessor', () => { sandboxEnvStr = `sandbox-exec (${seatbeltProfileVar || 'unknown'})`; } const modelVersion = 'test-model'; + // Use the mocked memoryUsage value + const memoryUsage = '11.8 MB'; const diagnosticInfo = ` ## Describe the bug @@ -249,6 +279,7 @@ Add any other context about the problem here. * **Operating System:** ${osVersion} * **Sandbox Environment:** ${sandboxEnvStr} * **Model Version:** ${modelVersion} +* **Memory Usage:** ${memoryUsage} `; let url = 'https://github.com/google-gemini/gemini-cli/issues/new?template=bug_report.md'; diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts index 5ec07c91..8f294380 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -7,11 +7,13 @@ import { useCallback, useMemo } from 'react'; import { type PartListUnion } from '@google/genai'; import open from 'open'; +import process from 'node:process'; import { UseHistoryManagerReturn } from './useHistoryManager.js'; import { Config } from '@gemini-code/server'; import { Message, MessageType, HistoryItemWithoutId } from '../types.js'; import { createShowMemoryAction } from './useShowMemoryCommand.js'; import { GIT_COMMIT_INFO } from '../../generated/git-commit.js'; +import { formatMemoryUsage } from '../utils/formatters.js'; export interface SlashCommandActionReturn { shouldScheduleTool?: boolean; @@ -206,6 +208,7 @@ export const useSlashCommandProcessor = ( sandboxEnv = `sandbox-exec (${process.env.SEATBELT_PROFILE || 'unknown'})`; } const modelVersion = config?.getModel() || 'Unknown'; + const memoryUsage = formatMemoryUsage(process.memoryUsage().rss); const diagnosticInfo = ` ## Describe the bug @@ -220,6 +223,7 @@ Add any other context about the problem here. * **Operating System:** ${osVersion} * **Sandbox Environment:** ${sandboxEnv} * **Model Version:** ${modelVersion} +* **Memory Usage:** ${memoryUsage} `; let bugReportUrl = diff --git a/packages/cli/src/ui/utils/formatters.ts b/packages/cli/src/ui/utils/formatters.ts new file mode 100644 index 00000000..ab02160e --- /dev/null +++ b/packages/cli/src/ui/utils/formatters.ts @@ -0,0 +1,16 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export const formatMemoryUsage = (bytes: number): string => { + const gb = bytes / (1024 * 1024 * 1024); + if (bytes < 1024 * 1024) { + return `${(bytes / 1024).toFixed(1)} KB`; + } + if (bytes < 1024 * 1024 * 1024) { + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; + } + return `${gb.toFixed(2)} GB`; +}; -- cgit v1.2.3