Skip to main content
Glama
file-manager.ts5.67 kB
/* istanbul ignore file */ import fs from 'fs'; import path from 'path'; /** * File types that can be managed by the FileManager */ export enum FileType { SEED = 'seed', WALLET_BACKUP = 'wallet-backup', LOG = 'log', TRANSACTION_DB = 'transaction-db' } /** * Configuration for file operations */ export interface FileConfig { /** * Base directory for all files * @default '.storage' */ baseDir?: string; /** * Whether to create directories if they don't exist * @default true */ createDirs?: boolean; /** * File permissions for directories * @default 0o755 */ dirMode?: number; /** * File permissions for files * @default 0o644 */ fileMode?: number; /** * Whether to use agent-specific subdirectories * @default true */ useAgentSubdirs?: boolean; } /** * Manages file operations and paths for different types of files */ export class FileManager { private static instance: FileManager | undefined; private config: Required<FileConfig>; private constructor(config: FileConfig = {}) { // Convert relative path to absolute path based on process execution directory const baseDir = config.baseDir || '.storage'; const absoluteBaseDir = path.isAbsolute(baseDir) ? baseDir : path.resolve(process.cwd(), baseDir); this.config = { baseDir: absoluteBaseDir, createDirs: config.createDirs ?? true, dirMode: config.dirMode || 0o755, fileMode: config.fileMode || 0o644, useAgentSubdirs: config.useAgentSubdirs ?? true }; } /** * Get the singleton instance of FileManager */ public static getInstance(config?: FileConfig): FileManager { if (!FileManager.instance) { FileManager.instance = new FileManager(config); } return FileManager.instance; } public static resetInstance(): void { FileManager.instance = undefined; } /** * Get the path for a specific file type and agent */ public getPath(fileType: FileType, agentId: string, filename?: string): string { const typeDir = this.getTypeDirectory(fileType); const agentDir = this.config.useAgentSubdirs ? path.join(typeDir, agentId) : typeDir; if (filename) { return path.join(agentDir, filename); } return agentDir; } /** * Get the directory for a specific file type */ private getTypeDirectory(fileType: FileType): string { const typeDirs: Record<FileType, string> = { [FileType.SEED]: 'seeds', [FileType.WALLET_BACKUP]: 'wallet-backups', [FileType.LOG]: 'logs', [FileType.TRANSACTION_DB]: 'transaction-db' }; return path.join(this.config.baseDir, typeDirs[fileType]); } /** * Ensure a directory exists */ public ensureDirectoryExists(dirPath: string): void { if (!fs.existsSync(dirPath)) { if (this.config.createDirs) { fs.mkdirSync(dirPath, { recursive: true, mode: this.config.dirMode }); } else { throw new Error(`Directory does not exist: ${dirPath}`); } } } /** * Write data to a file */ public writeFile(fileType: FileType, agentId: string, data: string | Buffer, filename: string): void { const filePath = this.getPath(fileType, agentId, filename); const dirPath = path.dirname(filePath); this.ensureDirectoryExists(dirPath); fs.writeFileSync(filePath, data, { mode: this.config.fileMode }); } /** * Read data from a file */ public readFile(fileType: FileType, agentId: string, filename: string): string { const filePath = this.getPath(fileType, agentId, filename); if (!fs.existsSync(filePath)) { throw new Error(`File does not exist: ${filePath}`); } return fs.readFileSync(filePath, 'utf-8'); } /** * Check if a file exists */ public fileExists(fileType: FileType, agentId: string, filename: string): boolean { const filePath = this.getPath(fileType, agentId, filename); return fs.existsSync(filePath); } /** * Delete a file */ public deleteFile(fileType: FileType, agentId: string, filename: string): void { const filePath = this.getPath(fileType, agentId, filename); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } } /** * List files in a directory */ public listFiles(fileType: FileType, agentId: string): string[] { const dirPath = this.getPath(fileType, agentId); if (!fs.existsSync(dirPath)) { return []; } return fs.readdirSync(dirPath); } /** * Get file stats */ public getFileStats(fileType: FileType, agentId: string, filename: string): fs.Stats { const filePath = this.getPath(fileType, agentId, filename); if (!fs.existsSync(filePath)) { throw new Error(`File does not exist: ${filePath}`); } return fs.statSync(filePath); } /** * Create a read stream for a file */ public createReadStream(fileType: FileType, agentId: string, filename: string): fs.ReadStream { const filePath = this.getPath(fileType, agentId, filename); if (!fs.existsSync(filePath)) { throw new Error(`File does not exist: ${filePath}`); } return fs.createReadStream(filePath); } /** * Create a write stream for a file */ public createWriteStream(fileType: FileType, agentId: string, filename: string): fs.WriteStream { const filePath = this.getPath(fileType, agentId, filename); const dirPath = path.dirname(filePath); this.ensureDirectoryExists(dirPath); return fs.createWriteStream(filePath, { mode: this.config.fileMode }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/evilpixi/pixi-midnight-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server