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.

152 lines 21.4 kB
/** * Search for content in the collection */ import { CollectionCache } from '../cache/CollectionCache.js'; import { CollectionSeeder } from './CollectionSeeder.js'; import { logger } from '../utils/logger.js'; import { normalizeSearchTerm, validateSearchQuery } from '../utils/searchUtils.js'; export class CollectionSearch { githubClient; collectionCache; searchBaseUrl = 'https://api.github.com/search/code'; constructor(githubClient, collectionCache) { this.githubClient = githubClient; this.collectionCache = collectionCache || new CollectionCache(); } /** * Search collection for content matching query * Falls back to cached data when GitHub API is not available or not authenticated */ async searchCollection(query) { // Validate search query for security try { validateSearchQuery(query, 1000); } catch (error) { logger.warn(`Invalid search query: ${error}`); return []; } try { // First, try GitHub API search if authenticated const searchUrl = `${this.searchBaseUrl}?q=${encodeURIComponent(query)}+repo:DollhouseMCP/collection+path:library+extension:md`; const data = await this.githubClient.fetchFromGitHub(searchUrl, false); // Don't require auth for search if (data.items && Array.isArray(data.items)) { logger.debug(`Found ${data.items.length} items via GitHub API search`); // Update cache with fresh data from API await this.updateCacheFromGitHubItems(data.items); return data.items; } return []; } catch (error) { logger.debug(`GitHub API search failed, falling back to cache: ${error}`); // Fallback to cached search return this.searchFromCache(query); } } /** * Search cached collection items */ async searchFromCache(query) { try { // Try to load from cache first const cachedItems = await this.collectionCache.searchCache(query); if (cachedItems.length > 0) { logger.debug(`Found ${cachedItems.length} items from cache`); return this.convertCacheItemsToGitHubFormat(cachedItems); } // If cache is empty or no results, use seed data const seedItems = this.searchSeedData(query); if (seedItems.length > 0) { logger.debug(`Found ${seedItems.length} items from seed data`); // Save seed data to cache for future use await this.collectionCache.saveCache(CollectionSeeder.getSeedData()); return this.convertCacheItemsToGitHubFormat(seedItems); } logger.debug('No items found in cache or seed data'); return []; } catch (error) { logger.error(`Cache search failed: ${error}`); // Last resort: search seed data without cache const seedItems = this.searchSeedData(query); logger.debug(`Fallback to seed data found ${seedItems.length} items`); return this.convertCacheItemsToGitHubFormat(seedItems); } } /** * Search seed data for matching items with fuzzy matching */ searchSeedData(query) { const seedData = CollectionSeeder.getSeedData(); const normalizedQuery = normalizeSearchTerm(query); return seedData.filter(item => { const normalizedName = normalizeSearchTerm(item.name); const normalizedPath = normalizeSearchTerm(item.path); return normalizedName.includes(normalizedQuery) || normalizedPath.includes(normalizedQuery); }); } /** * Convert cache items to GitHub API format for consistent response structure */ convertCacheItemsToGitHubFormat(cacheItems) { return cacheItems.map(item => ({ name: item.name, path: item.path, sha: item.sha, url: `https://api.github.com/repos/DollhouseMCP/collection/contents/${item.path}`, html_url: `https://github.com/DollhouseMCP/collection/blob/main/${item.path}`, repository: { name: 'collection', full_name: 'DollhouseMCP/collection' } })); } /** * Update cache with fresh data from GitHub API items */ async updateCacheFromGitHubItems(githubItems) { try { const cacheItems = githubItems.map(item => ({ name: item.name, path: item.path, sha: item.sha, last_modified: new Date().toISOString() })); await this.collectionCache.saveCache(cacheItems); logger.debug(`Updated cache with ${cacheItems.length} items from GitHub API`); } catch (error) { logger.debug(`Failed to update cache: ${error}`); // Don't throw - cache update failures shouldn't break functionality } } /** * Format search results */ formatSearchResults(items, query, personaIndicator = '') { if (items.length === 0) { return `${personaIndicator}🔍 No content found for query: "${query}"`; } const textParts = [`${personaIndicator}🔍 **Search Results for "${query}"** (${items.length} found)\n\n`]; items.forEach((item) => { // Extract content type from path (library/personas/creative/writer.md -> personas) const pathParts = item.path.split('/'); const contentType = pathParts[1] || 'content'; const contentIcons = { 'personas': '🎭', 'skills': '🛠️', 'agents': '🤖', 'prompts': '💬', 'templates': '📄', 'tools': '🔧', 'ensembles': '🎼' }; const icon = contentIcons[contentType] || '📄'; textParts.push(` ${icon} **${item.name.replace('.md', '')}**\n`, ` 📂 Path: ${item.path}\n`, ` 📥 Install: \`install_content "${item.path}"\`\n`, ` 👁️ Details: \`get_collection_content "${item.path}"\`\n\n`); }); return textParts.join(''); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29sbGVjdGlvblNlYXJjaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL0NvbGxlY3Rpb25TZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFHSCxPQUFPLEVBQUUsZUFBZSxFQUFrQixNQUFNLDZCQUE2QixDQUFDO0FBQzlFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVuRixNQUFNLE9BQU8sZ0JBQWdCO0lBQ25CLFlBQVksQ0FBZTtJQUMzQixlQUFlLENBQWtCO0lBQ2pDLGFBQWEsR0FBRyxvQ0FBb0MsQ0FBQztJQUU3RCxZQUFZLFlBQTBCLEVBQUUsZUFBaUM7UUFDdkUsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDakMsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLElBQUksSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUNsRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEtBQWE7UUFDbEMscUNBQXFDO1FBQ3JDLElBQUksQ0FBQztZQUNILG1CQUFtQixDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNuQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDOUMsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsZ0RBQWdEO1lBQ2hELE1BQU0sU0FBUyxHQUFHLEdBQUcsSUFBSSxDQUFDLGFBQWEsTUFBTSxrQkFBa0IsQ0FBQyxLQUFLLENBQUMseURBQXlELENBQUM7WUFDaEksTUFB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QUksQ0FBQyxJQUFJLElBQUksRUFDL0Isd0NBQXdDLElBQUksQ0FBQyxJQUFJLE9BQU8sRUFDeEQsZ0RBQWdELElBQUksQ0FBQyxJQUFJLFNBQVMsQ0FDbkUsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VhcmNoIGZvciBjb250ZW50IGluIHRoZSBjb2xsZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgR2l0SHViQ2xpZW50IH0gZnJvbSAnLi9HaXRIdWJDbGllbnQuanMnO1xuaW1wb3J0IHsgQ29sbGVjdGlvbkNhY2hlLCBDb2xsZWN0aW9uSXRlbSB9IGZyb20gJy4uL2NhY2hlL0NvbGxlY3Rpb25DYWNoZS5qcyc7XG5pbXBvcnQgeyBDb2xsZWN0aW9uU2VlZGVyIH0gZnJvbSAnLi9Db2xsZWN0aW9uU2VlZGVyLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBub3JtYWxpemVTZWFyY2hUZXJtLCB2YWxpZGF0ZVNlYXJjaFF1ZXJ5IH0gZnJvbSAnLi4vdXRpbHMvc2VhcmNoVXRpbHMuanMnO1xuXG5leHBvcnQgY2xhc3MgQ29sbGVjdGlvblNlYXJjaCB7XG4gIHByaXZhdGUgZ2l0aHViQ2xpZW50OiBHaXRIdWJDbGllbnQ7XG4gIHByaXZhdGUgY29sbGVjdGlvbkNhY2hlOiBDb2xsZWN0aW9uQ2FjaGU7XG4gIHByaXZhdGUgc2VhcmNoQmFzZVVybCA9ICdodHRwczovL2FwaS5naXRodWIuY29tL3NlYXJjaC9jb2RlJztcbiAgXG4gIGNvbnN0cnVjdG9yKGdpdGh1YkNsaWVudDogR2l0SHViQ2xpZW50LCBjb2xsZWN0aW9uQ2FjaGU/OiBDb2xsZWN0aW9uQ2FjaGUpIHtcbiAgICB0aGlzLmdpdGh1YkNsaWVudCA9IGdpdGh1YkNsaWVudDtcbiAgICB0aGlzLmNvbGxlY3Rpb25DYWNoZSA9IGNvbGxlY3Rpb25DYWNoZSB8fCBuZXcgQ29sbGVjdGlvbkNhY2hlKCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggY29sbGVjdGlvbiBmb3IgY29udGVudCBtYXRjaGluZyBxdWVyeVxuICAgKiBGYWxscyBiYWNrIHRvIGNhY2hlZCBkYXRhIHdoZW4gR2l0SHViIEFQSSBpcyBub3QgYXZhaWxhYmxlIG9yIG5vdCBhdXRoZW50aWNhdGVkXG4gICAqL1xuICBhc3luYyBzZWFyY2hDb2xsZWN0aW9uKHF1ZXJ5OiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgLy8gVmFsaWRhdGUgc2VhcmNoIHF1ZXJ5IGZvciBzZWN1cml0eVxuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZVNlYXJjaFF1ZXJ5KHF1ZXJ5LCAxMDAwKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLndhcm4oYEludmFsaWQgc2VhcmNoIHF1ZXJ5OiAke2Vycm9yfWApO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgLy8gRmlyc3QsIHRyeSBHaXRIdWIgQVBJIHNlYXJjaCBpZiBhdXRoZW50aWNhdGVkXG4gICAgICBjb25zdCBzZWFyY2hVcmwgPSBgJHt0aGlzLnNlYXJjaEJhc2VVcmx9P3E9JHtlbmNvZGVVUklDb21wb25lbnQocXVlcnkpfStyZXBvOkRvbGxob3VzZU1DUC9jb2xsZWN0aW9uK3BhdGg6bGlicmFyeStleHRlbnNpb246bWRgO1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMuZ2l0aHViQ2xpZW50LmZldGNoRnJvbUdpdEh1YihzZWFyY2hVcmwsIGZhbHNlKTsgLy8gRG9uJ3QgcmVxdWlyZSBhdXRoIGZvciBzZWFyY2hcbiAgICAgIFxuICAgICAgaWYgKGRhdGEuaXRlbXMgJiYgQXJyYXkuaXNBcnJheShkYXRhLml0ZW1zKSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7ZGF0YS5pdGVtcy5sZW5ndGh9IGl0ZW1zIHZpYSBHaXRIdWIgQVBJIHNlYXJjaGApO1xuICAgICAgICBcbiAgICAgICAgLy8gVXBkYXRlIGNhY2hlIHdpdGggZnJlc2ggZGF0YSBmcm9tIEFQSVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZUNhY2hlRnJvbUdpdEh1Ykl0ZW1zKGRhdGEuaXRlbXMpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIGRhdGEuaXRlbXM7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiBbXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKGBHaXRIdWIgQVBJIHNlYXJjaCBmYWlsZWQsIGZhbGxpbmcgYmFjayB0byBjYWNoZTogJHtlcnJvcn1gKTtcbiAgICAgIFxuICAgICAgLy8gRmFsbGJhY2sgdG8gY2FjaGVkIHNlYXJjaFxuICAgICAgcmV0dXJuIHRoaXMuc2VhcmNoRnJvbUNhY2hlKHF1ZXJ5KTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggY2FjaGVkIGNvbGxlY3Rpb24gaXRlbXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VhcmNoRnJvbUNhY2hlKHF1ZXJ5OiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyeSB0byBsb2FkIGZyb20gY2FjaGUgZmlyc3RcbiAgICAgIGNvbnN0IGNhY2hlZEl0ZW1zID0gYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2VhcmNoQ2FjaGUocXVlcnkpO1xuICAgICAgXG4gICAgICBpZiAoY2FjaGVkSXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7Y2FjaGVkSXRlbXMubGVuZ3RofSBpdGVtcyBmcm9tIGNhY2hlYCk7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoY2FjaGVkSXRlbXMpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBJZiBjYWNoZSBpcyBlbXB0eSBvciBubyByZXN1bHRzLCB1c2Ugc2VlZCBkYXRhXG4gICAgICBjb25zdCBzZWVkSXRlbXMgPSB0aGlzLnNlYXJjaFNlZWREYXRhKHF1ZXJ5KTtcbiAgICAgIGlmIChzZWVkSXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7c2VlZEl0ZW1zLmxlbmd0aH0gaXRlbXMgZnJvbSBzZWVkIGRhdGFgKTtcbiAgICAgICAgLy8gU2F2ZSBzZWVkIGRhdGEgdG8gY2FjaGUgZm9yIGZ1dHVyZSB1c2VcbiAgICAgICAgYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2F2ZUNhY2hlKENvbGxlY3Rpb25TZWVkZXIuZ2V0U2VlZERhdGEoKSk7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoc2VlZEl0ZW1zKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKCdObyBpdGVtcyBmb3VuZCBpbiBjYWNoZSBvciBzZWVkIGRhdGEnKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBDYWNoZSBzZWFyY2ggZmFpbGVkOiAke2Vycm9yfWApO1xuICAgICAgXG4gICAgICAvLyBMYXN0IHJlc29ydDogc2VhcmNoIHNlZWQgZGF0YSB3aXRob3V0IGNhY2hlXG4gICAgICBjb25zdCBzZWVkSXRlbXMgPSB0aGlzLnNlYXJjaFNlZWREYXRhKHF1ZXJ5KTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgRmFsbGJhY2sgdG8gc2VlZCBkYXRhIGZvdW5kICR7c2VlZEl0ZW1zLmxlbmd0aH0gaXRlbXNgKTtcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoc2VlZEl0ZW1zKTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggc2VlZCBkYXRhIGZvciBtYXRjaGluZyBpdGVtcyB3aXRoIGZ1enp5IG1hdGNoaW5nXG4gICAqL1xuICBwcml2YXRlIHNlYXJjaFNlZWREYXRhKHF1ZXJ5OiBzdHJpbmcpOiBDb2xsZWN0aW9uSXRlbVtdIHtcbiAgICBjb25zdCBzZWVkRGF0YSA9IENvbGxlY3Rpb25TZWVkZXIuZ2V0U2VlZERhdGEoKTtcbiAgICBjb25zdCBub3JtYWxpemVkUXVlcnkgPSBub3JtYWxpemVTZWFyY2hUZXJtKHF1ZXJ5KTtcbiAgICBcbiAgICByZXR1cm4gc2VlZERhdGEuZmlsdGVyKGl0ZW0gPT4ge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBub3JtYWxpemVTZWFyY2hUZXJtKGl0ZW0ubmFtZSk7XG4gICAgICBjb25zdCBub3JtYWxpemVkUGF0aCA9IG5vcm1hbGl6ZVNlYXJjaFRlcm0oaXRlbS5wYXRoKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKG5vcm1hbGl6ZWRRdWVyeSkgfHwgXG4gICAgICAgICAgICAgbm9ybWFsaXplZFBhdGguaW5jbHVkZXMobm9ybWFsaXplZFF1ZXJ5KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgXG4gIC8qKlxuICAgKiBDb252ZXJ0IGNhY2hlIGl0ZW1zIHRvIEdpdEh1YiBBUEkgZm9ybWF0IGZvciBjb25zaXN0ZW50IHJlc3BvbnNlIHN0cnVjdHVyZVxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0Q2FjaGVJdGVtc1RvR2l0SHViRm9ybWF0KGNhY2hlSXRlbXM6IENvbGxlY3Rpb25JdGVtW10pOiBhbnlbXSB7XG4gICAgcmV0dXJuIGNhY2hlSXRlbXMubWFwKGl0ZW0gPT4gKHtcbiAgICAgIG5hbWU6IGl0ZW0ubmFtZSxcbiAgICAgIHBhdGg6IGl0ZW0ucGF0aCxcbiAgICAgIHNoYTogaXRlbS5zaGEsXG4gICAgICB1cmw6IGBodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL0RvbGxob3VzZU1DUC9jb2xsZWN0aW9uL2NvbnRlbnRzLyR7aXRlbS5wYXRofWAsXG4gICAgICBodG1sX3VybDogYGh0dHBzOi8vZ2l0aHViLmNvbS9Eb2xsaG91c2VNQ1AvY29sbGVjdGlvbi9ibG9iL21haW4vJHtpdGVtLnBhdGh9YCxcbiAgICAgIHJlcG9zaXRvcnk6IHtcbiAgICAgICAgbmFtZTogJ2NvbGxlY3Rpb24nLFxuICAgICAgICBmdWxsX25hbWU6ICdEb2xsaG91c2VNQ1AvY29sbGVjdGlvbidcbiAgICAgIH1cbiAgICB9KSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGRhdGUgY2FjaGUgd2l0aCBmcmVzaCBkYXRhIGZyb20gR2l0SHViIEFQSSBpdGVtc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB1cGRhdGVDYWNoZUZyb21HaXRIdWJJdGVtcyhnaXRodWJJdGVtczogYW55W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY2FjaGVJdGVtczogQ29sbGVjdGlvbkl0ZW1bXSA9IGdpdGh1Ykl0ZW1zLm1hcChpdGVtID0+ICh7XG4gICAgICAgIG5hbWU6IGl0ZW0ubmFtZSxcbiAgICAgICAgcGF0aDogaXRlbS5wYXRoLFxuICAgICAgICBzaGE6IGl0ZW0uc2hhLFxuICAgICAgICBsYXN0X21vZGlmaWVkOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgIH0pKTtcbiAgICAgIFxuICAgICAgYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2F2ZUNhY2hlKGNhY2hlSXRlbXMpO1xuICAgICAgbG9nZ2VyLmRlYnVnKGBVcGRhdGVkIGNhY2hlIHdpdGggJHtjYWNoZUl0ZW1zLmxlbmd0aH0gaXRlbXMgZnJvbSBHaXRIdWIgQVBJYCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgRmFpbGVkIHRvIHVwZGF0ZSBjYWNoZTogJHtlcnJvcn1gKTtcbiAgICAgIC8vIERvbid0IHRocm93IC0gY2FjaGUgdXBkYXRlIGZhaWx1cmVzIHNob3VsZG4ndCBicmVhayBmdW5jdGlvbmFsaXR5XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogRm9ybWF0IHNlYXJjaCByZXN1bHRzXG4gICAqL1xuICBmb3JtYXRTZWFyY2hSZXN1bHRzKGl0ZW1zOiBhbnlbXSwgcXVlcnk6IHN0cmluZywgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBzdHJpbmcge1xuICAgIGlmIChpdGVtcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gTm8gY29udGVudCBmb3VuZCBmb3IgcXVlcnk6IFwiJHtxdWVyeX1cImA7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHRleHRQYXJ0cyA9IFtgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gKipTZWFyY2ggUmVzdWx0cyBmb3IgXCIke3F1ZXJ5fVwiKiogKCR7aXRlbXMubGVuZ3RofSBmb3VuZClcXG5cXG5gXTtcbiAgICBcbiAgICBpdGVtcy5mb3JFYWNoKChpdGVtOiBhbnkpID0+IHtcbiAgICAgIC8vIEV4dHJhY3QgY29udGVudCB0eXBlIGZyb20gcGF0aCAobGlicmFyeS9wZXJzb25hcy9jcmVhdGl2ZS93cml0ZXIubWQgLT4gcGVyc29uYXMpXG4gICAgICBjb25zdCBwYXRoUGFydHMgPSBpdGVtLnBhdGguc3BsaXQoJy8nKTtcbiAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcGF0aFBhcnRzWzFdIHx8ICdjb250ZW50JztcbiAgICAgIFxuICAgICAgY29uc3QgY29udGVudEljb25zOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICAgICAgICAncGVyc29uYXMnOiAn8J+OrScsXG4gICAgICAgICdza2lsbHMnOiAn8J+boO+4jycsXG4gICAgICAgICdhZ2VudHMnOiAn8J+klicsXG4gICAgICAgICdwcm9tcHRzJzogJ/CfkqwnLFxuICAgICAgICAndGVtcGxhdGVzJzogJ/Cfk4QnLFxuICAgICAgICAndG9vbHMnOiAn8J+UpycsXG4gICAgICAgICdlbnNlbWJsZXMnOiAn8J+OvCdcbiAgICAgIH07XG4gICAgICBjb25zdCBpY29uID0gY29udGVudEljb25zW2NvbnRlbnRUeXBlXSB8fCAn8J+ThCc7XG4gICAgICBcbiAgICAgIHRleHRQYXJ0cy5wdXNoKFxuICAgICAgICBgICAgJHtpY29ufSAqKiR7aXRlbS5uYW1lLnJlcGxhY2UoJy5tZCcsICcnKX0qKlxcbmAsXG4gICAgICAgIGAgICAgICDwn5OCIFBhdGg6ICR7aXRlbS5wYXRofVxcbmAsXG4gICAgICAgIGAgICAgICDwn5OlIEluc3RhbGw6IFxcYGluc3RhbGxfY29udGVudCBcIiR7aXRlbS5wYXRofVwiXFxgXFxuYCxcbiAgICAgICAgYCAgICAgIPCfkYHvuI8gRGV0YWlsczogXFxgZ2V0X2NvbGxlY3Rpb25fY29udGVudCBcIiR7aXRlbS5wYXRofVwiXFxgXFxuXFxuYFxuICAgICAgKTtcbiAgICB9KTtcbiAgICBcbiAgICByZXR1cm4gdGV4dFBhcnRzLmpvaW4oJycpO1xuICB9XG59Il19