UNPKG

@iyulab/oops

Version:

Core SDK for Oops - Safe text file editing with automatic backup

386 lines 15.2 kB
"use strict"; /** * Main Oops SDK class */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Oops = void 0; const config_1 = require("./config"); const workspace_1 = require("./workspace"); const tracker_1 = require("./tracker"); const backup_1 = require("./backup"); const diff_1 = require("./diff"); const version_1 = require("./version"); const simple_version_1 = require("./simple-version"); class Oops { configManager; workspaceManager; fileTracker; backupManager; diffProcessor; versionManager; simpleVersionManagers = new Map(); constructor(config = {}, workspacePath) { this.configManager = new config_1.ConfigManager(config); this.workspaceManager = new workspace_1.WorkspaceManager(workspacePath); this.fileTracker = new tracker_1.FileTracker(this.workspaceManager.getWorkspacePath()); this.backupManager = new backup_1.BackupManager(this.workspaceManager.getWorkspacePath()); this.diffProcessor = new diff_1.DiffProcessor(); this.versionManager = new version_1.VersionManager(this.workspaceManager.getWorkspacePath()); } // Workspace operations async init() { await this.workspaceManager.init(); } async getWorkspaceInfo() { try { return await this.workspaceManager.getInfo(); } catch { // If workspace doesn't exist, return basic info return { path: this.workspaceManager.getWorkspacePath(), type: 'local', exists: false, isHealthy: false, trackedFiles: [], createdAt: new Date(), }; } } // File tracking operations async track(filePath, message) { // Initialize workspace if needed if (!(await this.workspaceManager.exists())) { await this.init(); } return await this.fileTracker.startTracking(filePath, message); } async isTracked(filePath) { return await this.fileTracker.isTracked(filePath); } async getTrackingInfo(filePath) { return await this.fileTracker.getTrackingInfo(filePath); } // Diff operations async diff(filePath) { const trackingInfo = await this.fileTracker.getTrackingInfo(filePath); return await this.diffProcessor.generateDiff(trackingInfo.backupPath, filePath); } async hasChanges(filePath) { try { const trackingInfo = await this.fileTracker.getTrackingInfo(filePath); return await this.diffProcessor.hasChanges(trackingInfo.backupPath, filePath); } catch { // If we can't get tracking info, assume no changes return false; } } // Backup operations async keep(filePath) { // Verify file is being tracked if (!(await this.isTracked(filePath))) { throw new Error(`File is not being tracked: ${filePath}`); } // Apply changes by simply stopping tracking // The current file already contains the desired changes await this.fileTracker.stopTracking(filePath); } async undo(filePath) { // Verify file is being tracked if (!(await this.isTracked(filePath))) { throw new Error(`File is not being tracked: ${filePath}`); } // Get tracking info to find backup path const trackingInfo = await this.fileTracker.getTrackingInfo(filePath); // Restore file from backup const { FileSystem } = await Promise.resolve().then(() => __importStar(require('./file-system'))); if (await FileSystem.exists(trackingInfo.backupPath)) { await FileSystem.copyFile(trackingInfo.backupPath, filePath); } else { throw new Error(`Backup not found: ${trackingInfo.backupPath}`); } // Stop tracking await this.fileTracker.stopTracking(filePath); } async abort(filePath) { await this.fileTracker.stopTracking(filePath); } // Workspace management async isWorkspaceHealthy() { try { const info = await this.getWorkspaceInfo(); return info.exists && info.isHealthy; } catch { return false; } } async cleanWorkspace() { await this.workspaceManager.clean(); } async getWorkspaceSize() { const info = await this.getWorkspaceInfo(); let totalSize = 0; // Calculate total size of all tracked files for (const file of info.trackedFiles) { try { const { FileSystem } = await Promise.resolve().then(() => __importStar(require('./file-system'))); if (await FileSystem.exists(file.filePath)) { const fileInfo = await FileSystem.getFileInfo(file.filePath); totalSize += fileInfo.size; } } catch { // Ignore errors for individual files } } return { files: info.trackedFiles.length, sizeBytes: totalSize, }; } async getAllTrackedFiles() { return await this.fileTracker.getAllTracked(); } async keepAll() { const trackedFiles = await this.getAllTrackedFiles(); for (const file of trackedFiles) { await this.keep(file.filePath); } } async undoAll() { const trackedFiles = await this.getAllTrackedFiles(); for (const file of trackedFiles) { await this.undo(file.filePath); } } async abortAll() { const trackedFiles = await this.getAllTrackedFiles(); for (const file of trackedFiles) { await this.abort(file.filePath); } } async validateTrackedFiles() { const errors = []; const trackedFiles = await this.getAllTrackedFiles(); for (const file of trackedFiles) { try { const { FileSystem } = await Promise.resolve().then(() => __importStar(require('./file-system'))); if (!(await FileSystem.exists(file.filePath))) { errors.push(`Tracked file does not exist: ${file.filePath}`); } if (!(await FileSystem.exists(file.backupPath))) { errors.push(`Backup file does not exist: ${file.backupPath}`); } } catch (error) { errors.push(`Error validating ${file.filePath}: ${error.message}`); } } return { valid: errors.length === 0, errors }; } async getVersion() { try { const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); const path = await Promise.resolve().then(() => __importStar(require('path'))); const packagePath = path.join(__dirname, '../../package.json'); const packageContent = await fs.readFile(packagePath, 'utf8'); const packageJson = JSON.parse(packageContent); return packageJson.version; } catch { return '0.1.0'; } } static async createTempWorkspace() { const { FileSystem } = await Promise.resolve().then(() => __importStar(require('./file-system'))); const tempDir = await FileSystem.createTempDirectory('oops-temp-'); return new Oops({}, tempDir); } static async createLocalWorkspace(workspaceDir) { return new Oops({}, workspaceDir); } // Configuration getConfig() { return this.configManager.get(); } setConfig(key, value) { this.configManager.set(key, value); } // Simple Version System Methods (for TDD tests) async trackWithVersion(filePath, message) { // Initialize workspace if needed if (!(await this.workspaceManager.exists())) { await this.init(); } // Get or create simple version manager for this file const versionManager = this.getSimpleVersionManager(filePath); await versionManager.initialize(); // Create initial version return await versionManager.createInitialVersion(message || 'Initial version'); } async commitVersion(filePath, message) { const versionManager = this.getSimpleVersionManager(filePath); return await versionManager.commitVersion(message); } async getVersionHistory(filePath) { const versionManager = this.getSimpleVersionManager(filePath); const versions = await versionManager.getAllVersions(); if (versions.length === 0) { throw new Error(`File is not being tracked: ${filePath}`); } return versions; } async checkoutVersion(filePath, version) { const versionManager = this.getSimpleVersionManager(filePath); const versions = await versionManager.getAllVersions(); if (versions.length === 0) { throw new Error(`File is not being tracked: ${filePath}`); } await versionManager.checkoutVersion(version); } async getCurrentVersion(filePath) { const versionManager = this.getSimpleVersionManager(filePath); const versions = await versionManager.getAllVersions(); if (versions.length === 0) { throw new Error(`File is not being tracked: ${filePath}`); } const currentVersion = await versionManager.getCurrentVersion(); return currentVersion || 1; } async getVersionDiff(filePath, fromVersion, toVersion) { const versionManager = this.getSimpleVersionManager(filePath); const versions = await versionManager.getAllVersions(); if (versions.length === 0) { throw new Error(`File is not being tracked: ${filePath}`); } return await versionManager.getDiff(fromVersion, toVersion); } async hasVersionChanges(filePath) { try { const versionManager = this.getSimpleVersionManager(filePath); return await versionManager.hasChanges(); } catch { return false; } } getSimpleVersionManager(filePath) { if (!this.simpleVersionManagers.has(filePath)) { const versionManager = new simple_version_1.SimpleVersionManager(this.workspaceManager.getWorkspacePath(), filePath); this.simpleVersionManagers.set(filePath, versionManager); } return this.simpleVersionManagers.get(filePath); } // Version management operations (legacy) async trackWithVersioning(filePath, message) { // Initialize workspace if needed if (!(await this.workspaceManager.exists())) { await this.init(); } // Check if already versioned try { const history = await this.versionManager.getVersionHistory(filePath); return history.versions[history.versions.length - 1]; // Return latest version } catch { // Not versioned yet, initialize return await this.versionManager.initializeVersioning(filePath, message); } } async commit(filePath, message) { return await this.versionManager.createCommit(filePath, message); } async commitAll(message) { const trackedFiles = await this.getAllTrackedFiles(); const commits = []; const errors = []; for (const file of trackedFiles) { try { if (await this.hasVersionChanges(file.filePath)) { const commit = await this.versionManager.createCommit(file.filePath, message); commits.push(commit); } } catch (error) { // If version system fails, try to initialize versioning first try { await this.trackWithVersioning(file.filePath, 'Initial version'); if (await this.hasVersionChanges(file.filePath)) { const commit = await this.versionManager.createCommit(file.filePath, message); commits.push(commit); } } catch (initError) { // Only add to errors, don't print to console errors.push(`Failed to commit ${file.filePath}: ${initError.message}`); } } } // If we have errors but no commits, this might indicate a real problem if (errors.length > 0 && commits.length === 0) { // Only log the first few errors to avoid spam const significantErrors = errors.slice(0, 3); throw new Error(`No files could be committed. Recent errors: ${significantErrors.join('; ')}`); } return commits; } async getVersions(filePath) { return await this.versionManager.listVersions(filePath); } async versionDiff(filePath, fromVersion, toVersion) { return await this.versionManager.diff(filePath, fromVersion, toVersion); } async untrackWithVersioning(filePath) { // Remove version tracking await this.versionManager.removeVersioning(filePath); // Remove old-style tracking if it exists if (await this.isTracked(filePath)) { await this.abort(filePath); } } async undoWithVersioning(filePath, version) { const targetVersion = version || '1.0'; // Default to initial version // Checkout the specified version await this.versionManager.checkout(filePath, targetVersion); // Remove version tracking (stop tracking) await this.versionManager.removeVersioning(filePath); } } exports.Oops = Oops; //# sourceMappingURL=oops.js.map