diff --git a/backend/src/config/common-path.ts b/backend/src/config/common-path.ts index 173274f1..6112fbb8 100644 --- a/backend/src/config/common-path.ts +++ b/backend/src/config/common-path.ts @@ -1,161 +1,93 @@ import path from 'path'; import os from 'os'; -import { name } from '../../package.json'; import { existsSync, mkdirSync, promises } from 'fs-extra'; - -export class CodeFoxPaths { - private static readonly APP_NAME = name; - private static readonly ROOT_DIR = path.join( - os.homedir(), - `.${CodeFoxPaths.APP_NAME}`, +import { createHash } from 'crypto'; + +// Constants for base directories +const APP_NAME = 'codefox'; +const ROOT_DIR = path.join(os.homedir(), `.${APP_NAME}`); + +// Utility function to ensure a directory exists +const ensureDir = (dirPath: string): string => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } + return dirPath; +}; + +// ----------- We need path traverse Protection after we decide how we read and store the file !!!!!!!!!!!!! ------------ +// ------------------------------------------------------------------------------------------------------------- + +// Root Directory Accessor +export const getRootDir = (): string => ensureDir(ROOT_DIR); + +// Configuration Paths +export const getConfigDir = (): string => + ensureDir(path.join(getRootDir(), 'config')); +export const getConfigPath = (configName: string): string => + path.join(getConfigDir(), `${configName}.json`); + +// Models Directory +export const getModelsDir = (): string => + ensureDir(path.join(getRootDir(), 'models')); +export const getModelPath = (modelName: string): string => + path.join(getModelsDir(), modelName); + +// Project-Specific Paths +export const getProjectsDir = (): string => + ensureDir(path.join(getRootDir(), 'projects')); +export const getProjectPath = (projectId: string): string => + ensureDir(path.join(getProjectsDir(), projectId)); +export const getProjectSourceDir = (projectId: string): string => + ensureDir(path.join(getProjectPath(projectId), 'src')); +export const getProjectGeneratedDir = (projectId: string): string => + ensureDir(path.join(getProjectPath(projectId), 'generated')); +export const getProjectTestsDir = (projectId: string): string => + ensureDir(path.join(getProjectPath(projectId), 'tests')); + +// Database Paths +export const getDatabaseDir = (): string => + ensureDir(path.join(getRootDir(), 'data')); +export const getDatabasePath = (): string => + path.join(getDatabaseDir(), 'codefox.db'); + +// Vector Database (INDEX) Path +export const getIndexDir = (): string => + ensureDir(path.join(getRootDir(), 'INDEX')); +export const getIndexFilePath = (indexFileName: string): string => + path.join(getIndexDir(), indexFileName); + +// Temporary files +export const getTempDir = (): string => { + const tempDir = path.join(ROOT_DIR, 'temp'); + if (!existsSync(tempDir)) { + mkdirSync(tempDir, { recursive: true }); + } + return tempDir; +}; + +// Utility Functions +export const exists = (filePath: string): boolean => existsSync(filePath); + +export const cleanTempDir = async (): Promise => { + const tempDir = getTempDir(); + const files = await promises.readdir(tempDir); + await Promise.all( + files.map((file) => promises.unlink(path.join(tempDir, file))), ); - - /** - * Internal helper to ensure a directory exists before returning its path - * @param dirPath The directory path to check/create - * @returns The same directory path - */ - private static ensureDir(dirPath: string): string { - if (!existsSync(path.dirname(dirPath))) { - this.ensureDir(path.dirname(dirPath)); - } - if (!existsSync(dirPath)) { - mkdirSync(dirPath, { recursive: true }); - } - return dirPath; - } - - /** - * Root Directory - */ - public static getRootDir(): string { - return this.ensureDir(CodeFoxPaths.ROOT_DIR); - } - - /** - * Models Directory - */ - public static getModelsDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'models')); - } - - public static getModelPath(modelName: string): string { - return path.join(this.getModelsDir(), modelName); - } - - /** - * Projects Directory - */ - public static getProjectsDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'projects')); - } - - public static getProjectPath(projectId: string): string { - return this.ensureDir(path.join(this.getProjectsDir(), projectId)); - } - - public static getProjectSourceDir(projectId: string): string { - return this.ensureDir(path.join(this.getProjectPath(projectId), 'src')); - } - - public static getProjectGeneratedDir(projectId: string): string { - return this.ensureDir( - path.join(this.getProjectPath(projectId), 'generated'), - ); - } - - public static getProjectTestsDir(projectId: string): string { - return this.ensureDir(path.join(this.getProjectPath(projectId), 'tests')); - } - - /** - * Database - */ - public static getDatabaseDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'data')); - } - - public static getDatabasePath(): string { - this.getDatabaseDir(); // Ensure database directory exists - return path.join(this.getDatabaseDir(), 'codefox.db'); - } - - /** - * Configuration - */ - public static getConfigDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'config')); - } - - public static getConfigPath(configName: string): string { - this.getConfigDir(); // Ensure config directory exists - return path.join(this.getConfigDir(), `${configName}.json`); - } - - /** - * Cache - */ - public static getCacheDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'cache')); - } - - /** - * Logs - */ - public static getLogsDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'logs')); - } - - /** - * Temporary files - */ - public static getTempDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'temp')); - } - - /** - * Templates - */ - public static getTemplatesDir(): string { - return this.ensureDir(path.join(this.getRootDir(), 'templates')); - } - - public static getPromptTemplatePath(templateName: string): string { - this.getTemplatesDir(); // Ensure templates directory exists - return path.join(this.getTemplatesDir(), `${templateName}.txt`); - } - - /** - * Utility Methods - */ - public static resolvePath(...pathSegments: string[]): string { - const resolvedPath = path.join(this.getRootDir(), ...pathSegments); - return this.ensureDir(path.dirname(resolvedPath)); - } - - public static exists(filePath: string): boolean { - return existsSync(filePath); - } - - public static async cleanTempDir(): Promise { - const tempDir = this.getTempDir(); - const files = await promises.readdir(tempDir); - await Promise.all( - files.map((file) => promises.unlink(path.join(tempDir, file))), - ); - } - - public static getProjectStructure(projectId: string): { - root: string; - src: string; - generated: string; - tests: string; - } { - return { - root: this.getProjectPath(projectId), - src: this.getProjectSourceDir(projectId), - generated: this.getProjectGeneratedDir(projectId), - tests: this.getProjectTestsDir(projectId), - }; - } -} +}; + +// Access Project Structure +export const getProjectStructure = ( + projectId: string, +): { + root: string; + src: string; + generated: string; + tests: string; +} => ({ + root: getProjectPath(projectId), + src: getProjectSourceDir(projectId), + generated: getProjectGeneratedDir(projectId), + tests: getProjectTestsDir(projectId), +}); diff --git a/frontend/src/config/common-path.ts b/frontend/src/config/common-path.ts new file mode 100644 index 00000000..40ca5559 --- /dev/null +++ b/frontend/src/config/common-path.ts @@ -0,0 +1,91 @@ +import path from 'path'; +import { existsSync, mkdirSync, promises as fsPromises } from 'fs-extra'; +import { createHash } from 'crypto'; + +// Constants for the frontend root directory +const FRONTEND_ROOT_DIR = path.resolve(__dirname, '../.codefox-client'); +const CLIENT_CACHE_DIR = path.join(FRONTEND_ROOT_DIR, '.cache'); + +// Utility function to ensure a directory exists +const ensureDir = (dirPath: string): string => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } + return dirPath; +}; + +// ----------- We need path traverse Protection after we decide how we read and store the file !!!!!!!!!!!!! ------------ +// ------------------------------------------------------------------------------------------------------------- + +// Step 1: Frontend Root Directory +export const getFrontendRootDir = (): string => ensureDir(FRONTEND_ROOT_DIR); + +// Step 2: Cache Directory +export const getCacheDir = (): string => ensureDir(CLIENT_CACHE_DIR); + +// Step 3: User Cache Directory +export const getUserCacheDir = (userId: string): string => { + const hashedUserId = hashUserId(userId); + return ensureDir(path.join(getCacheDir(), hashedUserId)); +}; + +// Step 4: Project Cache Directory within a User's Directory +export const getProjectCacheDir = ( + userId: string, + projectId: string +): string => { + return ensureDir(path.join(getUserCacheDir(userId), projectId)); +}; + +// Step 5: Content Directory within a Project's Cache Directory +export const getProjectContentDir = ( + userId: string, + projectId: string +): string => { + return ensureDir(path.join(getProjectCacheDir(userId, projectId), 'content')); +}; + +// Updated function to get the full path to a specific file within the 'content' directory +export const getProjectContentPath = ( + userId: string, + projectId: string, + fileName: string +): string => { + return path.join(getProjectContentDir(userId, projectId), fileName); +}; + +// Helper function to hash user IDs for unique cache directories +const hashUserId = (userId: string): string => { + return createHash('md5').update(userId).digest('hex'); +}; + +// Utility Functions for File Operations +export const writeProjectContent = async ( + userId: string, + projectId: string, + fileName: string, + content: string +): Promise => { + const contentPath = getProjectContentPath(userId, projectId, fileName); + await fsPromises.writeFile(contentPath, content, 'utf8'); +}; + +export const readProjectContent = async ( + userId: string, + projectId: string, + fileName: string +): Promise => { + const contentPath = getProjectContentPath(userId, projectId, fileName); + return fsPromises.readFile(contentPath, 'utf8'); +}; + +export const deleteProjectContent = async ( + userId: string, + projectId: string, + fileName: string +): Promise => { + const contentPath = getProjectContentPath(userId, projectId, fileName); + if (existsSync(contentPath)) { + await fsPromises.unlink(contentPath); + } +};