UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

163 lines 24.2 kB
/** * Migration Manager - Handles migration from legacy structure to portfolio structure */ import * as fs from 'fs/promises'; import * as path from 'path'; import { ElementType } from './types.js'; import { logger } from '../utils/logger.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; export class MigrationManager { portfolioManager; constructor(portfolioManager) { this.portfolioManager = portfolioManager; } /** * Check if migration is needed */ async needsMigration() { const hasLegacy = await this.portfolioManager.hasLegacyPersonas(); const portfolioExists = await this.portfolioManager.exists(); // Need migration if we have legacy personas but no portfolio yet return hasLegacy && !portfolioExists; } /** * Perform migration from legacy to portfolio structure */ async migrate(options) { const result = { success: true, migratedCount: 0, errors: [], backedUp: false }; try { // Check if migration is needed if (!await this.needsMigration()) { logger.info('[MigrationManager] No migration needed'); return result; } logger.info('[MigrationManager] Starting migration from legacy personas to portfolio structure'); // Create backup if requested if (options?.backup) { const backupPath = await this.createBackup(); result.backedUp = true; result.backupPath = backupPath; logger.info(`[MigrationManager] Created backup at: ${backupPath}`); } // Initialize portfolio structure await this.portfolioManager.initialize(); // Get legacy personas const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const files = await fs.readdir(legacyDir); const personaFiles = files.filter(file => file.endsWith('.md')); logger.info(`[MigrationManager] Found ${personaFiles.length} personas to migrate`); // Migrate each persona for (const file of personaFiles) { try { await this.migratePersona(file); result.migratedCount++; } catch (error) { const errorMsg = `Failed to migrate ${file}: ${error instanceof Error ? error.message : String(error)}`; logger.error(`[MigrationManager] ${errorMsg}`); result.errors.push(errorMsg); result.success = false; } } // If all migrations successful, optionally clean up legacy directory if (result.success && result.migratedCount > 0) { logger.info(`[MigrationManager] Successfully migrated ${result.migratedCount} personas`); // Note: We don't automatically delete the legacy directory // User should manually remove it after confirming migration success } } catch (error) { result.success = false; const errorMsg = `Migration failed: ${error instanceof Error ? error.message : String(error)}`; result.errors.push(errorMsg); // Log with full error details including stack trace if (error instanceof Error) { logger.error(`[MigrationManager] ${errorMsg}`, { stack: error.stack, name: error.name, cause: error.cause }); } else { logger.error(`[MigrationManager] ${errorMsg}`, { rawError: error }); } } return result; } /** * Migrate a single persona file */ async migratePersona(filename) { // Normalize filename to prevent Unicode attacks const filenameValidation = UnicodeValidator.normalize(filename); const normalizedFilename = filenameValidation.normalizedContent; if (normalizedFilename !== filename) { logger.warn(`[MigrationManager] Filename normalized from "${filename}" to "${normalizedFilename}"`); } if (!filenameValidation.isValid) { logger.warn(`[MigrationManager] Filename has Unicode issues: ${filenameValidation.detectedIssues?.join(', ')}`); } const legacyPath = path.join(this.portfolioManager.getLegacyPersonasDir(), filename); const newPath = this.portfolioManager.getElementPath(ElementType.PERSONA, normalizedFilename); // Read the content const content = await fs.readFile(legacyPath, 'utf-8'); // Normalize content to prevent Unicode issues const contentValidation = UnicodeValidator.normalize(content); const normalizedContent = contentValidation.normalizedContent; if (!contentValidation.isValid) { logger.warn(`[MigrationManager] Content has Unicode issues in ${filename}: ${contentValidation.detectedIssues?.join(', ')}`); } // Write to new location await fs.writeFile(newPath, normalizedContent, 'utf-8'); logger.debug(`[MigrationManager] Migrated: ${filename}`); } /** * Create backup of legacy personas */ async createBackup() { const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const backupDir = `${legacyDir}_backup_${timestamp}`; // Create backup directory await fs.mkdir(backupDir, { recursive: true }); // Copy all files const files = await fs.readdir(legacyDir); for (const file of files) { const srcPath = path.join(legacyDir, file); const destPath = path.join(backupDir, file); const stats = await fs.stat(srcPath); if (stats.isFile()) { await fs.copyFile(srcPath, destPath); } } return backupDir; } /** * Get migration status report */ async getMigrationStatus() { const hasLegacyPersonas = await this.portfolioManager.hasLegacyPersonas(); let legacyPersonaCount = 0; if (hasLegacyPersonas) { const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const files = await fs.readdir(legacyDir); legacyPersonaCount = files.filter(file => file.endsWith('.md')).length; } const portfolioExists = await this.portfolioManager.exists(); const portfolioStats = portfolioExists ? await this.portfolioManager.getStatistics() : Object.values(ElementType).reduce((acc, type) => ({ ...acc, [type]: 0 }), {}); return { hasLegacyPersonas, legacyPersonaCount, portfolioExists, portfolioStats }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vTWlncmF0aW9uTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBVTlFLE1BQU0sT0FBTyxnQkFBZ0I7SUFDbkIsZ0JBQWdCLENBQW1CO0lBRTNDLFlBQVksZ0JBQWtDO1FBQzVDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsY0FBYztRQUN6QixNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ2xFLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBRTdELGlFQUFpRTtRQUNqRSxPQUFPLFNBQVMsSUFBSSxDQUFDLGVBQWUsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQThCO1FBQ2pELE1BQU0sTUFBTSxHQUFvQjtZQUM5QixPQUFPLEVBQUUsSUFBSTtZQUNiLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sRUFBRSxFQUFFO1lBQ1YsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILCtCQUErQjtZQUMvQixJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFF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SUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBZ0MsQ0FBQztRQUVqSCxPQUFPO1lBQ0wsaUJBQWlCO1lBQ2pCLGtCQUFrQjtZQUNsQixlQUFlO1lBQ2YsY0FBYztTQUNmLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1pZ3JhdGlvbiBNYW5hZ2VyIC0gSGFuZGxlcyBtaWdyYXRpb24gZnJvbSBsZWdhY3kgc3RydWN0dXJlIHRvIHBvcnRmb2xpbyBzdHJ1Y3R1cmVcbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgUG9ydGZvbGlvTWFuYWdlciB9IGZyb20gJy4vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE1pZ3JhdGlvblJlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIG1pZ3JhdGVkQ291bnQ6IG51bWJlcjtcbiAgZXJyb3JzOiBzdHJpbmdbXTtcbiAgYmFja2VkVXA6IGJvb2xlYW47XG4gIGJhY2t1cFBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRpb25NYW5hZ2VyIHtcbiAgcHJpdmF0ZSBwb3J0Zm9saW9NYW5hZ2VyOiBQb3J0Zm9saW9NYW5hZ2VyO1xuICBcbiAgY29uc3RydWN0b3IocG9ydGZvbGlvTWFuYWdlcjogUG9ydGZvbGlvTWFuYWdlcikge1xuICAgIHRoaXMucG9ydGZvbGlvTWFuYWdlciA9IHBvcnRmb2xpb01hbmFnZXI7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBpZiBtaWdyYXRpb24gaXMgbmVlZGVkXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgbmVlZHNNaWdyYXRpb24oKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgaGFzTGVnYWN5ID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmhhc0xlZ2FjeVBlcnNvbmFzKCk7XG4gICAgY29uc3QgcG9ydGZvbGlvRXhpc3RzID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmV4aXN0cygpO1xuICAgIFxuICAgIC8vIE5lZWQgbWlncmF0aW9uIGlmIHdlIGhhdmUgbGVnYWN5IHBlcnNvbmFzIGJ1dCBubyBwb3J0Zm9saW8geWV0XG4gICAgcmV0dXJuIGhhc0xlZ2FjeSAmJiAhcG9ydGZvbGlvRXhpc3RzO1xuICB9XG4gIFxuICAvKipcbiAgICogUGVyZm9ybSBtaWdyYXRpb24gZnJvbSBsZWdhY3kgdG8gcG9ydGZvbGlvIHN0cnVjdHVyZVxuICAgKi9cbiAgcHVibGljIGFzeW5jIG1pZ3JhdGUob3B0aW9ucz86IHsgYmFja3VwPzogYm9vbGVhbiB9KTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHQ6IE1pZ3JhdGlvblJlc3VsdCA9IHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBtaWdyYXRlZENvdW50OiAwLFxuICAgICAgZXJyb3JzOiBbXSxcbiAgICAgIGJhY2tlZFVwOiBmYWxzZVxuICAgIH07XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIG1pZ3JhdGlvbiBpcyBuZWVkZWRcbiAgICAgIGlmICghYXdhaXQgdGhpcy5uZWVkc01pZ3JhdGlvbigpKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdbTWlncmF0aW9uTWFuYWdlcl0gTm8gbWlncmF0aW9uIG5lZWRlZCcpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnW01pZ3JhdGlvbk1hbmFnZXJdIFN0YXJ0aW5nIG1pZ3JhdGlvbiBmcm9tIGxlZ2FjeSBwZXJzb25hcyB0byBwb3J0Zm9saW8gc3RydWN0dXJlJyk7XG4gICAgICBcbiAgICAgIC8vIENyZWF0ZSBiYWNrdXAgaWYgcmVxdWVzdGVkXG4gICAgICBpZiAob3B0aW9ucz8uYmFja3VwKSB7XG4gICAgICAgIGNvbnN0IGJhY2t1cFBhdGggPSBhd2FpdCB0aGlzLmNyZWF0ZUJhY2t1cCgpO1xuICAgICAgICByZXN1bHQuYmFja2VkVXAgPSB0cnVlO1xuICAgICAgICByZXN1bHQuYmFja3VwUGF0aCA9IGJhY2t1cFBhdGg7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbTWlncmF0aW9uTWFuYWdlcl0gQ3JlYXRlZCBiYWNrdXAgYXQ6ICR7YmFja3VwUGF0aH1gKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gSW5pdGlhbGl6ZSBwb3J0Zm9saW8gc3RydWN0dXJlXG4gICAgICBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuaW5pdGlhbGl6ZSgpO1xuICAgICAgXG4gICAgICAvLyBHZXQgbGVnYWN5IHBlcnNvbmFzXG4gICAgICBjb25zdCBsZWdhY3lEaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0TGVnYWN5UGVyc29uYXNEaXIoKTtcbiAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihsZWdhY3lEaXIpO1xuICAgICAgY29uc3QgcGVyc29uYUZpbGVzID0gZmlsZXMuZmlsdGVyKGZpbGUgPT4gZmlsZS5lbmRzV2l0aCgnLm1kJykpO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIEZvdW5kICR7cGVyc29uYUZpbGVzLmxlbmd0aH0gcGVyc29uYXMgdG8gbWlncmF0ZWApO1xuICAgICAgXG4gICAgICAvLyBNaWdyYXRlIGVhY2ggcGVyc29uYVxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHBlcnNvbmFGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHRoaXMubWlncmF0ZVBlcnNvbmEoZmlsZSk7XG4gICAgICAgICAgcmVzdWx0Lm1pZ3JhdGVkQ291bnQrKztcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zdCBlcnJvck1zZyA9IGBGYWlsZWQgdG8gbWlncmF0ZSAke2ZpbGV9OiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gO1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihgW01pZ3JhdGlvbk1hbmFnZXJdICR7ZXJyb3JNc2d9YCk7XG4gICAgICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGVycm9yTXNnKTtcbiAgICAgICAgICByZXN1bHQuc3VjY2VzcyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIElmIGFsbCBtaWdyYXRpb25zIHN1Y2Nlc3NmdWwsIG9wdGlvbmFsbHkgY2xlYW4gdXAgbGVnYWN5IGRpcmVjdG9yeVxuICAgICAgaWYgKHJlc3VsdC5zdWNjZXNzICYmIHJlc3VsdC5taWdyYXRlZENvdW50ID4gMCkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIFN1Y2Nlc3NmdWxseSBtaWdyYXRlZCAke3Jlc3VsdC5taWdyYXRlZENvdW50fSBwZXJzb25hc2ApO1xuICAgICAgICAvLyBOb3RlOiBXZSBkb24ndCBhdXRvbWF0aWNhbGx5IGRlbGV0ZSB0aGUgbGVnYWN5IGRpcmVjdG9yeVxuICAgICAgICAvLyBVc2VyIHNob3VsZCBtYW51YWxseSByZW1vdmUgaXQgYWZ0ZXIgY29uZmlybWluZyBtaWdyYXRpb24gc3VjY2Vzc1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJlc3VsdC5zdWNjZXNzID0gZmFsc2U7XG4gICAgICBjb25zdCBlcnJvck1zZyA9IGBNaWdyYXRpb24gZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gO1xuICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGVycm9yTXNnKTtcbiAgICAgIFxuICAgICAgLy8gTG9nIHdpdGggZnVsbCBlcnJvciBkZXRhaWxzIGluY2x1ZGluZyBzdGFjayB0cmFjZVxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBbTWlncmF0aW9uTWFuYWdlcl0gJHtlcnJvck1zZ31gLCB7IFxuICAgICAgICAgIHN0YWNrOiBlcnJvci5zdGFjayxcbiAgICAgICAgICBuYW1lOiBlcnJvci5uYW1lLFxuICAgICAgICAgIGNhdXNlOiBlcnJvci5jYXVzZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgW01pZ3JhdGlvbk1hbmFnZXJdICR7ZXJyb3JNc2d9YCwgeyByYXdFcnJvcjogZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNaWdyYXRlIGEgc2luZ2xlIHBlcnNvbmEgZmlsZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBtaWdyYXRlUGVyc29uYShmaWxlbmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTm9ybWFsaXplIGZpbGVuYW1lIHRvIHByZXZlbnQgVW5pY29kZSBhdHRhY2tzXG4gICAgY29uc3QgZmlsZW5hbWVWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoZmlsZW5hbWUpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRGaWxlbmFtZSA9IGZpbGVuYW1lVmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAobm9ybWFsaXplZEZpbGVuYW1lICE9PSBmaWxlbmFtZSkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBub3JtYWxpemVkIGZyb20gXCIke2ZpbGVuYW1lfVwiIHRvIFwiJHtub3JtYWxpemVkRmlsZW5hbWV9XCJgKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFmaWxlbmFtZVZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBoYXMgVW5pY29kZSBpc3N1ZXM6ICR7ZmlsZW5hbWVWYWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzPy5qb2luKCcsICcpfWApO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBsZWdhY3lQYXRoID0gcGF0aC5qb2luKHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRMZWdhY3lQZXJzb25hc0RpcigpLCBmaWxlbmFtZSk7XG4gICAgY29uc3QgbmV3UGF0aCA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRFbGVtZW50UGF0aChFbGVtZW50VHlwZS5QRVJTT05BLCBub3JtYWxpemVkRmlsZW5hbWUpO1xuICAgIFxuICAgIC8vIFJlYWQgdGhlIGNvbnRlbnRcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobGVnYWN5UGF0aCwgJ3V0Zi04Jyk7XG4gICAgXG4gICAgLy8gTm9ybWFsaXplIGNvbnRlbnQgdG8gcHJldmVudCBVbmljb2RlIGlzc3Vlc1xuICAgIGNvbnN0IGNvbnRlbnRWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoY29udGVudCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZENvbnRlbnQgPSBjb250ZW50VmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAoIWNvbnRlbnRWYWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBbTWlncmF0aW9uTWFuYWdlcl0gQ29udGVudCBoYXMgVW5pY29kZSBpc3N1ZXMgaW4gJHtmaWxlbmFtZX06ICR7Y29udGVudFZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgfVxuICAgIFxuICAgIC8vIFdyaXRlIHRvIG5ldyBsb2NhdGlvblxuICAgIGF3YWl0IGZzLndyaXRlRmlsZShuZXdQYXRoLCBub3JtYWxpemVkQ29udGVudCwgJ3V0Zi04Jyk7XG4gICAgXG4gICAgbG9nZ2VyLmRlYnVnKGBbTWlncmF0aW9uTWFuYWdlcl0gTWlncmF0ZWQ6ICR7ZmlsZW5hbWV9YCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDcmVhdGUgYmFja3VwIG9mIGxlZ2FjeSBwZXJzb25hc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVCYWNrdXAoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBsZWdhY3lEaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0TGVnYWN5UGVyc29uYXNEaXIoKTtcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCAnLScpO1xuICAgIGNvbnN0IGJhY2t1cERpciA9IGAke2xlZ2FjeURpcn1fYmFja3VwXyR7dGltZXN0YW1wfWA7XG4gICAgXG4gICAgLy8gQ3JlYXRlIGJhY2t1cCBkaXJlY3RvcnlcbiAgICBhd2FpdCBmcy5ta2RpcihiYWNrdXBEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIFxuICAgIC8vIENvcHkgYWxsIGZpbGVzXG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKGxlZ2FjeURpcik7XG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBjb25zdCBzcmNQYXRoID0gcGF0aC5qb2luKGxlZ2FjeURpciwgZmlsZSk7XG4gICAgICBjb25zdCBkZXN0UGF0aCA9IHBhdGguam9pbihiYWNrdXBEaXIsIGZpbGUpO1xuICAgICAgXG4gICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGZzLnN0YXQoc3JjUGF0aCk7XG4gICAgICBpZiAoc3RhdHMuaXNGaWxlKCkpIHtcbiAgICAgICAgYXdhaXQgZnMuY29weUZpbGUoc3JjUGF0aCwgZGVzdFBhdGgpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gYmFja3VwRGlyO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG1pZ3JhdGlvbiBzdGF0dXMgcmVwb3J0XG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0TWlncmF0aW9uU3RhdHVzKCk6IFByb21pc2U8e1xuICAgIGhhc0xlZ2FjeVBlcnNvbmFzOiBib29sZWFuO1xuICAgIGxlZ2FjeVBlcnNvbmFDb3VudDogbnVtYmVyO1xuICAgIHBvcnRmb2xpb0V4aXN0czogYm9vbGVhbjtcbiAgICBwb3J0Zm9saW9TdGF0czogUmVjb3JkPEVsZW1lbnRUeXBlLCBudW1iZXI+O1xuICB9PiB7XG4gICAgY29uc3QgaGFzTGVnYWN5UGVyc29uYXMgPSBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuaGFzTGVnYWN5UGVyc29uYXMoKTtcbiAgICBsZXQgbGVnYWN5UGVyc29uYUNvdW50ID0gMDtcbiAgICBcbiAgICBpZiAoaGFzTGVnYWN5UGVyc29uYXMpIHtcbiAgICAgIGNvbnN0IGxlZ2FjeURpciA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRMZWdhY3lQZXJzb25hc0RpcigpO1xuICAgICAgY29uc3QgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKGxlZ2FjeURpcik7XG4gICAgICBsZWdhY3lQZXJzb25hQ291bnQgPSBmaWxlcy5maWx0ZXIoZmlsZSA9PiBmaWxlLmVuZHNXaXRoKCcubWQnKSkubGVuZ3RoO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBwb3J0Zm9saW9FeGlzdHMgPSBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZXhpc3RzKCk7XG4gICAgY29uc3QgcG9ydGZvbGlvU3RhdHMgPSBwb3J0Zm9saW9FeGlzdHMgXG4gICAgICA/IGF3YWl0IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRTdGF0aXN0aWNzKClcbiAgICAgIDogT2JqZWN0LnZhbHVlcyhFbGVtZW50VHlwZSkucmVkdWNlKChhY2MsIHR5cGUpID0+ICh7IC4uLmFjYywgW3R5cGVdOiAwIH0pLCB7fSkgYXMgUmVjb3JkPEVsZW1lbnRUeXBlLCBudW1iZXI+O1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBoYXNMZWdhY3lQZXJzb25hcyxcbiAgICAgIGxlZ2FjeVBlcnNvbmFDb3VudCxcbiAgICAgIHBvcnRmb2xpb0V4aXN0cyxcbiAgICAgIHBvcnRmb2xpb1N0YXRzXG4gICAgfTtcbiAgfVxufSJdfQ==