fix(cli): change image paste location to global temp directory (#17396) (#17396)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
Dev Randalpura
2026-01-23 14:45:24 -08:00
committed by GitHub
parent da1664c7a0
commit daccf4d6d1
3 changed files with 35 additions and 11 deletions

View File

@@ -43,6 +43,9 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
debug: vi.fn(),
warn: vi.fn(),
},
Storage: class {
getProjectTempDir = vi.fn(() => '/tmp/global');
},
};
});
@@ -169,7 +172,7 @@ describe('clipboardUtils', () => {
describe('saveClipboardImage (Linux)', () => {
const mockTargetDir = '/tmp/target';
const mockTempDir = path.join(mockTargetDir, '.gemini-clipboard');
const mockTempDir = path.join('/tmp/global', 'images');
beforeEach(() => {
setPlatform('linux');
@@ -240,6 +243,7 @@ describe('clipboardUtils', () => {
const result = await promise;
expect(result).toContain(mockTempDir);
expect(result).toMatch(/clipboard-\d+\.png$/);
expect(spawn).toHaveBeenCalledWith('wl-paste', expect.any(Array));
expect(fs.mkdir).toHaveBeenCalledWith(mockTempDir, { recursive: true });
@@ -310,15 +314,18 @@ describe('clipboardUtils', () => {
// Stateless functions continue to use static imports
describe('cleanupOldClipboardImages', () => {
const mockTargetDir = '/tmp/target';
it('should not throw errors', async () => {
// Should handle missing directories gracefully
await expect(
cleanupOldClipboardImages('/path/that/does/not/exist'),
cleanupOldClipboardImages(mockTargetDir),
).resolves.not.toThrow();
});
it('should complete without errors on valid directory', async () => {
await expect(cleanupOldClipboardImages('.')).resolves.not.toThrow();
await expect(
cleanupOldClipboardImages(mockTargetDir),
).resolves.not.toThrow();
});
});

View File

@@ -13,6 +13,7 @@ import {
spawnAsync,
unescapePath,
escapePath,
Storage,
} from '@google/gemini-cli-core';
/**
@@ -244,19 +245,33 @@ const saveFileWithXclip = async (tempFilePath: string) => {
return false;
};
/**
* Gets the directory where clipboard images should be stored for a specific project.
*
* This uses the global temporary directory but creates a project-specific subdirectory
* based on the hash of the project path (via `Storage.getProjectTempDir()`).
* This prevents path conflicts between different projects while keeping the images
* outside of the user's project directory.
*
* @param targetDir The root directory of the current project.
* @returns The absolute path to the images directory.
*/
function getProjectClipboardImagesDir(targetDir: string): string {
const storage = new Storage(targetDir);
const baseDir = storage.getProjectTempDir();
return path.join(baseDir, 'images');
}
/**
* Saves the image from clipboard to a temporary file (macOS, Windows, and Linux)
* @param targetDir The target directory to create temp files within
* @returns The path to the saved image file, or null if no image or error
*/
export async function saveClipboardImage(
targetDir?: string,
targetDir: string,
): Promise<string | null> {
try {
// Create a temporary directory for clipboard images within the target directory
// This avoids security restrictions on paths outside the target directory
const baseDir = targetDir || process.cwd();
const tempDir = path.join(baseDir, '.gemini-clipboard');
const tempDir = getProjectClipboardImagesDir(targetDir);
await fs.mkdir(tempDir, { recursive: true });
// Generate a unique filename with timestamp
@@ -378,11 +393,10 @@ export async function saveClipboardImage(
* @param targetDir The target directory where temp files are stored
*/
export async function cleanupOldClipboardImages(
targetDir?: string,
targetDir: string,
): Promise<void> {
try {
const baseDir = targetDir || process.cwd();
const tempDir = path.join(baseDir, '.gemini-clipboard');
const tempDir = getProjectClipboardImagesDir(targetDir);
const files = await fs.readdir(tempDir);
const oneHourAgo = Date.now() - 60 * 60 * 1000;

View File

@@ -16,6 +16,9 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
return {
...actual,
spawnAsync: vi.fn(),
Storage: class {
getProjectTempDir = vi.fn(() => "C:\\User's Files");
},
};
});