@necto-ai/pgit
Version: 
Private file tracking with dual git repositories
297 lines • 10.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigManager = exports.ConfigMigrationError = exports.ConfigValidationError = exports.ConfigError = void 0;
const path_1 = __importDefault(require("path"));
const config_types_1 = require("../types/config.types");
const config_schema_1 = require("../types/config.schema");
const zod_1 = require("zod");
const filesystem_service_1 = require("./filesystem.service");
const platform_detector_1 = require("../utils/platform.detector");
const base_error_1 = require("../errors/base.error");
/**
 * Configuration management errors
 */
class ConfigError extends base_error_1.BaseError {
    constructor() {
        super(...arguments);
        this.code = 'CONFIG_ERROR';
        this.recoverable = true;
    }
}
exports.ConfigError = ConfigError;
class ConfigValidationError extends base_error_1.BaseError {
    constructor() {
        super(...arguments);
        this.code = 'CONFIG_VALIDATION_ERROR';
        this.recoverable = true;
    }
}
exports.ConfigValidationError = ConfigValidationError;
class ConfigMigrationError extends base_error_1.BaseError {
    constructor() {
        super(...arguments);
        this.code = 'CONFIG_MIGRATION_ERROR';
        this.recoverable = false;
    }
}
exports.ConfigMigrationError = ConfigMigrationError;
/**
 * Configuration manager for private git CLI
 */
class ConfigManager {
    constructor(workingDir, fileSystem) {
        this.configPath = path_1.default.join(workingDir, config_types_1.DEFAULT_PATHS.config);
        this.fileSystem = fileSystem || new filesystem_service_1.FileSystemService();
    }
    /**
     * Create initial configuration
     */
    async create(projectPath, options = {}) {
        const now = new Date();
        const projectName = path_1.default.basename(projectPath);
        const config = {
            version: config_types_1.CURRENT_CONFIG_VERSION,
            privateRepoPath: config_types_1.DEFAULT_PATHS.privateRepo,
            storagePath: config_types_1.DEFAULT_PATHS.storage,
            trackedPaths: [],
            initialized: now,
            settings: {
                ...config_types_1.DEFAULT_SETTINGS,
                ...options,
            },
            metadata: {
                projectName,
                mainRepoPath: projectPath,
                cliVersion: config_types_1.CURRENT_CONFIG_VERSION,
                platform: platform_detector_1.PlatformDetector.getPlatformName(),
                lastModified: now,
            },
        };
        await this.save(config);
        return config;
    }
    /**
     * Load configuration from file
     */
    async load() {
        if (this.cachedConfig) {
            return this.cachedConfig;
        }
        try {
            const content = await this.fileSystem.readFile(this.configPath);
            const jsonConfig = JSON.parse(content);
            const validatedConfig = config_schema_1.PrivateConfigJsonSchema.parse(jsonConfig);
            this.cachedConfig = validatedConfig;
            return validatedConfig;
        }
        catch (error) {
            if (error instanceof Error && error.name === 'ZodError') {
                throw new ConfigValidationError('Configuration data is invalid', error.message);
            }
            throw new ConfigError('Failed to load configuration', error instanceof Error ? error.message : String(error));
        }
    }
    /**
     * Save configuration to file
     */
    async save(config) {
        try {
            // Validate configuration
            const validatedConfig = config_schema_1.PrivateConfigSchema.parse(config);
            // Update last modified timestamp
            validatedConfig.metadata.lastModified = new Date();
            // Transform for JSON serialization
            const jsonConfig = this.transformToJson(validatedConfig);
            // Write to file
            const configContent = JSON.stringify(jsonConfig, null, 2);
            await this.fileSystem.writeFileAtomic(this.configPath, configContent);
            // Update cache
            this.cachedConfig = validatedConfig;
        }
        catch (error) {
            if (error instanceof zod_1.ZodError) {
                // Extract specific validation error messages from ZodError
                const zodError = error;
                const errors = zodError.issues || [];
                const errorMessages = errors.map((err) => err.message);
                // If all errors are "Required", use generic message for better UX
                const allRequired = errors.length > 0 && errors.every((err) => err.message === 'Required');
                const message = allRequired ? 'Configuration data is invalid' : errorMessages.join('; ');
                throw new ConfigValidationError(message, error.message);
            }
            throw new ConfigError('Failed to save configuration', error instanceof Error ? error.message : String(error));
        }
    }
    /**
     * Update git exclude settings
     */
    async updateGitExcludeSettings(newSettings) {
        const config = await this.load();
        config.settings.gitExclude = {
            ...config.settings.gitExclude,
            ...newSettings,
        };
        await this.save(config);
        return config;
    }
    /**
     * Get current git exclude settings
     */
    async getGitExcludeSettings() {
        const config = await this.load();
        return config.settings.gitExclude;
    }
    /**
     * Reset git exclude settings to defaults
     */
    async resetGitExcludeSettings() {
        const config = await this.load();
        config.settings.gitExclude = { ...config_types_1.DEFAULT_GIT_EXCLUDE_SETTINGS };
        await this.save(config);
        return config;
    }
    /**
     * Add a tracked path
     */
    async addTrackedPath(filePath) {
        const config = await this.load();
        const normalizedPath = path_1.default.normalize(filePath);
        if (!config.trackedPaths.includes(normalizedPath)) {
            config.trackedPaths.push(normalizedPath);
            await this.save(config);
        }
    }
    /**
     * Remove a tracked path
     */
    async removeTrackedPath(filePath) {
        const config = await this.load();
        const normalizedPath = path_1.default.normalize(filePath);
        const index = config.trackedPaths.indexOf(normalizedPath);
        if (index !== -1) {
            config.trackedPaths.splice(index, 1);
            await this.save(config);
        }
    }
    /**
     * Add multiple tracked paths
     */
    async addMultipleTrackedPaths(filePaths) {
        const config = await this.load();
        const normalizedPaths = filePaths.map(fp => path_1.default.normalize(fp));
        const uniquePaths = normalizedPaths.filter(np => !config.trackedPaths.includes(np));
        if (uniquePaths.length > 0) {
            config.trackedPaths.push(...uniquePaths);
            await this.save(config);
        }
    }
    /**
     * Remove multiple tracked paths
     */
    async removeMultipleTrackedPaths(filePaths) {
        const config = await this.load();
        const normalizedPaths = filePaths.map(fp => path_1.default.normalize(fp));
        const notTracked = [];
        for (const normalizedPath of normalizedPaths) {
            const index = config.trackedPaths.indexOf(normalizedPath);
            if (index !== -1) {
                config.trackedPaths.splice(index, 1);
            }
            else {
                notTracked.push(normalizedPath);
            }
        }
        if (notTracked.length > 0) {
            throw new ConfigError(`Some paths were not tracked: ${notTracked.join(', ')}`);
        }
        await this.save(config);
    }
    /**
     * Check if configuration exists
     */
    async exists() {
        return await this.fileSystem.isFile(this.configPath);
    }
    /**
     * Get cached configuration
     */
    getCached() {
        return this.cachedConfig;
    }
    /**
     * Clear configuration cache
     */
    clearCache() {
        this.cachedConfig = undefined;
    }
    /**
     * Get configuration file path
     */
    getConfigPath() {
        return this.configPath;
    }
    /**
     * Get configuration health status
     */
    async getHealth() {
        try {
            const exists = await this.exists();
            if (!exists) {
                return {
                    exists: false,
                    valid: false,
                    errors: ['Configuration file does not exist'],
                    needsMigration: false,
                    currentVersion: '',
                    targetVersion: config_types_1.CURRENT_CONFIG_VERSION,
                };
            }
            const config = await this.load();
            const needsMigration = config.version !== config_types_1.CURRENT_CONFIG_VERSION;
            return {
                exists: true,
                valid: true,
                errors: [],
                needsMigration,
                currentVersion: config.version,
                targetVersion: config_types_1.CURRENT_CONFIG_VERSION,
            };
        }
        catch (error) {
            return {
                exists: true,
                valid: false,
                errors: [error instanceof Error ? error.message : String(error)],
                needsMigration: false,
                currentVersion: '',
                targetVersion: config_types_1.CURRENT_CONFIG_VERSION,
            };
        }
    }
    /**
     * Transform configuration to JSON format
     */
    transformToJson(config) {
        return {
            version: config.version,
            privateRepoPath: config.privateRepoPath,
            storagePath: config.storagePath,
            trackedPaths: config.trackedPaths,
            initialized: config.initialized.toISOString(),
            lastCleanup: config.lastCleanup?.toISOString(),
            settings: config.settings,
            metadata: {
                projectName: config.metadata.projectName,
                mainRepoPath: config.metadata.mainRepoPath,
                cliVersion: config.metadata.cliVersion,
                platform: config.metadata.platform,
                lastModified: config.metadata.lastModified.toISOString(),
            },
        };
    }
}
exports.ConfigManager = ConfigManager;
//# sourceMappingURL=config.manager.js.map