Skip to main content
Glama
filesystem.ts7.16 kB
import { readdirSync, statSync, existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync } from 'fs'; import { join, basename, extname } from 'path'; import { getFullPath, getConfig } from '../config.js'; import { validateImageFormat, sanitizeFilename } from './validation.js'; export interface ModelInfo { type: string; name: string; path: string; size?: number; } export interface ImageInfo { filename: string; path: string; size: number; created_at: string; modified_at: string; } const MODEL_EXTENSIONS = ['.safetensors', '.ckpt', '.pt', '.pth', '.bin']; export function scanModelsDirectory(type: string): ModelInfo[] { const config = getConfig(); const basePath = getFullPath(config.paths.models); const typeMapping: Record<string, string> = { checkpoints: 'checkpoints', loras: 'loras', vae: 'vae', clip: 'clip', clip_vision: 'clip_vision', unet: 'unet', embeddings: 'embeddings', upscale_models: 'upscale_models', diffusion_models: 'diffusion_models', controlnet: 'controlnet', ipadapter: 'ipadapter', style_models: 'style_models', photomaker: 'photomaker', insightface: 'insightface' }; const results: ModelInfo[] = []; const scanDir = (dir: string, modelType: string): void => { if (!existsSync(dir)) return; try { const files = readdirSync(dir); for (const file of files) { const fullPath = join(dir, file); const stat = statSync(fullPath); if (stat.isDirectory()) { scanDir(fullPath, modelType); } else { const ext = extname(file).toLowerCase(); if (MODEL_EXTENSIONS.includes(ext)) { results.push({ type: modelType, name: file, path: fullPath.replace(basePath + '\\', ''), size: stat.size }); } } } } catch (error) { console.error(`Error scanning directory ${dir}:`, error); } }; if (type === 'all') { for (const [key, subdir] of Object.entries(typeMapping)) { scanDir(join(basePath, subdir), key); } } else { const subdir = typeMapping[type]; if (subdir) { scanDir(join(basePath, subdir), type); } } return results; } export function uploadImage(sourcePath: string, filename?: string, overwrite: boolean = false): { filename: string; path: string; size: number } { const config = getConfig(); const inputDir = getFullPath(config.paths.input); // Ensure input directory exists if (!existsSync(inputDir)) { mkdirSync(inputDir, { recursive: true }); } // Validate source file if (!existsSync(sourcePath)) { throw new Error(`Source file not found: ${sourcePath}`); } // Determine target filename let targetFilename = filename || basename(sourcePath); targetFilename = sanitizeFilename(targetFilename); // Validate image format if (!validateImageFormat(targetFilename)) { throw new Error(`Invalid image format: ${targetFilename}`); } // Handle existing file let targetPath = join(inputDir, targetFilename); if (existsSync(targetPath) && !overwrite) { const ext = extname(targetFilename); const nameWithoutExt = basename(targetFilename, ext); let counter = 1; do { targetFilename = `${nameWithoutExt}_${counter}${ext}`; targetPath = join(inputDir, targetFilename); counter++; } while (existsSync(targetPath)); } // Copy file copyFileSync(sourcePath, targetPath); const stat = statSync(targetPath); return { filename: targetFilename, path: targetPath, size: stat.size }; } export function getOutputImages(limit: number = 20, sort: 'newest' | 'oldest' | 'name' = 'newest', filter?: string): ImageInfo[] { const config = getConfig(); const outputDir = getFullPath(config.paths.output); if (!existsSync(outputDir)) { return []; } const files = readdirSync(outputDir); const images: ImageInfo[] = []; for (const file of files) { if (filter && !file.includes(filter)) continue; if (!validateImageFormat(file)) continue; const fullPath = join(outputDir, file); const stat = statSync(fullPath); if (stat.isFile()) { images.push({ filename: file, path: fullPath, size: stat.size, created_at: stat.birthtime.toISOString(), modified_at: stat.mtime.toISOString() }); } } // Sort if (sort === 'newest') { images.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); } else if (sort === 'oldest') { images.sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()); } else { images.sort((a, b) => a.filename.localeCompare(b.filename)); } return images.slice(0, limit); } export function ensureWorkflowLibraryExists(): void { const config = getConfig(); const libraryPath = getFullPath(config.paths.workflow_library); if (!existsSync(libraryPath)) { mkdirSync(libraryPath, { recursive: true }); } } export function saveWorkflowToLibrary(name: string, data: any): string { ensureWorkflowLibraryExists(); const config = getConfig(); const libraryPath = getFullPath(config.paths.workflow_library); const filePath = join(libraryPath, `${name}.json`); writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); return filePath; } export function loadWorkflowFromLibrary(name: string): any { const config = getConfig(); const libraryPath = getFullPath(config.paths.workflow_library); const filePath = join(libraryPath, `${name}.json`); if (!existsSync(filePath)) { throw new Error(`Workflow not found: ${name}`); } const data = readFileSync(filePath, 'utf-8'); return JSON.parse(data); } export function listWorkflowsInLibrary(filter?: string, tags?: string[]): any[] { ensureWorkflowLibraryExists(); const config = getConfig(); const libraryPath = getFullPath(config.paths.workflow_library); const files = readdirSync(libraryPath); const workflows = []; for (const file of files) { if (!file.endsWith('.json')) continue; const filePath = join(libraryPath, file); const stat = statSync(filePath); const data = JSON.parse(readFileSync(filePath, 'utf-8')); // Apply filters if (filter && !data.name?.includes(filter) && !data.description?.includes(filter)) { continue; } if (tags && tags.length > 0) { const workflowTags = data.tags || []; if (!tags.some((tag: string) => workflowTags.includes(tag))) { continue; } } workflows.push({ name: data.name, description: data.description, tags: data.tags, created_at: data.created_at, updated_at: data.updated_at, size: stat.size }); } return workflows; } export function deleteWorkflowFromLibrary(name: string): void { const config = getConfig(); const libraryPath = getFullPath(config.paths.workflow_library); const filePath = join(libraryPath, `${name}.json`); if (!existsSync(filePath)) { throw new Error(`Workflow not found: ${name}`); } unlinkSync(filePath); }

Implementation Reference

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/Nikolaibibo/claude-comfyui-mcp'

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