@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.
225 lines • 31.9 kB
JavaScript
/**
* upgradeElement - Upgrade element from v1 single-body to v2 dual-field format
*
* v1 format: Body text after YAML frontmatter, no `instructions` key in YAML
* v2 format: `instructions` in YAML frontmatter, `content` as markdown body
*
* Detection: If YAML frontmatter contains `instructions` key → already v2.
* Otherwise → v1, apply per-type default mapping.
*
* @see Plan: Dual-Field Element Architecture
*/
import { ElementType } from '../../portfolio/PortfolioManager.js';
import { logger } from '../../utils/logger.js';
import { ElementNotFoundError } from '../../utils/ErrorHandler.js';
import { normalizeElementTypeInput, formatValidElementTypesList, getElementTypeLabel, resolveElementByName, } from './helpers.js';
/**
* Per-type default mapping for v1 body text.
* Returns which field the body text should be assigned to.
*/
function getV1BodyMapping(elementType) {
switch (elementType) {
case ElementType.PERSONA:
case ElementType.SKILL:
case ElementType.AGENT:
return 'instructions';
case ElementType.TEMPLATE:
case ElementType.MEMORY:
case ElementType.ENSEMBLE:
return 'content';
default:
return 'content';
}
}
/**
* Detect whether an element is in v2 dual-field format.
*
* v2 indicators vary by element type:
* - For persona/skill/agent (body→instructions): v2 means instructions were in
* YAML frontmatter. If both instructions AND content are populated, it's
* definitively v2. If only instructions is populated (no content), it COULD be
* v1 (body→instructions) or v2 (instructions in YAML, empty body). Since we
* can't distinguish after loading, we treat instructions-only as v1 — the
* re-save is safe either way (it just writes v2 format to disk).
* - For template/memory/ensemble (body→content): v2 means instructions were added
* (since v1 would have empty instructions). Any non-empty instructions = v2.
*/
function isV2Format(element, elementType) {
const bodyMapping = getV1BodyMapping(elementType);
const instructions = (element.instructions || '').trim();
const content = getElementContent(element);
if (bodyMapping === 'instructions') {
// Persona/Skill/Agent: v1 has body→instructions (content empty).
// v2 has instructions in YAML frontmatter AND content as markdown body.
// Instructions-only (no content) is ambiguous — treated as v1, which is safe:
// the re-save writes v2 format without changing field values.
return instructions.length > 0 && content.length > 0;
}
else {
// Template/Memory/Ensemble: v1 has body→content (instructions empty).
// v2 has instructions in YAML AND content as body.
return instructions.length > 0;
}
}
/**
* Get content from element, handling Memory's getter pattern.
*/
function getElementContent(element) {
return (typeof element.content === 'string' ? element.content : '').trim();
}
/**
* Upgrade an element from v1 single-body format to v2 dual-field format.
*/
export async function upgradeElement(context, args) {
await context.ensureInitialized();
const { name, type, dry_run, instructions_override, content_override } = args;
if (!name) {
return error('Missing required parameter: element_name');
}
const { type: normalizedType } = normalizeElementTypeInput(type);
if (!normalizedType) {
return error(`Invalid element type '${type}'. Valid types: ${formatValidElementTypesList()}`);
}
const manager = getManagerForType(context, normalizedType);
if (!manager) {
const label = getElementTypeLabel(normalizedType, { plural: true });
return error(`Element type '${label}' is not yet supported for upgrade`);
}
const element = await resolveElementByName(manager, normalizedType, name);
if (!element) {
const label = getElementTypeLabel(normalizedType);
throw new ElementNotFoundError(label, name);
}
const currentInstructions = (element.instructions || '').trim();
const currentContent = getElementContent(element);
// Check if already v2 format (and no overrides provided)
if (isV2Format(element, normalizedType) && !instructions_override && !content_override) {
return {
content: [{
type: 'text',
text: `ℹ️ ${getElementTypeLabel(normalizedType)} '${element.metadata?.name || name}' is already in v2 dual-field format.\n\n` +
`**Instructions** (${currentInstructions.length} chars): ${truncate(currentInstructions, 100)}\n` +
`**Content** (${currentContent.length} chars): ${truncate(currentContent, 100)}`
}]
};
}
// Determine new field values
let newInstructions;
let newContent;
if (instructions_override !== undefined || content_override !== undefined) {
// Manual override mode
newInstructions = instructions_override ?? currentInstructions;
newContent = content_override ?? currentContent;
}
else {
// Auto-detection: field values stay the same — the managers already assigned the
// body text to the correct field during load (per getV1BodyMapping). The upgrade
// is the re-save itself: serializeElement() writes instructions to YAML frontmatter
// and content as the markdown body, converting the on-disk format from v1 to v2.
newInstructions = currentInstructions;
newContent = currentContent;
}
if (dry_run) {
// Preview mode — show what would change
const changes = [];
if (newInstructions !== currentInstructions) {
changes.push(`**instructions**: "${truncate(currentInstructions, 80)}" → "${truncate(newInstructions, 80)}"`);
}
if (newContent !== currentContent) {
changes.push(`**content**: "${truncate(currentContent, 80)}" → "${truncate(newContent, 80)}"`);
}
const displayName = element.metadata?.name || name;
const label = getElementTypeLabel(normalizedType);
if (changes.length === 0) {
return {
content: [{
type: 'text',
text: `ℹ️ ${label} '${displayName}' — no field changes needed for upgrade.\n\n` +
`The file will be re-saved in v2 format (instructions in YAML frontmatter, content as body).\n\n` +
`**instructions** (${newInstructions.length} chars): ${truncate(newInstructions, 150)}\n` +
`**content** (${newContent.length} chars): ${truncate(newContent, 150)}`
}]
};
}
return {
content: [{
type: 'text',
text: `🔍 Dry run — ${label} '${displayName}' upgrade preview:\n\n` +
changes.join('\n') + '\n\n' +
`Run without dry_run to apply these changes.`
}]
};
}
// Apply upgrade
element.instructions = newInstructions;
// For Memory, content is a getter — skip direct assignment
if (normalizedType !== ElementType.MEMORY) {
element.content = newContent;
}
// Determine file path for saving
const filePathCandidate = typeof element.getFilePath === 'function'
? element.getFilePath()
: (element.filePath || element.filename);
const filename = typeof filePathCandidate === 'string' && filePathCandidate.length > 0
? filePathCandidate
: '';
if (!filename) {
return error(`Cannot determine file path for ${getElementTypeLabel(normalizedType)} '${name}'`);
}
try {
await manager.save(element, filename);
}
catch (err) {
return error(`Failed to save upgraded element: ${err instanceof Error ? err.message : 'Unknown error'}`);
}
const displayName = element.metadata?.name || name;
const label = getElementTypeLabel(normalizedType);
logger.info(`[upgradeElement] Upgraded ${label} '${displayName}' to v2 dual-field format`, {
elementType: normalizedType,
elementName: displayName,
instructionsLength: newInstructions.length,
contentLength: newContent.length,
});
return {
content: [{
type: 'text',
text: `✅ Upgraded ${label} '${displayName}' to v2 dual-field format.\n\n` +
`**instructions** (${newInstructions.length} chars): ${truncate(newInstructions, 150)}\n` +
`**content** (${newContent.length} chars): ${truncate(newContent, 150)}`
}]
};
}
function error(message) {
return {
content: [{
type: 'text',
text: `❌ ${message}`
}]
};
}
function truncate(text, maxLength) {
if (!text)
return '(empty)';
if (text.length <= maxLength)
return text;
return text.slice(0, maxLength) + '...';
}
function getManagerForType(context, type) {
switch (type) {
case ElementType.PERSONA:
return context.personaManager;
case ElementType.SKILL:
return context.skillManager;
case ElementType.TEMPLATE:
return context.templateManager;
case ElementType.AGENT:
return context.agentManager;
case ElementType.MEMORY:
return context.memoryManager;
case ElementType.ENSEMBLE:
return context.ensembleManager;
default:
return null;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBncmFkZUVsZW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaGFuZGxlcnMvZWxlbWVudC1jcnVkL3VwZ3JhZGVFbGVtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFFbEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ25FLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsMkJBQTJCLEVBQzNCLG1CQUFtQixFQUNuQixvQkFBb0IsR0FFckIsTUFBTSxjQUFjLENBQUM7QUFpQnRCOzs7R0FHRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsV0FBd0I7SUFDaEQsUUFBUSxXQUFXLEVBQUUsQ0FBQztRQUNwQixLQUFLLFdBQVcsQ0FBQyxPQUFPLENBQUM7UUFDekIsS0FBSyxXQUFXLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLEtBQUssV0FBVyxDQUFDLEtBQUs7WUFDcEIsT0FBTyxjQUFjLENBQUM7UUFDeEIsS0FBSyxXQUFXLENBQUMsUUFBUSxDQUFDO1FBQzFCLEtBQUssV0FBVyxDQUFDLE1BQU0sQ0FBQztRQUN4QixLQUFLLFdBQVcsQ0FBQyxRQUFRO1lBQ3ZCLE9BQU8sU0FBUyxDQUFDO1FBQ25CO1lBQ0UsT0FBTyxTQUFTLENBQUM7SUFDckIsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxTQUFTLFVBQVUsQ0FBQyxPQUFZLEVBQUUsV0FBd0I7SUFDeEQsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDbEQsTUFBTSxZQUFZLEdBQUcsQ0FBQyxPQUFPLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3pELE1B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Iiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiB1cGdyYWRlRWxlbWVudCAtIFVwZ3JhZGUgZWxlbWVudCBmcm9tIHYxIHNpbmdsZS1ib2R5IHRvIHYyIGR1YWwtZmllbGQgZm9ybWF0XG4gKlxuICogdjEgZm9ybWF0OiBCb2R5IHRleHQgYWZ0ZXIgWUFNTCBmcm9udG1hdHRlciwgbm8gYGluc3RydWN0aW9uc2Aga2V5IGluIFlBTUxcbiAqIHYyIGZvcm1hdDogYGluc3RydWN0aW9uc2AgaW4gWUFNTCBmcm9udG1hdHRlciwgYGNvbnRlbnRgIGFzIG1hcmtkb3duIGJvZHlcbiAqXG4gKiBEZXRlY3Rpb246IElmIFlBTUwgZnJvbnRtYXR0ZXIgY29udGFpbnMgYGluc3RydWN0aW9uc2Aga2V5IOKGkiBhbHJlYWR5IHYyLlxuICogT3RoZXJ3aXNlIOKGkiB2MSwgYXBwbHkgcGVyLXR5cGUgZGVmYXVsdCBtYXBwaW5nLlxuICpcbiAqIEBzZWUgUGxhbjogRHVhbC1GaWVsZCBFbGVtZW50IEFyY2hpdGVjdHVyZVxuICovXG5cbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL1BvcnRmb2xpb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudENydWRDb250ZXh0IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudE5vdEZvdW5kRXJyb3IgfSBmcm9tICcuLi8uLi91dGlscy9FcnJvckhhbmRsZXIuanMnO1xuaW1wb3J0IHtcbiAgbm9ybWFsaXplRWxlbWVudFR5cGVJbnB1dCxcbiAgZm9ybWF0VmFsaWRFbGVtZW50VHlwZXNMaXN0LFxuICBnZXRFbGVtZW50VHlwZUxhYmVsLFxuICByZXNvbHZlRWxlbWVudEJ5TmFtZSxcbiAgRWxlbWVudE1hbmFnZXJPcGVyYXRpb25zLFxufSBmcm9tICcuL2hlbHBlcnMuanMnO1xuXG50eXBlIEVsZW1lbnRNYW5hZ2VyV2l0aFBlcnNpc3RlbmNlPFQ+ID0gRWxlbWVudE1hbmFnZXJPcGVyYXRpb25zPFQ+ICYge1xuICBzYXZlKGVsZW1lbnQ6IFQsIGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBVcGdyYWRlRWxlbWVudEFyZ3Mge1xuICBuYW1lOiBzdHJpbmc7XG4gIHR5cGU6IHN0cmluZztcbiAgLyoqIFByZXZpZXcgY2hhbmdlcyB3aXRob3V0IHdyaXRpbmcgdG8gZGlzayAqL1xuICBkcnlfcnVuPzogYm9vbGVhbjtcbiAgLyoqIE1hbnVhbGx5IHNwZWNpZnkgaW5zdHJ1Y3Rpb25zIChvdmVycmlkZXMgYXV0by1kZXRlY3Rpb24pICovXG4gIGluc3RydWN0aW9uc19vdmVycmlkZT86IHN0cmluZztcbiAgLyoqIE1hbnVhbGx5IHNwZWNpZnkgY29udGVudCAob3ZlcnJpZGVzIGF1dG8tZGV0ZWN0aW9uKSAqL1xuICBjb250ZW50X292ZXJyaWRlPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBlci10eXBlIGRlZmF1bHQgbWFwcGluZyBmb3IgdjEgYm9keSB0ZXh0LlxuICogUmV0dXJucyB3aGljaCBmaWVsZCB0aGUgYm9keSB0ZXh0IHNob3VsZCBiZSBhc3NpZ25lZCB0by5cbiAqL1xuZnVuY3Rpb24gZ2V0VjFCb2R5TWFwcGluZyhlbGVtZW50VHlwZTogRWxlbWVudFR5cGUpOiAnaW5zdHJ1Y3Rpb25zJyB8ICdjb250ZW50JyB7XG4gIHN3aXRjaCAoZWxlbWVudFR5cGUpIHtcbiAgICBjYXNlIEVsZW1lbnRUeXBlLlBFUlNPTkE6XG4gICAgY2FzZSBFbGVtZW50VHlwZS5TS0lMTDpcbiAgICBjYXNlIEVsZW1lbnRUeXBlLkFHRU5UOlxuICAgICAgcmV0dXJuICdpbnN0cnVjdGlvbnMnO1xuICAgIGNhc2UgRWxlbWVudFR5cGUuVEVNUExBVEU6XG4gICAgY2FzZSBFbGVtZW50VHlwZS5NRU1PUlk6XG4gICAgY2FzZSBFbGVtZW50VHlwZS5FTlNFTUJMRTpcbiAgICAgIHJldHVybiAnY29udGVudCc7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAnY29udGVudCc7XG4gIH1cbn1cblxuLyoqXG4gKiBEZXRlY3Qgd2hldGhlciBhbiBlbGVtZW50IGlzIGluIHYyIGR1YWwtZmllbGQgZm9ybWF0LlxuICpcbiAqIHYyIGluZGljYXRvcnMgdmFyeSBieSBlbGVtZW50IHR5cGU6XG4gKiAtIEZvciBwZXJzb25hL3NraWxsL2FnZW50IChib2R54oaSaW5zdHJ1Y3Rpb25zKTogdjIgbWVhbnMgaW5zdHJ1Y3Rpb25zIHdlcmUgaW5cbiAqICAgWUFNTCBmcm9udG1hdHRlci4gSWYgYm90aCBpbnN0cnVjdGlvbnMgQU5EIGNvbnRlbnQgYXJlIHBvcHVsYXRlZCwgaXQnc1xuICogICBkZWZpbml0aXZlbHkgdjIuIElmIG9ubHkgaW5zdHJ1Y3Rpb25zIGlzIHBvcHVsYXRlZCAobm8gY29udGVudCksIGl0IENPVUxEIGJlXG4gKiAgIHYxIChib2R54oaSaW5zdHJ1Y3Rpb25zKSBvciB2MiAoaW5zdHJ1Y3Rpb25zIGluIFlBTUwsIGVtcHR5IGJvZHkpLiBTaW5jZSB3ZVxuICogICBjYW4ndCBkaXN0aW5ndWlzaCBhZnRlciBsb2FkaW5nLCB3ZSB0cmVhdCBpbnN0cnVjdGlvbnMtb25seSBhcyB2MSDigJQgdGhlXG4gKiAgIHJlLXNhdmUgaXMgc2FmZSBlaXRoZXIgd2F5IChpdCBqdXN0IHdyaXRlcyB2MiBmb3JtYXQgdG8gZGlzaykuXG4gKiAtIEZvciB0ZW1wbGF0ZS9tZW1vcnkvZW5zZW1ibGUgKGJvZHnihpJjb250ZW50KTogdjIgbWVhbnMgaW5zdHJ1Y3Rpb25zIHdlcmUgYWRkZWRcbiAqICAgKHNpbmNlIHYxIHdvdWxkIGhhdmUgZW1wdHkgaW5zdHJ1Y3Rpb25zKS4gQW55IG5vbi1lbXB0eSBpbnN0cnVjdGlvbnMgPSB2Mi5cbiAqL1xuZnVuY3Rpb24gaXNWMkZvcm1hdChlbGVtZW50OiBhbnksIGVsZW1lbnRUeXBlOiBFbGVtZW50VHlwZSk6IGJvb2xlYW4ge1xuICBjb25zdCBib2R5TWFwcGluZyA9IGdldFYxQm9keU1hcHBpbmcoZWxlbWVudFR5cGUpO1xuICBjb25zdCBpbnN0cnVjdGlvbnMgPSAoZWxlbWVudC5pbnN0cnVjdGlvbnMgfHwgJycpLnRyaW0oKTtcbiAgY29uc3QgY29udGVudCA9IGdldEVsZW1lbnRDb250ZW50KGVsZW1lbnQpO1xuXG4gIGlmIChib2R5TWFwcGluZyA9PT0gJ2luc3RydWN0aW9ucycpIHtcbiAgICAvLyBQZXJzb25hL1NraWxsL0FnZW50OiB2MSBoYXMgYm9keeKGkmluc3RydWN0aW9ucyAoY29udGVudCBlbXB0eSkuXG4gICAgLy8gdjIgaGFzIGluc3RydWN0aW9ucyBpbiBZQU1MIGZyb250bWF0dGVyIEFORCBjb250ZW50IGFzIG1hcmtkb3duIGJvZHkuXG4gICAgLy8gSW5zdHJ1Y3Rpb25zLW9ubHkgKG5vIGNvbnRlbnQpIGlzIGFtYmlndW91cyDigJQgdHJlYXRlZCBhcyB2MSwgd2hpY2ggaXMgc2FmZTpcbiAgICAvLyB0aGUgcmUtc2F2ZSB3cml0ZXMgdjIgZm9ybWF0IHdpdGhvdXQgY2hhbmdpbmcgZmllbGQgdmFsdWVzLlxuICAgIHJldHVybiBpbnN0cnVjdGlvbnMubGVuZ3RoID4gMCAmJiBjb250ZW50Lmxlbmd0aCA+IDA7XG4gIH0gZWxzZSB7XG4gICAgLy8gVGVtcGxhdGUvTWVtb3J5L0Vuc2VtYmxlOiB2MSBoYXMgYm9keeKGkmNvbnRlbnQgKGluc3RydWN0aW9ucyBlbXB0eSkuXG4gICAgLy8gdjIgaGFzIGluc3RydWN0aW9ucyBpbiBZQU1MIEFORCBjb250ZW50IGFzIGJvZHkuXG4gICAgcmV0dXJuIGluc3RydWN0aW9ucy5sZW5ndGggPiAwO1xuICB9XG59XG5cbi8qKlxuICogR2V0IGNvbnRlbnQgZnJvbSBlbGVtZW50LCBoYW5kbGluZyBNZW1vcnkncyBnZXR0ZXIgcGF0dGVybi5cbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudENvbnRlbnQoZWxlbWVudDogYW55KTogc3RyaW5nIHtcbiAgcmV0dXJuICh0eXBlb2YgZWxlbWVudC5jb250ZW50ID09PSAnc3RyaW5nJyA/IGVsZW1lbnQuY29udGVudCA6ICcnKS50cmltKCk7XG59XG5cbi8qKlxuICogVXBncmFkZSBhbiBlbGVtZW50IGZyb20gdjEgc2luZ2xlLWJvZHkgZm9ybWF0IHRvIHYyIGR1YWwtZmllbGQgZm9ybWF0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBncmFkZUVsZW1lbnQoXG4gIGNvbnRleHQ6IEVsZW1lbnRDcnVkQ29udGV4dCxcbiAgYXJnczogVXBncmFkZUVsZW1lbnRBcmdzLFxuKSB7XG4gIGF3YWl0IGNvbnRleHQuZW5zdXJlSW5pdGlhbGl6ZWQoKTtcblxuICBjb25zdCB7IG5hbWUsIHR5cGUsIGRyeV9ydW4sIGluc3RydWN0aW9uc19vdmVycmlkZSwgY29udGVudF9vdmVycmlkZSB9ID0gYXJncztcblxuICBpZiAoIW5hbWUpIHtcbiAgICByZXR1cm4gZXJyb3IoJ01pc3NpbmcgcmVxdWlyZWQgcGFyYW1ldGVyOiBlbGVtZW50X25hbWUnKTtcbiAgfVxuXG4gIGNvbnN0IHsgdHlwZTogbm9ybWFsaXplZFR5cGUgfSA9IG5vcm1hbGl6ZUVsZW1lbnRUeXBlSW5wdXQodHlwZSk7XG4gIGlmICghbm9ybWFsaXplZFR5cGUpIHtcbiAgICByZXR1cm4gZXJyb3IoYEludmFsaWQgZWxlbWVudCB0eXBlICcke3R5cGV9Jy4gVmFsaWQgdHlwZXM6ICR7Zm9ybWF0VmFsaWRFbGVtZW50VHlwZXNMaXN0KCl9YCk7XG4gIH1cblxuICBjb25zdCBtYW5hZ2VyID0gZ2V0TWFuYWdlckZvclR5cGUoY29udGV4dCwgbm9ybWFsaXplZFR5cGUpO1xuICBpZiAoIW1hbmFnZXIpIHtcbiAgICBjb25zdCBsYWJlbCA9IGdldEVsZW1lbnRUeXBlTGFiZWwobm9ybWFsaXplZFR5cGUsIHsgcGx1cmFsOiB0cnVlIH0pO1xuICAgIHJldHVybiBlcnJvcihgRWxlbWVudCB0eXBlICcke2xhYmVsfScgaXMgbm90IHlldCBzdXBwb3J0ZWQgZm9yIHVwZ3JhZGVgKTtcbiAgfVxuXG4gIGNvbnN0IGVsZW1lbnQgPSBhd2FpdCByZXNvbHZlRWxlbWVudEJ5TmFtZShtYW5hZ2VyLCBub3JtYWxpemVkVHlwZSwgbmFtZSk7XG4gIGlmICghZWxlbWVudCkge1xuICAgIGNvbnN0IGxhYmVsID0gZ2V0RWxlbWVudFR5cGVMYWJlbChub3JtYWxpemVkVHlwZSk7XG4gICAgdGhyb3cgbmV3IEVsZW1lbnROb3RGb3VuZEVycm9yKGxhYmVsLCBuYW1lKTtcbiAgfVxuXG4gIGNvbnN0IGN1cnJlbnRJbnN0cnVjdGlvbnMgPSAoKGVsZW1lbnQgYXMgYW55KS5pbnN0cnVjdGlvbnMgfHwgJycpLnRyaW0oKTtcbiAgY29uc3QgY3VycmVudENvbnRlbnQgPSBnZXRFbGVtZW50Q29udGVudChlbGVtZW50KTtcblxuICAvLyBDaGVjayBpZiBhbHJlYWR5IHYyIGZvcm1hdCAoYW5kIG5vIG92ZXJyaWRlcyBwcm92aWRlZClcbiAgaWYgKGlzVjJGb3JtYXQoZWxlbWVudCwgbm9ybWFsaXplZFR5cGUpICYmICFpbnN0cnVjdGlvbnNfb3ZlcnJpZGUgJiYgIWNvbnRlbnRfb3ZlcnJpZGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3tcbiAgICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgICB0ZXh0OiBg4oS577iPICR7Z2V0RWxlbWVudFR5cGVMYWJlbChub3JtYWxpemVkVHlwZSl9ICckeyhlbGVtZW50IGFzIGFueSkubWV0YWRhdGE/Lm5hbWUgfHwgbmFtZX0nIGlzIGFscmVhZHkgaW4gdjIgZHVhbC1maWVsZCBmb3JtYXQuXFxuXFxuYCArXG4gICAgICAgICAgYCoqSW5zdHJ1Y3Rpb25zKiogKCR7Y3VycmVudEluc3RydWN0aW9ucy5sZW5ndGh9IGNoYXJzKTogJHt0cnVuY2F0ZShjdXJyZW50SW5zdHJ1Y3Rpb25zLCAxMDApfVxcbmAgK1xuICAgICAgICAgIGAqKkNvbnRlbnQqKiAoJHtjdXJyZW50Q29udGVudC5sZW5ndGh9IGNoYXJzKTogJHt0cnVuY2F0ZShjdXJyZW50Q29udGVudCwgMTAwKX1gXG4gICAgICB9XVxuICAgIH07XG4gIH1cblxuICAvLyBEZXRlcm1pbmUgbmV3IGZpZWxkIHZhbHVlc1xuICBsZXQgbmV3SW5zdHJ1Y3Rpb25zOiBzdHJpbmc7XG4gIGxldCBuZXdDb250ZW50OiBzdHJpbmc7XG5cbiAgaWYgKGluc3RydWN0aW9uc19vdmVycmlkZSAhPT0gdW5kZWZpbmVkIHx8IGNvbnRlbnRfb3ZlcnJpZGUgIT09IHVuZGVmaW5lZCkge1xuICAgIC8vIE1hbnVhbCBvdmVycmlkZSBtb2RlXG4gICAgbmV3SW5zdHJ1Y3Rpb25zID0gaW5zdHJ1Y3Rpb25zX292ZXJyaWRlID8/IGN1cnJlbnRJbnN0cnVjdGlvbnM7XG4gICAgbmV3Q29udGVudCA9IGNvbnRlbnRfb3ZlcnJpZGUgPz8gY3VycmVudENvbnRlbnQ7XG4gIH0gZWxzZSB7XG4gICAgLy8gQXV0by1kZXRlY3Rpb246IGZpZWxkIHZhbHVlcyBzdGF5IHRoZSBzYW1lIOKAlCB0aGUgbWFuYWdlcnMgYWxyZWFkeSBhc3NpZ25lZCB0aGVcbiAgICAvLyBib2R5IHRleHQgdG8gdGhlIGNvcnJlY3QgZmllbGQgZHVyaW5nIGxvYWQgKHBlciBnZXRWMUJvZHlNYXBwaW5nKS4gVGhlIHVwZ3JhZGVcbiAgICAvLyBpcyB0aGUgcmUtc2F2ZSBpdHNlbGY6IHNlcmlhbGl6ZUVsZW1lbnQoKSB3cml0ZXMgaW5zdHJ1Y3Rpb25zIHRvIFlBTUwgZnJvbnRtYXR0ZXJcbiAgICAvLyBhbmQgY29udGVudCBhcyB0aGUgbWFya2Rvd24gYm9keSwgY29udmVydGluZyB0aGUgb24tZGlzayBmb3JtYXQgZnJvbSB2MSB0byB2Mi5cbiAgICBuZXdJbnN0cnVjdGlvbnMgPSBjdXJyZW50SW5zdHJ1Y3Rpb25zO1xuICAgIG5ld0NvbnRlbnQgPSBjdXJyZW50Q29udGVudDtcbiAgfVxuXG4gIGlmIChkcnlfcnVuKSB7XG4gICAgLy8gUHJldmlldyBtb2RlIOKAlCBzaG93IHdoYXQgd291bGQgY2hhbmdlXG4gICAgY29uc3QgY2hhbmdlczogc3RyaW5nW10gPSBbXTtcbiAgICBpZiAobmV3SW5zdHJ1Y3Rpb25zICE9PSBjdXJyZW50SW5zdHJ1Y3Rpb25zKSB7XG4gICAgICBjaGFuZ2VzLnB1c2goYCoqaW5zdHJ1Y3Rpb25zKio6IFwiJHt0cnVuY2F0ZShjdXJyZW50SW5zdHJ1Y3Rpb25zLCA4MCl9XCIg4oaSIFwiJHt0cnVuY2F0ZShuZXdJbnN0cnVjdGlvbnMsIDgwKX1cImApO1xuICAgIH1cbiAgICBpZiAobmV3Q29udGVudCAhPT0gY3VycmVudENvbnRlbnQpIHtcbiAgICAgIGNoYW5nZXMucHVzaChgKipjb250ZW50Kio6IFwiJHt0cnVuY2F0ZShjdXJyZW50Q29udGVudCwgODApfVwiIOKGkiBcIiR7dHJ1bmNhdGUobmV3Q29udGVudCwgODApfVwiYCk7XG4gICAgfVxuXG4gICAgY29uc3QgZGlzcGxheU5hbWUgPSAoZWxlbWVudCBhcyBhbnkpLm1ldGFkYXRhPy5uYW1lIHx8IG5hbWU7XG4gICAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKG5vcm1hbGl6ZWRUeXBlKTtcblxuICAgIGlmIChjaGFuZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29udGVudDogW3tcbiAgICAgICAgICB0eXBlOiAndGV4dCcsXG4gICAgICAgICAgdGV4dDogYOKEue+4jyAke2xhYmVsfSAnJHtkaXNwbGF5TmFtZX0nIOKAlCBubyBmaWVsZCBjaGFuZ2VzIG5lZWRlZCBmb3IgdXBncmFkZS5cXG5cXG5gICtcbiAgICAgICAgICAgIGBUaGUgZmlsZSB3aWxsIGJlIHJlLXNhdmVkIGluIHYyIGZvcm1hdCAoaW5zdHJ1Y3Rpb25zIGluIFlBTUwgZnJvbnRtYXR0ZXIsIGNvbnRlbnQgYXMgYm9keSkuXFxuXFxuYCArXG4gICAgICAgICAgICBgKippbnN0cnVjdGlvbnMqKiAoJHtuZXdJbnN0cnVjdGlvbnMubGVuZ3RofSBjaGFycyk6ICR7dHJ1bmNhdGUobmV3SW5zdHJ1Y3Rpb25zLCAxNTApfVxcbmAgK1xuICAgICAgICAgICAgYCoqY29udGVudCoqICgke25ld0NvbnRlbnQubGVuZ3RofSBjaGFycyk6ICR7dHJ1bmNhdGUobmV3Q29udGVudCwgMTUwKX1gXG4gICAgICAgIH1dXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBjb250ZW50OiBbe1xuICAgICAgICB0eXBlOiAndGV4dCcsXG4gICAgICAgIHRleHQ6IGDwn5SNIERyeSBydW4g4oCUICR7bGFiZWx9ICcke2Rpc3BsYXlOYW1lfScgdXBncmFkZSBwcmV2aWV3OlxcblxcbmAgK1xuICAgICAgICAgIGNoYW5nZXMuam9pbignXFxuJykgKyAnXFxuXFxuJyArXG4gICAgICAgICAgYFJ1biB3aXRob3V0IGRyeV9ydW4gdG8gYXBwbHkgdGhlc2UgY2hhbmdlcy5gXG4gICAgICB9XVxuICAgIH07XG4gIH1cblxuICAvLyBBcHBseSB1cGdyYWRlXG4gIChlbGVtZW50IGFzIGFueSkuaW5zdHJ1Y3Rpb25zID0gbmV3SW5zdHJ1Y3Rpb25zO1xuICAvLyBGb3IgTWVtb3J5LCBjb250ZW50IGlzIGEgZ2V0dGVyIOKAlCBza2lwIGRpcmVjdCBhc3NpZ25tZW50XG4gIGlmIChub3JtYWxpemVkVHlwZSAhPT0gRWxlbWVudFR5cGUuTUVNT1JZKSB7XG4gICAgKGVsZW1lbnQgYXMgYW55KS5jb250ZW50ID0gbmV3Q29udGVudDtcbiAgfVxuXG4gIC8vIERldGVybWluZSBmaWxlIHBhdGggZm9yIHNhdmluZ1xuICBjb25zdCBmaWxlUGF0aENhbmRpZGF0ZSA9IHR5cGVvZiAoZWxlbWVudCBhcyBhbnkpLmdldEZpbGVQYXRoID09PSAnZnVuY3Rpb24nXG4gICAgPyAoZWxlbWVudCBhcyBhbnkpLmdldEZpbGVQYXRoKClcbiAgICA6ICgoZWxlbWVudCBhcyBhbnkpLmZpbGVQYXRoIHx8IChlbGVtZW50IGFzIGFueSkuZmlsZW5hbWUpO1xuICBjb25zdCBmaWxlbmFtZSA9IHR5cGVvZiBmaWxlUGF0aENhbmRpZGF0ZSA9PT0gJ3N0cmluZycgJiYgZmlsZVBhdGhDYW5kaWRhdGUubGVuZ3RoID4gMFxuICAgID8gZmlsZVBhdGhDYW5kaWRhdGVcbiAgICA6ICcnO1xuXG4gIGlmICghZmlsZW5hbWUpIHtcbiAgICByZXR1cm4gZXJyb3IoYENhbm5vdCBkZXRlcm1pbmUgZmlsZSBwYXRoIGZvciAke2dldEVsZW1lbnRUeXBlTGFiZWwobm9ybWFsaXplZFR5cGUpfSAnJHtuYW1lfSdgKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgYXdhaXQgbWFuYWdlci5zYXZlKGVsZW1lbnQsIGZpbGVuYW1lKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuIGVycm9yKGBGYWlsZWQgdG8gc2F2ZSB1cGdyYWRlZCBlbGVtZW50OiAke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcid9YCk7XG4gIH1cblxuICBjb25zdCBkaXNwbGF5TmFtZSA9IChlbGVtZW50IGFzIGFueSkubWV0YWRhdGE/Lm5hbWUgfHwgbmFtZTtcbiAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKG5vcm1hbGl6ZWRUeXBlKTtcblxuICBsb2dnZXIuaW5mbyhgW3VwZ3JhZGVFbGVtZW50XSBVcGdyYWRlZCAke2xhYmVsfSAnJHtkaXNwbGF5TmFtZX0nIHRvIHYyIGR1YWwtZmllbGQgZm9ybWF0YCwge1xuICAgIGVsZW1lbnRUeXBlOiBub3JtYWxpemVkVHlwZSxcbiAgICBlbGVtZW50TmFtZTogZGlzcGxheU5hbWUsXG4gICAgaW5zdHJ1Y3Rpb25zTGVuZ3RoOiBuZXdJbnN0cnVjdGlvbnMubGVuZ3RoLFxuICAgIGNvbnRlbnRMZW5ndGg6IG5ld0NvbnRlbnQubGVuZ3RoLFxuICB9KTtcblxuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6IFt7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICB0ZXh0OiBg4pyFIFVwZ3JhZGVkICR7bGFiZWx9ICcke2Rpc3BsYXlOYW1lfScgdG8gdjIgZHVhbC1maWVsZCBmb3JtYXQuXFxuXFxuYCArXG4gICAgICAgIGAqKmluc3RydWN0aW9ucyoqICgke25ld0luc3RydWN0aW9ucy5sZW5ndGh9IGNoYXJzKTogJHt0cnVuY2F0ZShuZXdJbnN0cnVjdGlvbnMsIDE1MCl9XFxuYCArXG4gICAgICAgIGAqKmNvbnRlbnQqKiAoJHtuZXdDb250ZW50Lmxlbmd0aH0gY2hhcnMpOiAke3RydW5jYXRlKG5ld0NvbnRlbnQsIDE1MCl9YFxuICAgIH1dXG4gIH07XG59XG5cbmZ1bmN0aW9uIGVycm9yKG1lc3NhZ2U6IHN0cmluZykge1xuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6IFt7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICB0ZXh0OiBg4p2MICR7bWVzc2FnZX1gXG4gICAgfV1cbiAgfTtcbn1cblxuZnVuY3Rpb24gdHJ1bmNhdGUodGV4dDogc3RyaW5nLCBtYXhMZW5ndGg6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmICghdGV4dCkgcmV0dXJuICcoZW1wdHkpJztcbiAgaWYgKHRleHQubGVuZ3RoIDw9IG1heExlbmd0aCkgcmV0dXJuIHRleHQ7XG4gIHJldHVybiB0ZXh0LnNsaWNlKDAsIG1heExlbmd0aCkgKyAnLi4uJztcbn1cblxuZnVuY3Rpb24gZ2V0TWFuYWdlckZvclR5cGUoY29udGV4dDogRWxlbWVudENydWRDb250ZXh0LCB0eXBlOiBFbGVtZW50VHlwZSk6IEVsZW1lbnRNYW5hZ2VyV2l0aFBlcnNpc3RlbmNlPGFueT4gfCBudWxsIHtcbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSBFbGVtZW50VHlwZS5QRVJTT05BOlxuICAgICAgcmV0dXJuIGNvbnRleHQucGVyc29uYU1hbmFnZXIgYXMgRWxlbWVudE1hbmFnZXJXaXRoUGVyc2lzdGVuY2U8YW55PjtcbiAgICBjYXNlIEVsZW1lbnRUeXBlLlNLSUxMOlxuICAgICAgcmV0dXJuIGNvbnRleHQuc2tpbGxNYW5hZ2VyIGFzIEVsZW1lbnRNYW5hZ2VyV2l0aFBlcnNpc3RlbmNlPGFueT47XG4gICAgY2FzZSBFbGVtZW50VHlwZS5URU1QTEFURTpcbiAgICAgIHJldHVybiBjb250ZXh0LnRlbXBsYXRlTWFuYWdlciBhcyBFbGVtZW50TWFuYWdlcldpdGhQZXJzaXN0ZW5jZTxhbnk+O1xuICAgIGNhc2UgRWxlbWVudFR5cGUuQUdFTlQ6XG4gICAgICByZXR1cm4gY29udGV4dC5hZ2VudE1hbmFnZXIgYXMgRWxlbWVudE1hbmFnZXJXaXRoUGVyc2lzdGVuY2U8YW55PjtcbiAgICBjYXNlIEVsZW1lbnRUeXBlLk1FTU9SWTpcbiAgICAgIHJldHVybiBjb250ZXh0Lm1lbW9yeU1hbmFnZXIgYXMgRWxlbWVudE1hbmFnZXJXaXRoUGVyc2lzdGVuY2U8YW55PjtcbiAgICBjYXNlIEVsZW1lbnRUeXBlLkVOU0VNQkxFOlxuICAgICAgcmV0dXJuIGNvbnRleHQuZW5zZW1ibGVNYW5hZ2VyIGFzIEVsZW1lbnRNYW5hZ2VyV2l0aFBlcnNpc3RlbmNlPGFueT47XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBudWxsO1xuICB9XG59XG4iXX0=