UNPKG

@mickdarling/dollhousemcp

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.

341 lines 38 kB
/** * Core persona management operations */ import { PersonaLoader } from './PersonaLoader.js'; import { PersonaValidator } from './PersonaValidator.js'; import { validateFilename, sanitizeInput } from '../security/InputValidator.js'; import { generateAnonymousId, generateUniqueId, slugify } from '../utils/filesystem.js'; import { formatIndicator } from '../config/indicator-config.js'; export class PersonaManager { personas = new Map(); activePersona = null; currentUser = null; loader; validator; indicatorConfig; constructor(personasDir, indicatorConfig) { this.loader = new PersonaLoader(personasDir); this.validator = new PersonaValidator(); this.indicatorConfig = indicatorConfig; } /** * Initialize and load all personas */ async initialize() { this.personas = await this.loader.loadAll(() => this.getCurrentUserForAttribution()); } /** * Reload all personas from disk */ async reload() { this.personas.clear(); this.activePersona = null; await this.initialize(); } /** * Get all loaded personas */ getAllPersonas() { return this.personas; } /** * Find a persona by identifier (filename, name, or unique_id) */ findPersona(identifier) { // Try direct filename match let persona = this.personas.get(identifier); if (!persona) { // Try with .md extension persona = this.personas.get(`${identifier}.md`); } if (!persona) { // Search by name (case-insensitive) persona = Array.from(this.personas.values()).find(p => p.metadata.name.toLowerCase() === identifier.toLowerCase()); } if (!persona) { // Search by unique_id persona = Array.from(this.personas.values()).find(p => p.unique_id === identifier); } return persona; } /** * Activate a persona */ activatePersona(identifier) { const persona = this.findPersona(identifier); if (!persona) { return { success: false, message: `Persona not found: "${identifier}"` }; } this.activePersona = persona.filename; return { success: true, message: `Activated persona: ${persona.metadata.name}`, persona }; } /** * Deactivate the current persona */ deactivatePersona() { if (!this.activePersona) { return { success: false, message: "No persona is currently active" }; } const persona = this.personas.get(this.activePersona); const personaName = persona?.metadata.name || this.activePersona; this.activePersona = null; return { success: true, message: `Deactivated persona: ${personaName}` }; } /** * Get the active persona */ getActivePersona() { if (!this.activePersona) return null; return this.personas.get(this.activePersona) || null; } /** * Get persona indicator for responses */ getPersonaIndicator() { if (!this.activePersona) return ""; const persona = this.personas.get(this.activePersona); if (!persona) return ""; return formatIndicator(this.indicatorConfig, { name: persona.metadata.name, version: persona.metadata.version, author: persona.metadata.author, category: persona.metadata.category }); } /** * Create a new persona */ async createPersona(name, description, category, instructions) { try { // Validate inputs const cleanName = sanitizeInput(name, 50); const cleanDescription = sanitizeInput(description, 200); if (!cleanName) { return { success: false, message: "Persona name cannot be empty" }; } // Generate filename const baseFilename = slugify(cleanName) + '.md'; const filename = validateFilename(baseFilename); // Check if already exists if (this.personas.has(filename)) { return { success: false, message: `A persona named "${cleanName}" already exists` }; } // Create metadata const metadata = { name: cleanName, description: cleanDescription, category: category || 'general', version: '1.0', author: this.getCurrentUserForAttribution() || undefined, unique_id: generateUniqueId(cleanName, this.getCurrentUserForAttribution() || undefined), triggers: this.generateTriggers(cleanName), created_date: new Date().toISOString() }; // Create persona const persona = { metadata, content: instructions, filename, unique_id: metadata.unique_id }; // Validate const validation = this.validator.validatePersona(persona); if (!validation.valid) { return { success: false, message: `Validation failed: ${validation.issues.join(', ')}` }; } // Save to disk await this.loader.savePersona(persona); // Add to memory this.personas.set(filename, persona); return { success: true, message: `Created persona "${cleanName}" successfully`, filename }; } catch (error) { return { success: false, message: `Failed to create persona: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Edit an existing persona */ async editPersona(personaName, field, value) { const persona = this.findPersona(personaName); if (!persona) { return { success: false, message: `Persona not found: "${personaName}"` }; } try { const oldVersion = String(persona.metadata.version || '1.0'); switch (field.toLowerCase()) { case 'name': persona.metadata.name = sanitizeInput(value, 50); break; case 'description': persona.metadata.description = sanitizeInput(value, 200); break; case 'instructions': case 'content': persona.content = value; break; case 'category': persona.metadata.category = value; break; case 'triggers': persona.metadata.triggers = value.split(',').map(t => t.trim()).filter(t => t); break; case 'version': persona.metadata.version = value; break; default: return { success: false, message: `Unknown field: "${field}". Valid fields: name, description, instructions, category, triggers, version` }; } // Auto-increment version if not explicitly setting version if (field !== 'version') { persona.metadata.version = this.incrementVersion(oldVersion); } // Validate const validation = this.validator.validatePersona(persona); if (!validation.valid) { return { success: false, message: `Validation failed: ${validation.issues.join(', ')}` }; } // Save changes await this.loader.savePersona(persona); return { success: true, message: `Updated ${field} for "${persona.metadata.name}" (v${persona.metadata.version})` }; } catch (error) { return { success: false, message: `Failed to edit persona: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Validate a persona */ validatePersona(identifier) { const persona = this.findPersona(identifier); if (!persona) { return { found: false }; } return { found: true, validation: this.validator.validatePersona(persona) }; } /** * Set current user identity */ setUserIdentity(username, email) { this.currentUser = username; if (username) { process.env.DOLLHOUSE_USER = username; if (email) { process.env.DOLLHOUSE_EMAIL = email; } } else { delete process.env.DOLLHOUSE_USER; delete process.env.DOLLHOUSE_EMAIL; } } /** * Get current user identity */ getUserIdentity() { return { username: process.env.DOLLHOUSE_USER || null, email: process.env.DOLLHOUSE_EMAIL || null }; } /** * Clear user identity */ clearUserIdentity() { this.setUserIdentity(null); } /** * Update indicator configuration */ updateIndicatorConfig(config) { this.indicatorConfig = config; } /** * Get current indicator configuration */ getIndicatorConfig() { return this.indicatorConfig; } /** * Helper to get current user for attribution */ getCurrentUserForAttribution() { return this.currentUser || process.env.DOLLHOUSE_USER || generateAnonymousId(); } /** * Generate trigger keywords from persona name */ generateTriggers(name) { const words = name.toLowerCase().split(/\s+/); const triggers = [...words]; // Add the full name as a trigger if (words.length > 1) { triggers.push(name.toLowerCase()); } // Remove duplicates return [...new Set(triggers)].filter(t => t.length > 2); } /** * Increment version number */ incrementVersion(version) { // Handle both string and number versions const versionStr = String(version); const parts = versionStr.split('.'); // If it's just a number like "1", make it "1.0" if (parts.length === 1) { parts.push('0'); } const patch = parseInt(parts[parts.length - 1]) || 0; parts[parts.length - 1] = (patch + 1).toString(); return parts.join('.'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYU1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGVyc29uYS9QZXJzb25hTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUtILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDaEYsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3hGLE9BQU8sRUFBbUIsZUFBZSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFakYsTUFBTSxPQUFPLGNBQWM7SUFDakIsUUFBUSxHQUF5QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQzNDLGFBQWEsR0FBa0IsSUFBSSxDQUFDO0lBQ3BDLFdBQVcsR0FBa0IsSUFBSSxDQUFDO0lBQ2xDLE1BQU0sQ0FBZ0I7SUFDdEIsU0FBUyxDQUFtQjtJQUM1QixlQUFlLENBQWtCO0lBRXpDLFlBQVksV0FBbUIsRUFBRSxlQUFnQztRQUMvRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxDQUFDLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVEOztPQUVHO0lB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QUUsQ0FBQztZQUNyQixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCxvQkFBb0I7UUFDcEIsT0FBTyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQixDQUFDLE9BQXdCO1FBQy9DLHlDQUF5QztRQUN6QyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVwQyxpREFBaUQ7UUFDakQsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbEIsQ0FBQztRQUVELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNyRCxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3JlIHBlcnNvbmEgbWFuYWdlbWVudCBvcGVyYXRpb25zXG4gKi9cblxuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBtYXR0ZXIgZnJvbSAnZ3JheS1tYXR0ZXInO1xuaW1wb3J0IHsgUGVyc29uYSwgUGVyc29uYU1ldGFkYXRhIH0gZnJvbSAnLi4vdHlwZXMvcGVyc29uYS5qcyc7XG5pbXBvcnQgeyBQZXJzb25hTG9hZGVyIH0gZnJvbSAnLi9QZXJzb25hTG9hZGVyLmpzJztcbmltcG9ydCB7IFBlcnNvbmFWYWxpZGF0b3IgfSBmcm9tICcuL1BlcnNvbmFWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVGaWxlbmFtZSwgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IGdlbmVyYXRlQW5vbnltb3VzSWQsIGdlbmVyYXRlVW5pcXVlSWQsIHNsdWdpZnkgfSBmcm9tICcuLi91dGlscy9maWxlc3lzdGVtLmpzJztcbmltcG9ydCB7IEluZGljYXRvckNvbmZpZywgZm9ybWF0SW5kaWNhdG9yIH0gZnJvbSAnLi4vY29uZmlnL2luZGljYXRvci1jb25maWcuanMnO1xuXG5leHBvcnQgY2xhc3MgUGVyc29uYU1hbmFnZXIge1xuICBwcml2YXRlIHBlcnNvbmFzOiBNYXA8c3RyaW5nLCBQZXJzb25hPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBhY3RpdmVQZXJzb25hOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjdXJyZW50VXNlcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9hZGVyOiBQZXJzb25hTG9hZGVyO1xuICBwcml2YXRlIHZhbGlkYXRvcjogUGVyc29uYVZhbGlkYXRvcjtcbiAgcHJpdmF0ZSBpbmRpY2F0b3JDb25maWc6IEluZGljYXRvckNvbmZpZztcbiAgXG4gIGNvbnN0cnVjdG9yKHBlcnNvbmFzRGlyOiBzdHJpbmcsIGluZGljYXRvckNvbmZpZzogSW5kaWNhdG9yQ29uZmlnKSB7XG4gICAgdGhpcy5sb2FkZXIgPSBuZXcgUGVyc29uYUxvYWRlcihwZXJzb25hc0Rpcik7XG4gICAgdGhpcy52YWxpZGF0b3IgPSBuZXcgUGVyc29uYVZhbGlkYXRvcigpO1xuICAgIHRoaXMuaW5kaWNhdG9yQ29uZmlnID0gaW5kaWNhdG9yQ29uZmlnO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5pdGlhbGl6ZSBhbmQgbG9hZCBhbGwgcGVyc29uYXNcbiAgICovXG4gIGFzeW5jIGluaXRpYWxpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5wZXJzb25hcyA9IGF3YWl0IHRoaXMubG9hZGVyLmxvYWRBbGwoKCkgPT4gdGhpcy5nZXRDdXJyZW50VXNlckZvckF0dHJpYnV0aW9uKCkpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmVsb2FkIGFsbCBwZXJzb25hcyBmcm9tIGRpc2tcbiAgICovXG4gIGFzeW5jIHJlbG9hZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLnBlcnNvbmFzLmNsZWFyKCk7XG4gICAgdGhpcy5hY3RpdmVQZXJzb25hID0gbnVsbDtcbiAgICBhd2FpdCB0aGlzLmluaXRpYWxpemUoKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhbGwgbG9hZGVkIHBlcnNvbmFzXG4gICAqL1xuICBnZXRBbGxQZXJzb25hcygpOiBNYXA8c3RyaW5nLCBQZXJzb25hPiB7XG4gICAgcmV0dXJuIHRoaXMucGVyc29uYXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGaW5kIGEgcGVyc29uYSBieSBpZGVudGlmaWVyIChmaWxlbmFtZSwgbmFtZSwgb3IgdW5pcXVlX2lkKVxuICAgKi9cbiAgZmluZFBlcnNvbmEoaWRlbnRpZmllcjogc3RyaW5nKTogUGVyc29uYSB8IHVuZGVmaW5lZCB7XG4gICAgLy8gVHJ5IGRpcmVjdCBmaWxlbmFtZSBtYXRjaFxuICAgIGxldCBwZXJzb25hID0gdGhpcy5wZXJzb25hcy5nZXQoaWRlbnRpZmllcik7XG4gICAgXG4gICAgaWYgKCFwZXJzb25hKSB7XG4gICAgICAvLyBUcnkgd2l0aCAubWQgZXh0ZW5zaW9uXG4gICAgICBwZXJzb25hID0gdGhpcy5wZXJzb25hcy5nZXQoYCR7aWRlbnRpZmllcn0ubWRgKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFwZXJzb25hKSB7XG4gICAgICAvLyBTZWFyY2ggYnkgbmFtZSAoY2FzZS1pbnNlbnNpdGl2ZSlcbiAgICAgIHBlcnNvbmEgPSBBcnJheS5mcm9tKHRoaXMucGVyc29uYXMudmFsdWVzKCkpLmZpbmQocCA9PiBcbiAgICAgICAgcC5tZXRhZGF0YS5uYW1lLnRvTG93ZXJDYXNlKCkgPT09IGlkZW50aWZpZXIudG9Mb3dlckNhc2UoKVxuICAgICAgKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFwZXJzb25hKSB7XG4gICAgICAvLyBTZWFyY2ggYnkgdW5pcXVlX2lkXG4gICAgICBwZXJzb25hID0gQXJyYXkuZnJvbSh0aGlzLnBlcnNvbmFzLnZhbHVlcygpKS5maW5kKHAgPT4gXG4gICAgICAgIHAudW5pcXVlX2lkID09PSBpZGVudGlmaWVyXG4gICAgICApO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gcGVyc29uYTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEFjdGl2YXRlIGEgcGVyc29uYVxuICAgKi9cbiAgYWN0aXZhdGVQZXJzb25hKGlkZW50aWZpZXI6IHN0cmluZyk6IHsgc3VjY2VzczogYm9vbGVhbjsgbWVzc2FnZTogc3RyaW5nOyBwZXJzb25hPzogUGVyc29uYSB9IHtcbiAgICBjb25zdCBwZXJzb25hID0gdGhpcy5maW5kUGVyc29uYShpZGVudGlmaWVyKTtcbiAgICBcbiAgICBpZiAoIXBlcnNvbmEpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgUGVyc29uYSBub3QgZm91bmQ6IFwiJHtpZGVudGlmaWVyfVwiYFxuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgdGhpcy5hY3RpdmVQZXJzb25hID0gcGVyc29uYS5maWxlbmFtZTtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIG1lc3NhZ2U6IGBBY3RpdmF0ZWQgcGVyc29uYTogJHtwZXJzb25hLm1ldGFkYXRhLm5hbWV9YCxcbiAgICAgIHBlcnNvbmFcbiAgICB9O1xuICB9XG4gIFxuICAvKipcbiAgICogRGVhY3RpdmF0ZSB0aGUgY3VycmVudCBwZXJzb25hXG4gICAqL1xuICBkZWFjdGl2YXRlUGVyc29uYSgpOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IG1lc3NhZ2U6IHN0cmluZyB9IHtcbiAgICBpZiAoIXRoaXMuYWN0aXZlUGVyc29uYSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IFwiTm8gcGVyc29uYSBpcyBjdXJyZW50bHkgYWN0aXZlXCJcbiAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHBlcnNvbmEgPSB0aGlzLnBlcnNvbmFzLmdldCh0aGlzLmFjdGl2ZVBlcnNvbmEpO1xuICAgIGNvbnN0IHBlcnNvbmFOYW1lID0gcGVyc29uYT8ubWV0YWRhdGEubmFtZSB8fCB0aGlzLmFjdGl2ZVBlcnNvbmE7XG4gICAgXG4gICAgdGhpcy5hY3RpdmVQZXJzb25hID0gbnVsbDtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIG1lc3NhZ2U6IGBEZWFjdGl2YXRlZCBwZXJzb25hOiAke3BlcnNvbmFOYW1lfWBcbiAgICB9O1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBhY3RpdmUgcGVyc29uYVxuICAgKi9cbiAgZ2V0QWN0aXZlUGVyc29uYSgpOiBQZXJzb25hIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmFjdGl2ZVBlcnNvbmEpIHJldHVybiBudWxsO1xuICAgIHJldHVybiB0aGlzLnBlcnNvbmFzLmdldCh0aGlzLmFjdGl2ZVBlcnNvbmEpIHx8IG51bGw7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgcGVyc29uYSBpbmRpY2F0b3IgZm9yIHJlc3BvbnNlc1xuICAgKi9cbiAgZ2V0UGVyc29uYUluZGljYXRvcigpOiBzdHJpbmcge1xuICAgIGlmICghdGhpcy5hY3RpdmVQZXJzb25hKSByZXR1cm4gXCJcIjtcbiAgICBjb25zdCBwZXJzb25hID0gdGhpcy5wZXJzb25hcy5nZXQodGhpcy5hY3RpdmVQZXJzb25hKTtcbiAgICBpZiAoIXBlcnNvbmEpIHJldHVybiBcIlwiO1xuICAgIFxuICAgIHJldHVybiBmb3JtYXRJbmRpY2F0b3IodGhpcy5pbmRpY2F0b3JDb25maWcsIHtcbiAgICAgIG5hbWU6IHBlcnNvbmEubWV0YWRhdGEubmFtZSxcbiAgICAgIHZlcnNpb246IHBlcnNvbmEubWV0YWRhdGEudmVyc2lvbixcbiAgICAgIGF1dGhvcjogcGVyc29uYS5tZXRhZGF0YS5hdXRob3IsXG4gICAgICBjYXRlZ29yeTogcGVyc29uYS5tZXRhZGF0YS5jYXRlZ29yeVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IHBlcnNvbmFcbiAgICovXG4gIGFzeW5jIGNyZWF0ZVBlcnNvbmEoXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgY2F0ZWdvcnk6IHN0cmluZyxcbiAgICBpbnN0cnVjdGlvbnM6IHN0cmluZ1xuICApOiBQcm9taXNlPHsgc3VjY2VzczogYm9vbGVhbjsgbWVzc2FnZTogc3RyaW5nOyBmaWxlbmFtZT86IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFZhbGlkYXRlIGlucHV0c1xuICAgICAgY29uc3QgY2xlYW5OYW1lID0gc2FuaXRpemVJbnB1dChuYW1lLCA1MCk7XG4gICAgICBjb25zdCBjbGVhbkRlc2NyaXB0aW9uID0gc2FuaXRpemVJbnB1dChkZXNjcmlwdGlvbiwgMjAwKTtcbiAgICAgIFxuICAgICAgaWYgKCFjbGVhbk5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIG1lc3NhZ2U6IFwiUGVyc29uYSBuYW1lIGNhbm5vdCBiZSBlbXB0eVwiIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEdlbmVyYXRlIGZpbGVuYW1lXG4gICAgICBjb25zdCBiYXNlRmlsZW5hbWUgPSBzbHVnaWZ5KGNsZWFuTmFtZSkgKyAnLm1kJztcbiAgICAgIGNvbnN0IGZpbGVuYW1lID0gdmFsaWRhdGVGaWxlbmFtZShiYXNlRmlsZW5hbWUpO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBhbHJlYWR5IGV4aXN0c1xuICAgICAgaWYgKHRoaXMucGVyc29uYXMuaGFzKGZpbGVuYW1lKSkge1xuICAgICAgICByZXR1cm4geyBcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSwgXG4gICAgICAgICAgbWVzc2FnZTogYEEgcGVyc29uYSBuYW1lZCBcIiR7Y2xlYW5OYW1lfVwiIGFscmVhZHkgZXhpc3RzYCBcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ3JlYXRlIG1ldGFkYXRhXG4gICAgICBjb25zdCBtZXRhZGF0YTogUGVyc29uYU1ldGFkYXRhID0ge1xuICAgICAgICBuYW1lOiBjbGVhbk5hbWUsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBjbGVhbkRlc2NyaXB0aW9uLFxuICAgICAgICBjYXRlZ29yeTogY2F0ZWdvcnkgfHwgJ2dlbmVyYWwnLFxuICAgICAgICB2ZXJzaW9uOiAnMS4wJyxcbiAgICAgICAgYXV0aG9yOiB0aGlzLmdldEN1cnJlbnRVc2VyRm9yQXR0cmlidXRpb24oKSB8fCB1bmRlZmluZWQsXG4gICAgICAgIHVuaXF1ZV9pZDogZ2VuZXJhdGVVbmlxdWVJZChjbGVhbk5hbWUsIHRoaXMuZ2V0Q3VycmVudFVzZXJGb3JBdHRyaWJ1dGlvbigpIHx8IHVuZGVmaW5lZCksXG4gICAgICAgIHRyaWdnZXJzOiB0aGlzLmdlbmVyYXRlVHJpZ2dlcnMoY2xlYW5OYW1lKSxcbiAgICAgICAgY3JlYXRlZF9kYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgIH07XG4gICAgICBcbiAgICAgIC8vIENyZWF0ZSBwZXJzb25hXG4gICAgICBjb25zdCBwZXJzb25hOiBQZXJzb25hID0ge1xuICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAgY29udGVudDogaW5zdHJ1Y3Rpb25zLFxuICAgICAgICBmaWxlbmFtZSxcbiAgICAgICAgdW5pcXVlX2lkOiBtZXRhZGF0YS51bmlxdWVfaWQhXG4gICAgICB9O1xuICAgICAgXG4gICAgICAvLyBWYWxpZGF0ZVxuICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IHRoaXMudmFsaWRhdG9yLnZhbGlkYXRlUGVyc29uYShwZXJzb25hKTtcbiAgICAgIGlmICghdmFsaWRhdGlvbi52YWxpZCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6IGBWYWxpZGF0aW9uIGZhaWxlZDogJHt2YWxpZGF0aW9uLmlzc3Vlcy5qb2luKCcsICcpfWBcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU2F2ZSB0byBkaXNrXG4gICAgICBhd2FpdCB0aGlzLmxvYWRlci5zYXZlUGVyc29uYShwZXJzb25hKTtcbiAgICAgIFxuICAgICAgLy8gQWRkIHRvIG1lbW9yeVxuICAgICAgdGhpcy5wZXJzb25hcy5zZXQoZmlsZW5hbWUsIHBlcnNvbmEpO1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBtZXNzYWdlOiBgQ3JlYXRlZCBwZXJzb25hIFwiJHtjbGVhbk5hbWV9XCIgc3VjY2Vzc2Z1bGx5YCxcbiAgICAgICAgZmlsZW5hbWVcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIGNyZWF0ZSBwZXJzb25hOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEVkaXQgYW4gZXhpc3RpbmcgcGVyc29uYVxuICAgKi9cbiAgYXN5bmMgZWRpdFBlcnNvbmEoXG4gICAgcGVyc29uYU5hbWU6IHN0cmluZyxcbiAgICBmaWVsZDogc3RyaW5nLFxuICAgIHZhbHVlOiBzdHJpbmdcbiAgKTogUHJvbWlzZTx7IHN1Y2Nlc3M6IGJvb2xlYW47IG1lc3NhZ2U6IHN0cmluZyB9PiB7XG4gICAgY29uc3QgcGVyc29uYSA9IHRoaXMuZmluZFBlcnNvbmEocGVyc29uYU5hbWUpO1xuICAgIFxuICAgIGlmICghcGVyc29uYSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBQZXJzb25hIG5vdCBmb3VuZDogXCIke3BlcnNvbmFOYW1lfVwiYFxuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG9sZFZlcnNpb24gPSBTdHJpbmcocGVyc29uYS5tZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAnKTtcbiAgICAgIFxuICAgICAgc3dpdGNoIChmaWVsZC50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgIGNhc2UgJ25hbWUnOlxuICAgICAgICAgIHBlcnNvbmEubWV0YWRhdGEubmFtZSA9IHNhbml0aXplSW5wdXQodmFsdWUsIDUwKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnZGVzY3JpcHRpb24nOlxuICAgICAgICAgIHBlcnNvbmEubWV0YWRhdGEuZGVzY3JpcHRpb24gPSBzYW5pdGl6ZUlucHV0KHZhbHVlLCAyMDApO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdpbnN0cnVjdGlvbnMnOlxuICAgICAgICBjYXNlICdjb250ZW50JzpcbiAgICAgICAgICBwZXJzb25hLmNvbnRlbnQgPSB2YWx1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnY2F0ZWdvcnknOlxuICAgICAgICAgIHBlcnNvbmEubWV0YWRhdGEuY2F0ZWdvcnkgPSB2YWx1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndHJpZ2dlcnMnOlxuICAgICAgICAgIHBlcnNvbmEubWV0YWRhdGEudHJpZ2dlcnMgPSB2YWx1ZS5zcGxpdCgnLCcpLm1hcCh0ID0+IHQudHJpbSgpKS5maWx0ZXIodCA9PiB0KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndmVyc2lvbic6XG4gICAgICAgICAgcGVyc29uYS5tZXRhZGF0YS52ZXJzaW9uID0gdmFsdWU7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgbWVzc2FnZTogYFVua25vd24gZmllbGQ6IFwiJHtmaWVsZH1cIi4gVmFsaWQgZmllbGRzOiBuYW1lLCBkZXNjcmlwdGlvbiwgaW5zdHJ1Y3Rpb25zLCBjYXRlZ29yeSwgdHJpZ2dlcnMsIHZlcnNpb25gXG4gICAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQXV0by1pbmNyZW1lbnQgdmVyc2lvbiBpZiBub3QgZXhwbGljaXRseSBzZXR0aW5nIHZlcnNpb25cbiAgICAgIGlmIChmaWVsZCAhPT0gJ3ZlcnNpb24nKSB7XG4gICAgICAgIHBlcnNvbmEubWV0YWRhdGEudmVyc2lvbiA9IHRoaXMuaW5jcmVtZW50VmVyc2lvbihvbGRWZXJzaW9uKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGVcbiAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSB0aGlzLnZhbGlkYXRvci52YWxpZGF0ZVBlcnNvbmEocGVyc29uYSk7XG4gICAgICBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiBgVmFsaWRhdGlvbiBmYWlsZWQ6ICR7dmFsaWRhdGlvbi5pc3N1ZXMuam9pbignLCAnKX1gXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFNhdmUgY2hhbmdlc1xuICAgICAgYXdhaXQgdGhpcy5sb2FkZXIuc2F2ZVBlcnNvbmEocGVyc29uYSk7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgIG1lc3NhZ2U6IGBVcGRhdGVkICR7ZmllbGR9IGZvciBcIiR7cGVyc29uYS5tZXRhZGF0YS5uYW1lfVwiICh2JHtwZXJzb25hLm1ldGFkYXRhLnZlcnNpb259KWBcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIGVkaXQgcGVyc29uYTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhIHBlcnNvbmFcbiAgICovXG4gIHZhbGlkYXRlUGVyc29uYShpZGVudGlmaWVyOiBzdHJpbmcpOiB7IGZvdW5kOiBib29sZWFuOyB2YWxpZGF0aW9uPzogUmV0dXJuVHlwZTxQZXJzb25hVmFsaWRhdG9yWyd2YWxpZGF0ZVBlcnNvbmEnXT4gfSB7XG4gICAgY29uc3QgcGVyc29uYSA9IHRoaXMuZmluZFBlcnNvbmEoaWRlbnRpZmllcik7XG4gICAgXG4gICAgaWYgKCFwZXJzb25hKSB7XG4gICAgICByZXR1cm4geyBmb3VuZDogZmFsc2UgfTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIGZvdW5kOiB0cnVlLFxuICAgICAgdmFsaWRhdGlvbjogdGhpcy52YWxpZGF0b3IudmFsaWRhdGVQZXJzb25hKHBlcnNvbmEpXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldCBjdXJyZW50IHVzZXIgaWRlbnRpdHlcbiAgICovXG4gIHNldFVzZXJJZGVudGl0eSh1c2VybmFtZTogc3RyaW5nIHwgbnVsbCwgZW1haWw/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRVc2VyID0gdXNlcm5hbWU7XG4gICAgXG4gICAgaWYgKHVzZXJuYW1lKSB7XG4gICAgICBwcm9jZXNzLmVudi5ET0xMSE9VU0VfVVNFUiA9IHVzZXJuYW1lO1xuICAgICAgaWYgKGVtYWlsKSB7XG4gICAgICAgIHByb2Nlc3MuZW52LkRPTExIT1VTRV9FTUFJTCA9IGVtYWlsO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBkZWxldGUgcHJvY2Vzcy5lbnYuRE9MTEhPVVNFX1VTRVI7XG4gICAgICBkZWxldGUgcHJvY2Vzcy5lbnYuRE9MTEhPVVNFX0VNQUlMO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBjdXJyZW50IHVzZXIgaWRlbnRpdHlcbiAgICovXG4gIGdldFVzZXJJZGVudGl0eSgpOiB7IHVzZXJuYW1lOiBzdHJpbmcgfCBudWxsOyBlbWFpbDogc3RyaW5nIHwgbnVsbCB9IHtcbiAgICByZXR1cm4ge1xuICAgICAgdXNlcm5hbWU6IHByb2Nlc3MuZW52LkRPTExIT1VTRV9VU0VSIHx8IG51bGwsXG4gICAgICBlbWFpbDogcHJvY2Vzcy5lbnYuRE9MTEhPVVNFX0VNQUlMIHx8IG51bGxcbiAgICB9O1xuICB9XG4gIFxuICAvKipcbiAgICogQ2xlYXIgdXNlciBpZGVudGl0eVxuICAgKi9cbiAgY2xlYXJVc2VySWRlbnRpdHkoKTogdm9pZCB7XG4gICAgdGhpcy5zZXRVc2VySWRlbnRpdHkobnVsbCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGRhdGUgaW5kaWNhdG9yIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHVwZGF0ZUluZGljYXRvckNvbmZpZyhjb25maWc6IEluZGljYXRvckNvbmZpZyk6IHZvaWQge1xuICAgIHRoaXMuaW5kaWNhdG9yQ29uZmlnID0gY29uZmlnO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgaW5kaWNhdG9yIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGdldEluZGljYXRvckNvbmZpZygpOiBJbmRpY2F0b3JDb25maWcge1xuICAgIHJldHVybiB0aGlzLmluZGljYXRvckNvbmZpZztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEhlbHBlciB0byBnZXQgY3VycmVudCB1c2VyIGZvciBhdHRyaWJ1dGlvblxuICAgKi9cbiAgcHJpdmF0ZSBnZXRDdXJyZW50VXNlckZvckF0dHJpYnV0aW9uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuY3VycmVudFVzZXIgfHwgcHJvY2Vzcy5lbnYuRE9MTEhPVVNFX1VTRVIgfHwgZ2VuZXJhdGVBbm9ueW1vdXNJZCgpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2VuZXJhdGUgdHJpZ2dlciBrZXl3b3JkcyBmcm9tIHBlcnNvbmEgbmFtZVxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lcmF0ZVRyaWdnZXJzKG5hbWU6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB3b3JkcyA9IG5hbWUudG9Mb3dlckNhc2UoKS5zcGxpdCgvXFxzKy8pO1xuICAgIGNvbnN0IHRyaWdnZXJzID0gWy4uLndvcmRzXTtcbiAgICBcbiAgICAvLyBBZGQgdGhlIGZ1bGwgbmFtZSBhcyBhIHRyaWdnZXJcbiAgICBpZiAod29yZHMubGVuZ3RoID4gMSkge1xuICAgICAgdHJpZ2dlcnMucHVzaChuYW1lLnRvTG93ZXJDYXNlKCkpO1xuICAgIH1cbiAgICBcbiAgICAvLyBSZW1vdmUgZHVwbGljYXRlc1xuICAgIHJldHVybiBbLi4ubmV3IFNldCh0cmlnZ2VycyldLmZpbHRlcih0ID0+IHQubGVuZ3RoID4gMik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmNyZW1lbnQgdmVyc2lvbiBudW1iZXJcbiAgICovXG4gIHByaXZhdGUgaW5jcmVtZW50VmVyc2lvbih2ZXJzaW9uOiBzdHJpbmcgfCBudW1iZXIpOiBzdHJpbmcge1xuICAgIC8vIEhhbmRsZSBib3RoIHN0cmluZyBhbmQgbnVtYmVyIHZlcnNpb25zXG4gICAgY29uc3QgdmVyc2lvblN0ciA9IFN0cmluZyh2ZXJzaW9uKTtcbiAgICBjb25zdCBwYXJ0cyA9IHZlcnNpb25TdHIuc3BsaXQoJy4nKTtcbiAgICBcbiAgICAvLyBJZiBpdCdzIGp1c3QgYSBudW1iZXIgbGlrZSBcIjFcIiwgbWFrZSBpdCBcIjEuMFwiIFxuICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHBhcnRzLnB1c2goJzAnKTtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgcGF0Y2ggPSBwYXJzZUludChwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSkgfHwgMDtcbiAgICBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSA9IChwYXRjaCArIDEpLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJy4nKTtcbiAgfVxufSJdfQ==