Update contextFileName to support an optional list of strings (#1001)
This commit is contained in:
parent
34e0d9c0b6
commit
2a1ad1f5d9
|
@ -38,9 +38,9 @@ When you create a `.gemini/settings.json` file for project-specific settings, or
|
||||||
|
|
||||||
### Available Settings in `settings.json`:
|
### Available Settings in `settings.json`:
|
||||||
|
|
||||||
- **`contextFileName`** (string, optional):
|
- **`contextFileName`** (string or array of strings, optional):
|
||||||
|
|
||||||
- **Description:** Specifies the filename for context files (e.g., `GEMINI.md`, `AGENTS.md`).
|
- **Description:** Specifies the filename for context files (e.g., `GEMINI.md`, `AGENTS.md`). May be a single filename or a list of accepted filenames.
|
||||||
- **Default:** `GEMINI.md`
|
- **Default:** `GEMINI.md`
|
||||||
- **Example:** `"contextFileName": "AGENTS.md"`
|
- **Example:** `"contextFileName": "AGENTS.md"`
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ export interface ExtensionConfig {
|
||||||
name: string;
|
name: string;
|
||||||
version: string;
|
version: string;
|
||||||
mcpServers?: Record<string, MCPServerConfig>;
|
mcpServers?: Record<string, MCPServerConfig>;
|
||||||
contextFileName?: string;
|
contextFileName?: string | string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadExtensions(workspaceDir: string): ExtensionConfig[] {
|
export function loadExtensions(workspaceDir: string): ExtensionConfig[] {
|
||||||
|
@ -76,12 +76,15 @@ function loadExtensionsFromDir(dir: string): ExtensionConfig[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extensionConfig.contextFileName) {
|
if (extensionConfig.contextFileName) {
|
||||||
const contextFilePath = path.join(
|
const contextFileNames = Array.isArray(extensionConfig.contextFileName)
|
||||||
extensionDir,
|
? extensionConfig.contextFileName
|
||||||
extensionConfig.contextFileName,
|
: [extensionConfig.contextFileName];
|
||||||
);
|
const resolvedPaths = contextFileNames
|
||||||
if (fs.existsSync(contextFilePath)) {
|
.map((fileName) => path.join(extensionDir, fileName))
|
||||||
extensionConfig.contextFileName = contextFilePath;
|
.filter((filePath) => fs.existsSync(filePath));
|
||||||
|
if (resolvedPaths.length > 0) {
|
||||||
|
extensionConfig.contextFileName =
|
||||||
|
resolvedPaths.length === 1 ? resolvedPaths[0] : resolvedPaths;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const contextFilePath = path.join(extensionDir, 'gemini.md');
|
const contextFilePath = path.join(extensionDir, 'gemini.md');
|
||||||
|
|
|
@ -35,7 +35,7 @@ export interface Settings {
|
||||||
mcpServerCommand?: string;
|
mcpServerCommand?: string;
|
||||||
mcpServers?: Record<string, MCPServerConfig>;
|
mcpServers?: Record<string, MCPServerConfig>;
|
||||||
showMemoryUsage?: boolean;
|
showMemoryUsage?: boolean;
|
||||||
contextFileName?: string;
|
contextFileName?: string | string[];
|
||||||
accessibility?: AccessibilitySettings;
|
accessibility?: AccessibilitySettings;
|
||||||
telemetry?: boolean;
|
telemetry?: boolean;
|
||||||
preferredEditor?: string;
|
preferredEditor?: string;
|
||||||
|
|
|
@ -64,6 +64,7 @@ interface MockServerConfig {
|
||||||
getShowMemoryUsage: Mock<() => boolean>;
|
getShowMemoryUsage: Mock<() => boolean>;
|
||||||
getAccessibility: Mock<() => AccessibilitySettings>;
|
getAccessibility: Mock<() => AccessibilitySettings>;
|
||||||
getProjectRoot: Mock<() => string | undefined>;
|
getProjectRoot: Mock<() => string | undefined>;
|
||||||
|
getAllGeminiMdFilenames: Mock<() => string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock @gemini-cli/core and its Config class
|
// Mock @gemini-cli/core and its Config class
|
||||||
|
@ -124,12 +125,14 @@ vi.mock('@gemini-cli/core', async (importOriginal) => {
|
||||||
getProjectRoot: vi.fn(() => opts.projectRoot),
|
getProjectRoot: vi.fn(() => opts.projectRoot),
|
||||||
getGeminiClient: vi.fn(() => ({})),
|
getGeminiClient: vi.fn(() => ({})),
|
||||||
getCheckpointEnabled: vi.fn(() => opts.checkpoint ?? true),
|
getCheckpointEnabled: vi.fn(() => opts.checkpoint ?? true),
|
||||||
|
getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
...actualCore,
|
...actualCore,
|
||||||
Config: ConfigClassMock,
|
Config: ConfigClassMock,
|
||||||
MCPServerConfig: actualCore.MCPServerConfig,
|
MCPServerConfig: actualCore.MCPServerConfig,
|
||||||
|
getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -269,6 +272,26 @@ describe('App UI', () => {
|
||||||
expect(lastFrame()).toContain('Using 1 AGENTS.MD file');
|
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(
|
||||||
|
<App
|
||||||
|
config={mockConfig as unknown as ServerConfig}
|
||||||
|
settings={mockSettings}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
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 () => {
|
it('should display custom contextFileName with plural when set and count is > 1', async () => {
|
||||||
mockSettings = createMockSettings({
|
mockSettings = createMockSettings({
|
||||||
contextFileName: 'MY_NOTES.TXT',
|
contextFileName: 'MY_NOTES.TXT',
|
||||||
|
|
|
@ -45,7 +45,7 @@ import process from 'node:process';
|
||||||
import {
|
import {
|
||||||
getErrorMessage,
|
getErrorMessage,
|
||||||
type Config,
|
type Config,
|
||||||
getCurrentGeminiMdFilename,
|
getAllGeminiMdFilenames,
|
||||||
ApprovalMode,
|
ApprovalMode,
|
||||||
isEditorAvailable,
|
isEditorAvailable,
|
||||||
EditorType,
|
EditorType,
|
||||||
|
@ -373,6 +373,14 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
||||||
|
|
||||||
const branchName = useGitBranchName(config.getTargetDir());
|
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) {
|
if (quittingMessages) {
|
||||||
return (
|
return (
|
||||||
<Box flexDirection="column" marginBottom={1}>
|
<Box flexDirection="column" marginBottom={1}>
|
||||||
|
@ -509,10 +517,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
||||||
) : (
|
) : (
|
||||||
<ContextSummaryDisplay
|
<ContextSummaryDisplay
|
||||||
geminiMdFileCount={geminiMdFileCount}
|
geminiMdFileCount={geminiMdFileCount}
|
||||||
contextFileName={
|
contextFileNames={contextFileNames}
|
||||||
settings.merged.contextFileName ||
|
|
||||||
getCurrentGeminiMdFilename()
|
|
||||||
}
|
|
||||||
mcpServers={config.getMcpServers()}
|
mcpServers={config.getMcpServers()}
|
||||||
showToolDescriptions={showToolDescriptions}
|
showToolDescriptions={showToolDescriptions}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,14 +11,14 @@ import { type MCPServerConfig } from '@gemini-cli/core';
|
||||||
|
|
||||||
interface ContextSummaryDisplayProps {
|
interface ContextSummaryDisplayProps {
|
||||||
geminiMdFileCount: number;
|
geminiMdFileCount: number;
|
||||||
contextFileName: string;
|
contextFileNames: string[];
|
||||||
mcpServers?: Record<string, MCPServerConfig>;
|
mcpServers?: Record<string, MCPServerConfig>;
|
||||||
showToolDescriptions?: boolean;
|
showToolDescriptions?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
|
export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
|
||||||
geminiMdFileCount,
|
geminiMdFileCount,
|
||||||
contextFileName,
|
contextFileNames,
|
||||||
mcpServers,
|
mcpServers,
|
||||||
showToolDescriptions,
|
showToolDescriptions,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -30,7 +30,9 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
|
||||||
|
|
||||||
const geminiMdText =
|
const geminiMdText =
|
||||||
geminiMdFileCount > 0
|
geminiMdFileCount > 0
|
||||||
? `${geminiMdFileCount} ${contextFileName} file${geminiMdFileCount > 1 ? 's' : ''}`
|
? `${geminiMdFileCount} ${contextFileNames[0]} file${
|
||||||
|
geminiMdFileCount > 1 ? 's' : ''
|
||||||
|
}`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const mcpText =
|
const mcpText =
|
||||||
|
|
|
@ -74,7 +74,7 @@ export interface ConfigParameters {
|
||||||
geminiMdFileCount?: number;
|
geminiMdFileCount?: number;
|
||||||
approvalMode?: ApprovalMode;
|
approvalMode?: ApprovalMode;
|
||||||
showMemoryUsage?: boolean;
|
showMemoryUsage?: boolean;
|
||||||
contextFileName?: string;
|
contextFileName?: string | string[];
|
||||||
geminiIgnorePatterns?: string[];
|
geminiIgnorePatterns?: string[];
|
||||||
accessibility?: AccessibilitySettings;
|
accessibility?: AccessibilitySettings;
|
||||||
telemetry?: boolean;
|
telemetry?: boolean;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
MemoryTool,
|
MemoryTool,
|
||||||
setGeminiMdFilename,
|
setGeminiMdFilename,
|
||||||
getCurrentGeminiMdFilename,
|
getCurrentGeminiMdFilename,
|
||||||
|
getAllGeminiMdFilenames,
|
||||||
DEFAULT_CONTEXT_FILENAME,
|
DEFAULT_CONTEXT_FILENAME,
|
||||||
} from './memoryTool.js';
|
} from './memoryTool.js';
|
||||||
import * as fs from 'fs/promises';
|
import * as fs from 'fs/promises';
|
||||||
|
@ -74,6 +75,13 @@ describe('MemoryTool', () => {
|
||||||
setGeminiMdFilename('');
|
setGeminiMdFilename('');
|
||||||
expect(getCurrentGeminiMdFilename()).toBe(initialName);
|
expect(getCurrentGeminiMdFilename()).toBe(initialName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle an array of filenames', () => {
|
||||||
|
const newNames = ['CUSTOM_CONTEXT.md', 'ANOTHER_CONTEXT.md'];
|
||||||
|
setGeminiMdFilename(newNames);
|
||||||
|
expect(getCurrentGeminiMdFilename()).toBe('CUSTOM_CONTEXT.md');
|
||||||
|
expect(getAllGeminiMdFilenames()).toEqual(newNames);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('performAddMemoryEntry (static method)', () => {
|
describe('performAddMemoryEntry (static method)', () => {
|
||||||
|
|
|
@ -51,18 +51,32 @@ export const MEMORY_SECTION_HEADER = '## Gemini Added Memories';
|
||||||
|
|
||||||
// This variable will hold the currently configured filename for GEMINI.md context files.
|
// This variable will hold the currently configured filename for GEMINI.md context files.
|
||||||
// It defaults to DEFAULT_CONTEXT_FILENAME but can be overridden by setGeminiMdFilename.
|
// It defaults to DEFAULT_CONTEXT_FILENAME but can be overridden by setGeminiMdFilename.
|
||||||
let currentGeminiMdFilename = DEFAULT_CONTEXT_FILENAME;
|
let currentGeminiMdFilename: string | string[] = DEFAULT_CONTEXT_FILENAME;
|
||||||
|
|
||||||
export function setGeminiMdFilename(newFilename: string): void {
|
export function setGeminiMdFilename(newFilename: string | string[]): void {
|
||||||
if (newFilename && newFilename.trim() !== '') {
|
if (Array.isArray(newFilename)) {
|
||||||
|
if (newFilename.length > 0) {
|
||||||
|
currentGeminiMdFilename = newFilename.map((name) => name.trim());
|
||||||
|
}
|
||||||
|
} else if (newFilename && newFilename.trim() !== '') {
|
||||||
currentGeminiMdFilename = newFilename.trim();
|
currentGeminiMdFilename = newFilename.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentGeminiMdFilename(): string {
|
export function getCurrentGeminiMdFilename(): string {
|
||||||
|
if (Array.isArray(currentGeminiMdFilename)) {
|
||||||
|
return currentGeminiMdFilename[0];
|
||||||
|
}
|
||||||
return currentGeminiMdFilename;
|
return currentGeminiMdFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAllGeminiMdFilenames(): string[] {
|
||||||
|
if (Array.isArray(currentGeminiMdFilename)) {
|
||||||
|
return currentGeminiMdFilename;
|
||||||
|
}
|
||||||
|
return [currentGeminiMdFilename];
|
||||||
|
}
|
||||||
|
|
||||||
interface SaveMemoryParams {
|
interface SaveMemoryParams {
|
||||||
fact: string;
|
fact: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { homedir } from 'os';
|
||||||
import { bfsFileSearch } from './bfsFileSearch.js';
|
import { bfsFileSearch } from './bfsFileSearch.js';
|
||||||
import {
|
import {
|
||||||
GEMINI_CONFIG_DIR,
|
GEMINI_CONFIG_DIR,
|
||||||
getCurrentGeminiMdFilename,
|
getAllGeminiMdFilenames,
|
||||||
} from '../tools/memoryTool.js';
|
} from '../tools/memoryTool.js';
|
||||||
|
|
||||||
// Simple console logger, similar to the one previously in CLI's config.ts
|
// Simple console logger, similar to the one previously in CLI's config.ts
|
||||||
|
@ -83,131 +83,135 @@ async function getGeminiMdFilePathsInternal(
|
||||||
debugMode: boolean,
|
debugMode: boolean,
|
||||||
extensionContextFilePaths: string[] = [],
|
extensionContextFilePaths: string[] = [],
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const resolvedCwd = path.resolve(currentWorkingDirectory);
|
const allPaths = new Set<string>();
|
||||||
const resolvedHome = path.resolve(userHomePath);
|
const geminiMdFilenames = getAllGeminiMdFilenames();
|
||||||
const globalMemoryPath = path.join(
|
|
||||||
resolvedHome,
|
|
||||||
GEMINI_CONFIG_DIR,
|
|
||||||
getCurrentGeminiMdFilename(),
|
|
||||||
);
|
|
||||||
const paths: string[] = [];
|
|
||||||
|
|
||||||
if (debugMode)
|
for (const geminiMdFilename of geminiMdFilenames) {
|
||||||
logger.debug(
|
const resolvedCwd = path.resolve(currentWorkingDirectory);
|
||||||
`Searching for ${getCurrentGeminiMdFilename()} starting from CWD: ${resolvedCwd}`,
|
const resolvedHome = path.resolve(userHomePath);
|
||||||
|
const globalMemoryPath = path.join(
|
||||||
|
resolvedHome,
|
||||||
|
GEMINI_CONFIG_DIR,
|
||||||
|
geminiMdFilename,
|
||||||
);
|
);
|
||||||
if (debugMode) logger.debug(`User home directory: ${resolvedHome}`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.access(globalMemoryPath, fsSync.constants.R_OK);
|
|
||||||
paths.push(globalMemoryPath);
|
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Found readable global ${getCurrentGeminiMdFilename()}: ${globalMemoryPath}`,
|
`Searching for ${geminiMdFilename} starting from CWD: ${resolvedCwd}`,
|
||||||
);
|
);
|
||||||
} catch {
|
if (debugMode) logger.debug(`User home directory: ${resolvedHome}`);
|
||||||
if (debugMode)
|
|
||||||
logger.debug(
|
|
||||||
`Global ${getCurrentGeminiMdFilename()} not found or not readable: ${globalMemoryPath}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const projectRoot = await findProjectRoot(resolvedCwd);
|
try {
|
||||||
if (debugMode)
|
await fs.access(globalMemoryPath, fsSync.constants.R_OK);
|
||||||
logger.debug(`Determined project root: ${projectRoot ?? 'None'}`);
|
allPaths.add(globalMemoryPath);
|
||||||
|
if (debugMode)
|
||||||
const upwardPaths: string[] = [];
|
logger.debug(
|
||||||
let currentDir = resolvedCwd;
|
`Found readable global ${geminiMdFilename}: ${globalMemoryPath}`,
|
||||||
// Determine the directory that signifies the top of the project or user-specific space.
|
);
|
||||||
const ultimateStopDir = projectRoot
|
} catch {
|
||||||
? path.dirname(projectRoot)
|
if (debugMode)
|
||||||
: path.dirname(resolvedHome);
|
logger.debug(
|
||||||
|
`Global ${geminiMdFilename} not found or not readable: ${globalMemoryPath}`,
|
||||||
while (currentDir && currentDir !== path.dirname(currentDir)) {
|
);
|
||||||
// Loop until filesystem root or currentDir is empty
|
|
||||||
if (debugMode) {
|
|
||||||
logger.debug(
|
|
||||||
`Checking for ${getCurrentGeminiMdFilename()} in (upward scan): ${currentDir}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the global .gemini directory itself during upward scan from CWD,
|
const projectRoot = await findProjectRoot(resolvedCwd);
|
||||||
// as global is handled separately and explicitly first.
|
if (debugMode)
|
||||||
if (currentDir === path.join(resolvedHome, GEMINI_CONFIG_DIR)) {
|
logger.debug(`Determined project root: ${projectRoot ?? 'None'}`);
|
||||||
|
|
||||||
|
const upwardPaths: string[] = [];
|
||||||
|
let currentDir = resolvedCwd;
|
||||||
|
// Determine the directory that signifies the top of the project or user-specific space.
|
||||||
|
const ultimateStopDir = projectRoot
|
||||||
|
? path.dirname(projectRoot)
|
||||||
|
: path.dirname(resolvedHome);
|
||||||
|
|
||||||
|
while (currentDir && currentDir !== path.dirname(currentDir)) {
|
||||||
|
// Loop until filesystem root or currentDir is empty
|
||||||
if (debugMode) {
|
if (debugMode) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Upward scan reached global config dir path, stopping upward search here: ${currentDir}`,
|
`Checking for ${geminiMdFilename} in (upward scan): ${currentDir}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const potentialPath = path.join(currentDir, getCurrentGeminiMdFilename());
|
// Skip the global .gemini directory itself during upward scan from CWD,
|
||||||
try {
|
// as global is handled separately and explicitly first.
|
||||||
await fs.access(potentialPath, fsSync.constants.R_OK);
|
if (currentDir === path.join(resolvedHome, GEMINI_CONFIG_DIR)) {
|
||||||
// Add to upwardPaths only if it's not the already added globalMemoryPath
|
|
||||||
if (potentialPath !== globalMemoryPath) {
|
|
||||||
upwardPaths.unshift(potentialPath);
|
|
||||||
if (debugMode) {
|
if (debugMode) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Found readable upward ${getCurrentGeminiMdFilename()}: ${potentialPath}`,
|
`Upward scan reached global config dir path, stopping upward search here: ${currentDir}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const potentialPath = path.join(currentDir, geminiMdFilename);
|
||||||
|
try {
|
||||||
|
await fs.access(potentialPath, fsSync.constants.R_OK);
|
||||||
|
// Add to upwardPaths only if it's not the already added globalMemoryPath
|
||||||
|
if (potentialPath !== globalMemoryPath) {
|
||||||
|
upwardPaths.unshift(potentialPath);
|
||||||
|
if (debugMode) {
|
||||||
|
logger.debug(
|
||||||
|
`Found readable upward ${geminiMdFilename}: ${potentialPath}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
if (debugMode) {
|
||||||
|
logger.debug(
|
||||||
|
`Upward ${geminiMdFilename} not found or not readable in: ${currentDir}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
if (debugMode) {
|
// Stop condition: if currentDir is the ultimateStopDir, break after this iteration.
|
||||||
logger.debug(
|
if (currentDir === ultimateStopDir) {
|
||||||
`Upward ${getCurrentGeminiMdFilename()} not found or not readable in: ${currentDir}`,
|
if (debugMode)
|
||||||
);
|
logger.debug(
|
||||||
|
`Reached ultimate stop directory for upward scan: ${currentDir}`,
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentDir = path.dirname(currentDir);
|
||||||
}
|
}
|
||||||
|
upwardPaths.forEach((p) => allPaths.add(p));
|
||||||
|
|
||||||
// Stop condition: if currentDir is the ultimateStopDir, break after this iteration.
|
const downwardPaths = await bfsFileSearch(resolvedCwd, {
|
||||||
if (currentDir === ultimateStopDir) {
|
fileName: geminiMdFilename,
|
||||||
if (debugMode)
|
maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY,
|
||||||
logger.debug(
|
debug: debugMode,
|
||||||
`Reached ultimate stop directory for upward scan: ${currentDir}`,
|
respectGitIgnore: true,
|
||||||
);
|
projectRoot: projectRoot || resolvedCwd,
|
||||||
break;
|
});
|
||||||
}
|
downwardPaths.sort(); // Sort for consistent ordering, though hierarchy might be more complex
|
||||||
|
if (debugMode && downwardPaths.length > 0)
|
||||||
currentDir = path.dirname(currentDir);
|
logger.debug(
|
||||||
}
|
`Found downward ${geminiMdFilename} files (sorted): ${JSON.stringify(
|
||||||
paths.push(...upwardPaths);
|
downwardPaths,
|
||||||
|
)}`,
|
||||||
const downwardPaths = await bfsFileSearch(resolvedCwd, {
|
);
|
||||||
fileName: getCurrentGeminiMdFilename(),
|
// Add downward paths only if they haven't been included already (e.g. from upward scan)
|
||||||
maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY,
|
for (const dPath of downwardPaths) {
|
||||||
debug: debugMode,
|
allPaths.add(dPath);
|
||||||
respectGitIgnore: true,
|
|
||||||
projectRoot: projectRoot || resolvedCwd,
|
|
||||||
});
|
|
||||||
downwardPaths.sort(); // Sort for consistent ordering, though hierarchy might be more complex
|
|
||||||
if (debugMode && downwardPaths.length > 0)
|
|
||||||
logger.debug(
|
|
||||||
`Found downward ${getCurrentGeminiMdFilename()} files (sorted): ${JSON.stringify(
|
|
||||||
downwardPaths,
|
|
||||||
)}`,
|
|
||||||
);
|
|
||||||
// Add downward paths only if they haven't been included already (e.g. from upward scan)
|
|
||||||
for (const dPath of downwardPaths) {
|
|
||||||
if (!paths.includes(dPath)) {
|
|
||||||
paths.push(dPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add extension context file paths
|
// Add extension context file paths
|
||||||
for (const extensionPath of extensionContextFilePaths) {
|
for (const extensionPath of extensionContextFilePaths) {
|
||||||
if (!paths.includes(extensionPath)) {
|
allPaths.add(extensionPath);
|
||||||
paths.push(extensionPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const finalPaths = Array.from(allPaths);
|
||||||
|
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Final ordered ${getCurrentGeminiMdFilename()} paths to read: ${JSON.stringify(paths)}`,
|
`Final ordered ${getAllGeminiMdFilenames()} paths to read: ${JSON.stringify(
|
||||||
|
finalPaths,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
return paths;
|
return finalPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readGeminiMdFiles(
|
async function readGeminiMdFiles(
|
||||||
|
@ -228,7 +232,7 @@ async function readGeminiMdFiles(
|
||||||
if (!isTestEnv) {
|
if (!isTestEnv) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Warning: Could not read ${getCurrentGeminiMdFilename()} file at ${filePath}. Error: ${message}`,
|
`Warning: Could not read ${getAllGeminiMdFilenames()} file at ${filePath}. Error: ${message}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
results.push({ filePath, content: null }); // Still include it with null content
|
results.push({ filePath, content: null }); // Still include it with null content
|
||||||
|
|
Loading…
Reference in New Issue