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.

208 lines • 27.2 kB
#!/usr/bin/env node /** * Migration utility for legacy .md memory files * * FIX (#1206): Migrates old-format memory files to current YAML format * * Legacy formats found: * 1. YAML frontmatter + markdown content (.md files in root) * 2. Pure YAML with wrong extension (.md should be .yaml) * * Target format: * - Pure YAML files * - In date-organized folders (YYYY-MM-DD/) * - .yaml extension only */ import fs from 'node:fs/promises'; import path from 'node:path'; import os from 'node:os'; import { fileURLToPath } from 'node:url'; import { SecureYamlParser } from '../security/secureYamlParser.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; const __filename = fileURLToPath(import.meta.url); // Reserved for future use in migration utilities const _dirname = path.dirname(__filename); /** * Find all legacy .md files in memories directory */ async function findLegacyFiles(memoriesDir) { const files = await fs.readdir(memoriesDir); return files.filter(f => f.endsWith('.md') && !f.startsWith('.')); } /** * Parse legacy file and extract date */ async function parseLegacyFile(filePath) { const content = await fs.readFile(filePath, 'utf-8'); // Check if pure YAML or frontmatter const isYamlOnly = !content.startsWith('---\n') || (content.startsWith('---\n') && content.indexOf('\n---\n') === content.lastIndexOf('\n---\n')); let parsed; if (isYamlOnly) { // Pure YAML file parsed = SecureYamlParser.parse(`---\n${content}\n---\n`, { validateContent: false, validateFields: false // Legacy files may have non-standard formats }); } else { // Frontmatter + markdown parsed = SecureYamlParser.parse(content, { validateContent: false, validateFields: false // Legacy files may have non-standard formats }); } // Normalize version format (1.0 → 1.0.0) if (parsed.data?.version && typeof parsed.data.version === 'number') { parsed.data.version = `${parsed.data.version}.0`; } if (parsed.data?.metadata?.version && typeof parsed.data.metadata.version === 'number') { parsed.data.metadata.version = `${parsed.data.metadata.version}.0`; } // Extract creation date from metadata const created = parsed.data?.metadata?.created || parsed.data?.created || new Date().toISOString(); const createdDate = created.split('T')[0]; // YYYY-MM-DD return { content: parsed.data, createdDate, isYamlOnly }; } /** * Migrate a single legacy file */ async function migrateLegacyFile(memoriesDir, filename, dryRun = true) { try { const oldPath = path.join(memoriesDir, filename); const { content, createdDate, isYamlOnly } = await parseLegacyFile(oldPath); // Generate new filename (remove .md, add .yaml) const baseName = path.basename(filename, '.md'); const newFilename = `${baseName}.yaml`; // Create date folder path const dateFolder = path.join(memoriesDir, createdDate); const newPath = path.join(dateFolder, newFilename); // Check if target already exists try { await fs.access(newPath); return { file: filename, status: 'skipped', reason: 'Target file already exists', newPath }; } catch { // Target doesn't exist, proceed } if (!dryRun) { // Create date folder if needed await fs.mkdir(dateFolder, { recursive: true }); // Write new YAML file const yamlContent = Object.entries(content) .map(([key, value]) => { const yamlValue = typeof value === 'string' ? value : JSON.stringify(value, null, 2).split('\n').map((line, i) => i === 0 ? line : ` ${line}`).join('\n'); return `${key}: ${yamlValue}`; }) .join('\n'); await fs.writeFile(newPath, yamlContent, 'utf-8'); // Archive old file (don't delete, move to .archive/) const archiveDir = path.join(memoriesDir, '.archive'); await fs.mkdir(archiveDir, { recursive: true }); const archivePath = path.join(archiveDir, filename); await fs.rename(oldPath, archivePath); } return { file: filename, status: 'success', reason: isYamlOnly ? 'Migrated pure YAML' : 'Migrated frontmatter+markdown', newPath }; } catch (error) { return { file: filename, status: 'error', reason: error instanceof Error ? error.message : String(error) }; } } /** * Main migration function */ async function migrateAll(memoriesDir, dryRun = true) { console.log(`\nšŸ”„ Legacy Memory Migration Tool`); console.log(`Mode: ${dryRun ? 'DRY RUN (no changes)' : 'LIVE (will modify files)'}`); console.log(`Directory: ${memoriesDir}\n`); const legacyFiles = await findLegacyFiles(memoriesDir); if (legacyFiles.length === 0) { console.log('āœ… No legacy .md files found'); return; } console.log(`Found ${legacyFiles.length} legacy files:\n`); const results = []; for (const file of legacyFiles) { const result = await migrateLegacyFile(memoriesDir, file, dryRun); results.push(result); // FIX (SonarCloud S3358): Extract nested ternary to if-else let icon; if (result.status === 'success') { icon = 'āœ…'; } else if (result.status === 'skipped') { icon = 'ā­ļø'; } else { icon = 'āŒ'; } console.log(`${icon} ${file}`); if (result.reason) console.log(` ${result.reason}`); if (result.newPath) console.log(` → ${result.newPath}`); console.log(); } // Summary const success = results.filter(r => r.status === 'success').length; const skipped = results.filter(r => r.status === 'skipped').length; const errors = results.filter(r => r.status === 'error').length; console.log('\nšŸ“Š Summary:'); console.log(` Success: ${success}`); console.log(` Skipped: ${skipped}`); console.log(` Errors: ${errors}`); if (dryRun && success > 0) { console.log('\nšŸ’” Run with --live to apply changes'); } } // CLI if (import.meta.url === `file://${process.argv[1]}`) { // FIX (DMCP-SEC-004): Normalize user input to prevent Unicode normalization attacks const userProvidedDir = process.argv[2]; let memoriesDir; if (userProvidedDir) { const validation = UnicodeValidator.normalize(userProvidedDir); if (!validation.isValid) { console.error(`āŒ Invalid path: ${validation.detectedIssues?.join(', ')}`); process.exit(1); } memoriesDir = validation.normalizedContent; } else { // FIX (SonarCloud): Use os.homedir() instead of process.env.HOME for reliability memoriesDir = path.join(os.homedir(), '.dollhouse/portfolio/memories'); } const dryRun = !process.argv.includes('--live'); // FIX (SonarCloud S7785): Use top-level await instead of promise chain try { await migrateAll(memoriesDir, dryRun); } catch (error) { console.error(error); process.exit(1); } } export { migrateAll, migrateLegacyFile, findLegacyFiles }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0ZS1sZWdhY3ktbWVtb3JpZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvbWlncmF0ZS1sZWdhY3ktbWVtb3JpZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFFSCxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsQyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFFOUUsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDbEQsaURBQWlEO0FBQ2pELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7QUFTMUM7O0dBRUc7QUFDSCxLQUFLLFVBQVUsZUFBZSxDQUFDLFdBQW1CO0lBQ2hELE1BQU0sS0FBSyxHQUFHLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUM1QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQ3BFLENBQUM7QUFFRDs7R0FFRztBQUNILEtBQUssVUFBVSxlQUFlLENBQUMsUUFBZ0I7SUFLN0MsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUVyRCxvQ0FBb0M7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QUFFLENBQUM7WUFDeEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsVUFBVSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQztRQUNELFdBQVcsR0FBRyxVQUFVLENBQUMsaUJBQWlCLENBQUM7SUFDN0MsQ0FBQztTQUFNLENBQUM7UUFDTixpRkFBaUY7UUFDakYsV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLCtCQUErQixDQUFDLENBQUM7SUFDekUsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFaEQsdUVBQXVFO0lBQ3ZFLElBQUksQ0FBQztRQUNILE1BQU0sVUFBVSxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDO0FBQ0gsQ0FBQztBQUVELE9BQU8sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsZUFBZSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG4vKipcbiAqIE1pZ3JhdGlvbiB1dGlsaXR5IGZvciBsZWdhY3kgLm1kIG1lbW9yeSBmaWxlc1xuICpcbiAqIEZJWCAoIzEyMDYpOiBNaWdyYXRlcyBvbGQtZm9ybWF0IG1lbW9yeSBmaWxlcyB0byBjdXJyZW50IFlBTUwgZm9ybWF0XG4gKlxuICogTGVnYWN5IGZvcm1hdHMgZm91bmQ6XG4gKiAxLiBZQU1MIGZyb250bWF0dGVyICsgbWFya2Rvd24gY29udGVudCAoLm1kIGZpbGVzIGluIHJvb3QpXG4gKiAyLiBQdXJlIFlBTUwgd2l0aCB3cm9uZyBleHRlbnNpb24gKC5tZCBzaG91bGQgYmUgLnlhbWwpXG4gKlxuICogVGFyZ2V0IGZvcm1hdDpcbiAqIC0gUHVyZSBZQU1MIGZpbGVzXG4gKiAtIEluIGRhdGUtb3JnYW5pemVkIGZvbGRlcnMgKFlZWVktTU0tREQvKVxuICogLSAueWFtbCBleHRlbnNpb24gb25seVxuICovXG5cbmltcG9ydCBmcyBmcm9tICdub2RlOmZzL3Byb21pc2VzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgb3MgZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAnbm9kZTp1cmwnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5cbmNvbnN0IF9fZmlsZW5hbWUgPSBmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCk7XG4vLyBSZXNlcnZlZCBmb3IgZnV0dXJlIHVzZSBpbiBtaWdyYXRpb24gdXRpbGl0aWVzXG5jb25zdCBfZGlybmFtZSA9IHBhdGguZGlybmFtZShfX2ZpbGVuYW1lKTtcblxuaW50ZXJmYWNlIE1pZ3JhdGlvblJlc3VsdCB7XG4gIGZpbGU6IHN0cmluZztcbiAgc3RhdHVzOiAnc3VjY2VzcycgfCAnc2tpcHBlZCcgfCAnZXJyb3InO1xuICByZWFzb24/OiBzdHJpbmc7XG4gIG5ld1BhdGg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmluZCBhbGwgbGVnYWN5IC5tZCBmaWxlcyBpbiBtZW1vcmllcyBkaXJlY3RvcnlcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmluZExlZ2FjeUZpbGVzKG1lbW9yaWVzRGlyOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihtZW1vcmllc0Rpcik7XG4gIHJldHVybiBmaWxlcy5maWx0ZXIoZiA9PiBmLmVuZHNXaXRoKCcubWQnKSAmJiAhZi5zdGFydHNXaXRoKCcuJykpO1xufVxuXG4vKipcbiAqIFBhcnNlIGxlZ2FjeSBmaWxlIGFuZCBleHRyYWN0IGRhdGVcbiAqL1xuYXN5bmMgZnVuY3Rpb24gcGFyc2VMZWdhY3lGaWxlKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgY29udGVudDogYW55O1xuICBjcmVhdGVkRGF0ZTogc3RyaW5nO1xuICBpc1lhbWxPbmx5OiBib29sZWFuO1xufT4ge1xuICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZVBhdGgsICd1dGYtOCcpO1xuXG4gIC8vIENoZWNrIGlmIHB1cmUgWUFNTCBvciBmcm9udG1hdHRlclxuICBjb25zdCBpc1lhbWxPbmx5ID0gIWNvbnRlbnQuc3RhcnRzV2l0aCgnLS0tXFxuJykgfHxcbiAgICAoY29udGVudC5zdGFydHNXaXRoKCctLS1cXG4nKSAmJiBjb250ZW50LmluZGV4T2YoJ1xcbi0tLVxcbicpID09PSBjb250ZW50Lmxhc3RJbmRleE9mKCdcXG4tLS1cXG4nKSk7XG5cbiAgbGV0IHBhcnNlZDogYW55O1xuICBpZiAoaXNZYW1sT25seSkge1xuICAgIC8vIFB1cmUgWUFNTCBmaWxlXG4gICAgcGFyc2VkID0gU2VjdXJlWWFtbFBhcnNlci5wYXJzZShgLS0tXFxuJHtjb250ZW50fVxcbi0tLVxcbmAsIHtcbiAgICAgIHZhbGlkYXRlQ29udGVudDogZmFsc2UsXG4gICAgICB2YWxpZGF0ZUZpZWxkczogZmFsc2UgIC8vIExlZ2FjeSBmaWxlcyBtYXkgaGF2ZSBub24tc3RhbmRhcmQgZm9ybWF0c1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIC8vIEZyb250bWF0dGVyICsgbWFya2Rvd25cbiAgICBwYXJzZWQgPSBTZWN1cmVZYW1sUGFyc2VyLnBhcnNlKGNvbnRlbnQsIHtcbiAgICAgIHZhbGlkYXRlQ29udGVudDogZmFsc2UsXG4gICAgICB2YWxpZGF0ZUZpZWxkczogZmFsc2UgIC8vIExlZ2FjeSBmaWxlcyBtYXkgaGF2ZSBub24tc3RhbmRhcmQgZm9ybWF0c1xuICAgIH0pO1xuICB9XG5cbiAgLy8gTm9ybWFsaXplIHZlcnNpb24gZm9ybWF0ICgxLjAg4oaSIDEuMC4wKVxuICBpZiAocGFyc2VkLmRhdGE/LnZlcnNpb24gJiYgdHlwZW9mIHBhcnNlZC5kYXRhLnZlcnNpb24gPT09ICdudW1iZXInKSB7XG4gICAgcGFyc2VkLmRhdGEudmVyc2lvbiA9IGAke3BhcnNlZC5kYXRhLnZlcnNpb259LjBgO1xuICB9XG4gIGlmIChwYXJzZWQuZGF0YT8ubWV0YWRhdGE/LnZlcnNpb24gJiYgdHlwZW9mIHBhcnNlZC5kYXRhLm1ldGFkYXRhLnZlcnNpb24gPT09ICdudW1iZXInKSB7XG4gICAgcGFyc2VkLmRhdGEubWV0YWRhdGEudmVyc2lvbiA9IGAke3BhcnNlZC5kYXRhLm1ldGFkYXRhLnZlcnNpb259LjBgO1xuICB9XG5cbiAgLy8gRXh0cmFjdCBjcmVhdGlvbiBkYXRlIGZyb20gbWV0YWRhdGFcbiAgY29uc3QgY3JlYXRlZCA9IHBhcnNlZC5kYXRhPy5tZXRhZGF0YT8uY3JlYXRlZCB8fFxuICAgICAgICAgICAgICAgICAgcGFyc2VkLmRhdGE/LmNyZWF0ZWQgfHxcbiAgICAgICAgICAgICAgICAgIG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcblxuICBjb25zdCBjcmVhdGVkRGF0ZSA9IGNyZWF0ZWQuc3BsaXQoJ1QnKVswXTsgLy8gWVlZWS1NTS1ERFxuXG4gIHJldHVybiB7XG4gICAgY29udGVudDogcGFyc2VkLmRhdGEsXG4gICAgY3JlYXRlZERhdGUsXG4gICAgaXNZYW1sT25seVxuICB9O1xufVxuXG4vKipcbiAqIE1pZ3JhdGUgYSBzaW5nbGUgbGVnYWN5IGZpbGVcbiAqL1xuYXN5bmMgZnVuY3Rpb24gbWlncmF0ZUxlZ2FjeUZpbGUoXG4gIG1lbW9yaWVzRGlyOiBzdHJpbmcsXG4gIGZpbGVuYW1lOiBzdHJpbmcsXG4gIGRyeVJ1bjogYm9vbGVhbiA9IHRydWVcbik6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gIHRyeSB7XG4gICAgY29uc3Qgb2xkUGF0aCA9IHBhdGguam9pbihtZW1vcmllc0RpciwgZmlsZW5hbWUpO1xuICAgIGNvbnN0IHsgY29udGVudCwgY3JlYXRlZERhdGUsIGlzWWFtbE9ubHkgfSA9IGF3YWl0IHBhcnNlTGVnYWN5RmlsZShvbGRQYXRoKTtcblxuICAgIC8vIEdlbmVyYXRlIG5ldyBmaWxlbmFtZSAocmVtb3ZlIC5tZCwgYWRkIC55YW1sKVxuICAgIGNvbnN0IGJhc2VOYW1lID0gcGF0aC5iYXNlbmFtZShmaWxlbmFtZSwgJy5tZCcpO1xuICAgIGNvbnN0IG5ld0ZpbGVuYW1lID0gYCR7YmFzZU5hbWV9LnlhbWxgO1xuXG4gICAgLy8gQ3JlYXRlIGRhdGUgZm9sZGVyIHBhdGhcbiAgICBjb25zdCBkYXRlRm9sZGVyID0gcGF0aC5qb2luKG1lbW9yaWVzRGlyLCBjcmVhdGVkRGF0ZSk7XG4gICAgY29uc3QgbmV3UGF0aCA9IHBhdGguam9pbihkYXRlRm9sZGVyLCBuZXdGaWxlbmFtZSk7XG5cbiAgICAvLyBDaGVjayBpZiB0YXJnZXQgYWxyZWFkeSBleGlzdHNcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZnMuYWNjZXNzKG5ld1BhdGgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmlsZTogZmlsZW5hbWUsXG4gICAgICAgIHN0YXR1czogJ3NraXBwZWQnLFxuICAgICAgICByZWFzb246ICdUYXJnZXQgZmlsZSBhbHJlYWR5IGV4aXN0cycsXG4gICAgICAgIG5ld1BhdGhcbiAgICAgIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBUYXJnZXQgZG9lc24ndCBleGlzdCwgcHJvY2VlZFxuICAgIH1cblxuICAgIGlmICghZHJ5UnVuKSB7XG4gICAgICAvLyBDcmVhdGUgZGF0ZSBmb2xkZXIgaWYgbmVlZGVkXG4gICAgICBhd2FpdCBmcy5ta2RpcihkYXRlRm9sZGVyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAgICAgLy8gV3JpdGUgbmV3IFlBTUwgZmlsZVxuICAgICAgY29uc3QgeWFtbENvbnRlbnQgPSBPYmplY3QuZW50cmllcyhjb250ZW50KVxuICAgICAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgICAgICBjb25zdCB5YW1sVmFsdWUgPSB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnXG4gICAgICAgICAgICA/IHZhbHVlXG4gICAgICAgICAgICA6IEpTT04uc3RyaW5naWZ5KHZhbHVlLCBudWxsLCAyKS5zcGxpdCgnXFxuJykubWFwKChsaW5lLCBpKSA9PiBpID09PSAwID8gbGluZSA6IGAgICR7bGluZX1gKS5qb2luKCdcXG4nKTtcbiAgICAgICAgICByZXR1cm4gYCR7a2V5fTogJHt5YW1sVmFsdWV9YDtcbiAgICAgICAgfSlcbiAgICAgICAgLmpvaW4oJ1xcbicpO1xuXG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUobmV3UGF0aCwgeWFtbENvbnRlbnQsICd1dGYtOCcpO1xuXG4gICAgICAvLyBBcmNoaXZlIG9sZCBmaWxlIChkb24ndCBkZWxldGUsIG1vdmUgdG8gLmFyY2hpdmUvKVxuICAgICAgY29uc3QgYXJjaGl2ZURpciA9IHBhdGguam9pbihtZW1vcmllc0RpciwgJy5hcmNoaXZlJyk7XG4gICAgICBhd2FpdCBmcy5ta2RpcihhcmNoaXZlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIGNvbnN0IGFyY2hpdmVQYXRoID0gcGF0aC5qb2luKGFyY2hpdmVEaXIsIGZpbGVuYW1lKTtcbiAgICAgIGF3YWl0IGZzLnJlbmFtZShvbGRQYXRoLCBhcmNoaXZlUGF0aCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbGU6IGZpbGVuYW1lLFxuICAgICAgc3RhdHVzOiAnc3VjY2VzcycsXG4gICAgICByZWFzb246IGlzWWFtbE9ubHkgPyAnTWlncmF0ZWQgcHVyZSBZQU1MJyA6ICdNaWdyYXRlZCBmcm9udG1hdHRlcittYXJrZG93bicsXG4gICAgICBuZXdQYXRoXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgZmlsZTogZmlsZW5hbWUsXG4gICAgICBzdGF0dXM6ICdlcnJvcicsXG4gICAgICByZWFzb246IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBNYWluIG1pZ3JhdGlvbiBmdW5jdGlvblxuICovXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlQWxsKG1lbW9yaWVzRGlyOiBzdHJpbmcsIGRyeVJ1bjogYm9vbGVhbiA9IHRydWUpIHtcbiAgY29uc29sZS5sb2coYFxcbvCflIQgTGVnYWN5IE1lbW9yeSBNaWdyYXRpb24gVG9vbGApO1xuICBjb25zb2xlLmxvZyhgTW9kZTogJHtkcnlSdW4gPyAnRFJZIFJVTiAobm8gY2hhbmdlcyknIDogJ0xJVkUgKHdpbGwgbW9kaWZ5IGZpbGVzKSd9YCk7XG4gIGNvbnNvbGUubG9nKGBEaXJlY3Rvcnk6ICR7bWVtb3JpZXNEaXJ9XFxuYCk7XG5cbiAgY29uc3QgbGVnYWN5RmlsZXMgPSBhd2FpdCBmaW5kTGVnYWN5RmlsZXMobWVtb3JpZXNEaXIpO1xuXG4gIGlmIChsZWdhY3lGaWxlcy5sZW5ndGggPT09IDApIHtcbiAgICBjb25zb2xlLmxvZygn4pyFIE5vIGxlZ2FjeSAubWQgZmlsZXMgZm91bmQnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zb2xlLmxvZyhgRm91bmQgJHtsZWdhY3lGaWxlcy5sZW5ndGh9IGxlZ2FjeSBmaWxlczpcXG5gKTtcblxuICBjb25zdCByZXN1bHRzOiBNaWdyYXRpb25SZXN1bHRbXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgZmlsZSBvZiBsZWdhY3lGaWxlcykge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG1pZ3JhdGVMZWdhY3lGaWxlKG1lbW9yaWVzRGlyLCBmaWxlLCBkcnlSdW4pO1xuICAgIHJlc3VsdHMucHVzaChyZXN1bHQpO1xuXG4gICAgLy8gRklYIChTb25hckNsb3VkIFMzMzU4KTogRXh0cmFjdCBuZXN0ZWQgdGVybmFyeSB0byBpZi1lbHNlXG4gICAgbGV0IGljb246IHN0cmluZztcbiAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ3N1Y2Nlc3MnKSB7XG4gICAgICBpY29uID0gJ+KchSc7XG4gICAgfSBlbHNlIGlmIChyZXN1bHQuc3RhdHVzID09PSAnc2tpcHBlZCcpIHtcbiAgICAgIGljb24gPSAn4o+t77iPJztcbiAgICB9IGVsc2Uge1xuICAgICAgaWNvbiA9ICfinYwnO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGAke2ljb259ICR7ZmlsZX1gKTtcbiAgICBpZiAocmVzdWx0LnJlYXNvbikgY29uc29sZS5sb2coYCAgICR7cmVzdWx0LnJlYXNvbn1gKTtcbiAgICBpZiAocmVzdWx0Lm5ld1BhdGgpIGNvbnNvbGUubG9nKGAgICDihpIgJHtyZXN1bHQubmV3UGF0aH1gKTtcbiAgICBjb25zb2xlLmxvZygpO1xuICB9XG5cbiAgLy8gU3VtbWFyeVxuICBjb25zdCBzdWNjZXNzID0gcmVzdWx0cy5maWx0ZXIociA9PiByLnN0YXR1cyA9PT0gJ3N1Y2Nlc3MnKS5sZW5ndGg7XG4gIGNvbnN0IHNraXBwZWQgPSByZXN1bHRzLmZpbHRlcihyID0+IHIuc3RhdHVzID09PSAnc2tpcHBlZCcpLmxlbmd0aDtcbiAgY29uc3QgZXJyb3JzID0gcmVzdWx0cy5maWx0ZXIociA9PiByLnN0YXR1cyA9PT0gJ2Vycm9yJykubGVuZ3RoO1xuXG4gIGNvbnNvbGUubG9nKCdcXG7wn5OKIFN1bW1hcnk6Jyk7XG4gIGNvbnNvbGUubG9nKGAgICBTdWNjZXNzOiAke3N1Y2Nlc3N9YCk7XG4gIGNvbnNvbGUubG9nKGAgICBTa2lwcGVkOiAke3NraXBwZWR9YCk7XG4gIGNvbnNvbGUubG9nKGAgICBFcnJvcnM6ICR7ZXJyb3JzfWApO1xuXG4gIGlmIChkcnlSdW4gJiYgc3VjY2VzcyA+IDApIHtcbiAgICBjb25zb2xlLmxvZygnXFxu8J+SoSBSdW4gd2l0aCAtLWxpdmUgdG8gYXBwbHkgY2hhbmdlcycpO1xuICB9XG59XG5cbi8vIENMSVxuaWYgKGltcG9ydC5tZXRhLnVybCA9PT0gYGZpbGU6Ly8ke3Byb2Nlc3MuYXJndlsxXX1gKSB7XG4gIC8vIEZJWCAoRE1DUC1TRUMtMDA0KTogTm9ybWFsaXplIHVzZXIgaW5wdXQgdG8gcHJldmVudCBVbmljb2RlIG5vcm1hbGl6YXRpb24gYXR0YWNrc1xuICBjb25zdCB1c2VyUHJvdmlkZWREaXIgPSBwcm9jZXNzLmFyZ3ZbMl07XG4gIGxldCBtZW1vcmllc0Rpcjogc3RyaW5nO1xuXG4gIGlmICh1c2VyUHJvdmlkZWREaXIpIHtcbiAgICBjb25zdCB2YWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodXNlclByb3ZpZGVkRGlyKTtcbiAgICBpZiAoIXZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgY29uc29sZS5lcnJvcihg4p2MIEludmFsaWQgcGF0aDogJHt2YWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzPy5qb2luKCcsICcpfWApO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgICBtZW1vcmllc0RpciA9IHZhbGlkYXRpb24ubm9ybWFsaXplZENvbnRlbnQ7XG4gIH0gZWxzZSB7XG4gICAgLy8gRklYIChTb25hckNsb3VkKTogVXNlIG9zLmhvbWVkaXIoKSBpbnN0ZWFkIG9mIHByb2Nlc3MuZW52LkhPTUUgZm9yIHJlbGlhYmlsaXR5XG4gICAgbWVtb3JpZXNEaXIgPSBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLmRvbGxob3VzZS9wb3J0Zm9saW8vbWVtb3JpZXMnKTtcbiAgfVxuXG4gIGNvbnN0IGRyeVJ1biA9ICFwcm9jZXNzLmFyZ3YuaW5jbHVkZXMoJy0tbGl2ZScpO1xuXG4gIC8vIEZJWCAoU29uYXJDbG91ZCBTNzc4NSk6IFVzZSB0b3AtbGV2ZWwgYXdhaXQgaW5zdGVhZCBvZiBwcm9taXNlIGNoYWluXG4gIHRyeSB7XG4gICAgYXdhaXQgbWlncmF0ZUFsbChtZW1vcmllc0RpciwgZHJ5UnVuKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbn1cblxuZXhwb3J0IHsgbWlncmF0ZUFsbCwgbWlncmF0ZUxlZ2FjeUZpbGUsIGZpbmRMZWdhY3lGaWxlcyB9OyJdfQ==