import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { logger } from './logger.js';
// Screenshot temporary folder management
export const TEMP_SCREENSHOTS_FOLDER = join(tmpdir(), 'mcp-screenshots');
let screenshotCounter = 0;
/**
* Initialize temp folder for screenshots
*/
export async function initTempFolder(): Promise<void> {
try {
await fs.mkdir(TEMP_SCREENSHOTS_FOLDER, { recursive: true });
logger.info(`Screenshot temp folder initialized: ${TEMP_SCREENSHOTS_FOLDER}`);
} catch (error) {
logger.error('Failed to initialize temp folder', error as Error);
}
}
/**
* Generate timestamp-based filename for screenshots
*/
export function generateScreenshotFilename(prefix: string = 'screenshot'): string {
const now = new Date();
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, -5); // Remove milliseconds and 'Z'
screenshotCounter++;
return `${prefix}-${timestamp}-${screenshotCounter.toString().padStart(3, '0')}.png`;
}
/**
* Clean up old screenshots (keep last N screenshots)
*/
export async function cleanupOldScreenshots(keepLast: number = 20): Promise<void> {
try {
const files = await fs.readdir(TEMP_SCREENSHOTS_FOLDER);
const screenshots = files
.filter(f => f.endsWith('.png'))
.map(f => ({ name: f, path: join(TEMP_SCREENSHOTS_FOLDER, f) }))
.sort((a, b) => a.name.localeCompare(b.name));
if (screenshots.length > keepLast) {
const toDelete = screenshots.slice(0, screenshots.length - keepLast);
for (const file of toDelete) {
await fs.unlink(file.path);
logger.debug(`Cleaned up old screenshot: ${file.name}`);
}
}
} catch (error) {
logger.warn('Failed to cleanup old screenshots', error as Error);
}
}
/**
* Get the full path for a screenshot filename
*/
export function getScreenshotPath(filename: string): string {
return join(TEMP_SCREENSHOTS_FOLDER, filename);
}
/**
* Check if a screenshot exists
*/
export async function screenshotExists(filename: string): Promise<boolean> {
try {
await fs.access(getScreenshotPath(filename));
return true;
} catch {
return false;
}
}
/**
* Get list of all screenshots in temp folder
*/
export async function getAllScreenshots(): Promise<string[]> {
try {
const files = await fs.readdir(TEMP_SCREENSHOTS_FOLDER);
return files.filter(f => f.endsWith('.png')).sort((a, b) => b.localeCompare(a));
} catch {
return [];
}
}
/**
* Get screenshot metadata including file size and dimensions
*/
export async function getScreenshotMetadata(filename: string): Promise<{
filename: string;
path: string;
size: string;
modified: string;
dimensions?: { width: number; height: number };
exists: boolean;
}> {
const filePath = getScreenshotPath(filename);
try {
const stats = await fs.stat(filePath);
let dimensions: { width: number; height: number } | undefined;
try {
// Try to get dimensions using sharp
const sharp = (await import('sharp')).default;
const metadata = await sharp(filePath).metadata();
if (metadata.width && metadata.height) {
dimensions = { width: metadata.width, height: metadata.height };
}
} catch {
// Ignore dimension errors
}
return {
filename,
path: filePath,
size: `${(stats.size / 1024).toFixed(1)}KB`,
modified: stats.mtime.toISOString(),
dimensions,
exists: true
};
} catch {
return {
filename,
path: filePath,
size: '0KB',
modified: '',
exists: false
};
}
}
/**
* Extract timestamp from filename
*/
export function extractTimestampFromScreenshotFilename(filename: string): string | undefined {
const match = filename.match(/(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})/);
if (match) {
return match[1].replace(/T/, ' ').replace(/-/g, ':');
}
return undefined;
}