async function getGeminiMdFilePathsInternal()

in packages/core/src/utils/memoryDiscovery.ts [82:217]


async function getGeminiMdFilePathsInternal(
  currentWorkingDirectory: string,
  userHomePath: string,
  debugMode: boolean,
  fileService: FileDiscoveryService,
  extensionContextFilePaths: string[] = [],
): Promise<string[]> {
  const allPaths = new Set<string>();
  const geminiMdFilenames = getAllGeminiMdFilenames();

  for (const geminiMdFilename of geminiMdFilenames) {
    const resolvedCwd = path.resolve(currentWorkingDirectory);
    const resolvedHome = path.resolve(userHomePath);
    const globalMemoryPath = path.join(
      resolvedHome,
      GEMINI_CONFIG_DIR,
      geminiMdFilename,
    );

    if (debugMode)
      logger.debug(
        `Searching for ${geminiMdFilename} starting from CWD: ${resolvedCwd}`,
      );
    if (debugMode) logger.debug(`User home directory: ${resolvedHome}`);

    try {
      await fs.access(globalMemoryPath, fsSync.constants.R_OK);
      allPaths.add(globalMemoryPath);
      if (debugMode)
        logger.debug(
          `Found readable global ${geminiMdFilename}: ${globalMemoryPath}`,
        );
    } catch {
      if (debugMode)
        logger.debug(
          `Global ${geminiMdFilename} not found or not readable: ${globalMemoryPath}`,
        );
    }

    const projectRoot = await findProjectRoot(resolvedCwd);
    if (debugMode)
      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) {
        logger.debug(
          `Checking for ${geminiMdFilename} in (upward scan): ${currentDir}`,
        );
      }

      // Skip the global .gemini directory itself during upward scan from CWD,
      // as global is handled separately and explicitly first.
      if (currentDir === path.join(resolvedHome, GEMINI_CONFIG_DIR)) {
        if (debugMode) {
          logger.debug(
            `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}`,
          );
        }
      }

      // Stop condition: if currentDir is the ultimateStopDir, break after this iteration.
      if (currentDir === ultimateStopDir) {
        if (debugMode)
          logger.debug(
            `Reached ultimate stop directory for upward scan: ${currentDir}`,
          );
        break;
      }

      currentDir = path.dirname(currentDir);
    }
    upwardPaths.forEach((p) => allPaths.add(p));

    const downwardPaths = await bfsFileSearch(resolvedCwd, {
      fileName: geminiMdFilename,
      maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY,
      debug: debugMode,
      fileService,
    });
    downwardPaths.sort(); // Sort for consistent ordering, though hierarchy might be more complex
    if (debugMode && downwardPaths.length > 0)
      logger.debug(
        `Found downward ${geminiMdFilename} 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) {
      allPaths.add(dPath);
    }
  }

  // Add extension context file paths
  for (const extensionPath of extensionContextFilePaths) {
    allPaths.add(extensionPath);
  }

  const finalPaths = Array.from(allPaths);

  if (debugMode)
    logger.debug(
      `Final ordered ${getAllGeminiMdFilenames()} paths to read: ${JSON.stringify(
        finalPaths,
      )}`,
    );
  return finalPaths;
}