@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
JavaScript
/**
* 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==