From 2a1ad1f5d961b9f9593a6016eea7dd398bdeed0b Mon Sep 17 00:00:00 2001 From: Billy Biggs Date: Fri, 13 Jun 2025 09:19:08 -0700 Subject: Update contextFileName to support an optional list of strings (#1001) --- packages/cli/src/config/extension.ts | 17 +++++++++------- packages/cli/src/config/settings.ts | 2 +- packages/cli/src/ui/App.test.tsx | 23 ++++++++++++++++++++++ packages/cli/src/ui/App.tsx | 15 +++++++++----- .../src/ui/components/ContextSummaryDisplay.tsx | 8 +++++--- 5 files changed, 49 insertions(+), 16 deletions(-) (limited to 'packages/cli/src') diff --git a/packages/cli/src/config/extension.ts b/packages/cli/src/config/extension.ts index 9dd33e1b..685c0b74 100644 --- a/packages/cli/src/config/extension.ts +++ b/packages/cli/src/config/extension.ts @@ -16,7 +16,7 @@ export interface ExtensionConfig { name: string; version: string; mcpServers?: Record; - contextFileName?: string; + contextFileName?: string | string[]; } export function loadExtensions(workspaceDir: string): ExtensionConfig[] { @@ -76,12 +76,15 @@ function loadExtensionsFromDir(dir: string): ExtensionConfig[] { } if (extensionConfig.contextFileName) { - const contextFilePath = path.join( - extensionDir, - extensionConfig.contextFileName, - ); - if (fs.existsSync(contextFilePath)) { - extensionConfig.contextFileName = contextFilePath; + const contextFileNames = Array.isArray(extensionConfig.contextFileName) + ? extensionConfig.contextFileName + : [extensionConfig.contextFileName]; + const resolvedPaths = contextFileNames + .map((fileName) => path.join(extensionDir, fileName)) + .filter((filePath) => fs.existsSync(filePath)); + if (resolvedPaths.length > 0) { + extensionConfig.contextFileName = + resolvedPaths.length === 1 ? resolvedPaths[0] : resolvedPaths; } } else { const contextFilePath = path.join(extensionDir, 'gemini.md'); diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index e00ebb79..25f9d79d 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -35,7 +35,7 @@ export interface Settings { mcpServerCommand?: string; mcpServers?: Record; showMemoryUsage?: boolean; - contextFileName?: string; + contextFileName?: string | string[]; accessibility?: AccessibilitySettings; telemetry?: boolean; preferredEditor?: string; diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx index b8959bfb..201d0698 100644 --- a/packages/cli/src/ui/App.test.tsx +++ b/packages/cli/src/ui/App.test.tsx @@ -64,6 +64,7 @@ interface MockServerConfig { getShowMemoryUsage: Mock<() => boolean>; getAccessibility: Mock<() => AccessibilitySettings>; getProjectRoot: Mock<() => string | undefined>; + getAllGeminiMdFilenames: Mock<() => string[]>; } // Mock @gemini-cli/core and its Config class @@ -124,12 +125,14 @@ vi.mock('@gemini-cli/core', async (importOriginal) => { getProjectRoot: vi.fn(() => opts.projectRoot), getGeminiClient: vi.fn(() => ({})), getCheckpointEnabled: vi.fn(() => opts.checkpoint ?? true), + getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']), }; }); return { ...actualCore, Config: ConfigClassMock, MCPServerConfig: actualCore.MCPServerConfig, + getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']), }; }); @@ -269,6 +272,26 @@ describe('App UI', () => { expect(lastFrame()).toContain('Using 1 AGENTS.MD file'); }); + it('should display the first custom contextFileName when an array is provided', async () => { + mockSettings = createMockSettings({ + contextFileName: ['AGENTS.MD', 'CONTEXT.MD'], + theme: 'Default', + }); + mockConfig.getGeminiMdFileCount.mockReturnValue(2); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); + expect(lastFrame()).toContain('Using 2 AGENTS.MD files'); + }); + it('should display custom contextFileName with plural when set and count is > 1', async () => { mockSettings = createMockSettings({ contextFileName: 'MY_NOTES.TXT', diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 2d37c42a..c7ed9a81 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -45,7 +45,7 @@ import process from 'node:process'; import { getErrorMessage, type Config, - getCurrentGeminiMdFilename, + getAllGeminiMdFilenames, ApprovalMode, isEditorAvailable, EditorType, @@ -373,6 +373,14 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const branchName = useGitBranchName(config.getTargetDir()); + const contextFileNames = useMemo(() => { + const fromSettings = settings.merged.contextFileName; + if (fromSettings) { + return Array.isArray(fromSettings) ? fromSettings : [fromSettings]; + } + return getAllGeminiMdFilenames(); + }, [settings.merged.contextFileName]); + if (quittingMessages) { return ( @@ -509,10 +517,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { ) : ( diff --git a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx index c4527066..904bf81f 100644 --- a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx +++ b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx @@ -11,14 +11,14 @@ import { type MCPServerConfig } from '@gemini-cli/core'; interface ContextSummaryDisplayProps { geminiMdFileCount: number; - contextFileName: string; + contextFileNames: string[]; mcpServers?: Record; showToolDescriptions?: boolean; } export const ContextSummaryDisplay: React.FC = ({ geminiMdFileCount, - contextFileName, + contextFileNames, mcpServers, showToolDescriptions, }) => { @@ -30,7 +30,9 @@ export const ContextSummaryDisplay: React.FC = ({ const geminiMdText = geminiMdFileCount > 0 - ? `${geminiMdFileCount} ${contextFileName} file${geminiMdFileCount > 1 ? 's' : ''}` + ? `${geminiMdFileCount} ${contextFileNames[0]} file${ + geminiMdFileCount > 1 ? 's' : '' + }` : ''; const mcpText = -- cgit v1.2.3