@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.
141 lines • 19.3 kB
JavaScript
/**
* Standardized response formatting for element CRUD operations
*
* This module provides consistent response formatting across all element handlers,
* addressing the type confusion between CrudResponse and MCP response formats.
*/
import { getElementTypeLabel } from './helpers.js';
/**
* Bridge between CrudResponse and MCP format
* Converts structured CRUD responses to MCP tool responses
*/
export function crudResponseToMcp(response, options) {
if (response.success && response.data !== undefined) {
const text = options?.formatData
? options.formatData(response.data)
: `✅ Operation completed successfully`;
return {
content: [{ type: 'text', text }],
isError: false
};
}
// Error case
const errorPrefix = options?.context || 'Operation failed';
const errorMessage = response.error || 'Unknown error';
const errorCode = response.errorCode ? ` (${response.errorCode})` : '';
return {
content: [{
type: 'text',
text: `❌ ${errorPrefix}: ${errorMessage}${errorCode}`
}],
isError: true
};
}
/**
* Format a structured error response with consistent styling
*
* @param title - Bold title for the error (e.g., "Persona Not Found")
* @param message - Main error message
* @param suggestion - Optional suggestion for the user
* @returns Formatted MCP response
*/
export function formatErrorResponse(title, message, suggestion) {
let text = `❌ **${title}**\n\n${message}`;
if (suggestion) {
text += `\n\n${suggestion}`;
}
return {
content: [{ type: 'text', text }],
isError: true
};
}
/**
* Format a simple success message
*/
export function formatSuccessResponse(message) {
return {
content: [{ type: 'text', text: `✅ ${message}` }],
isError: false
};
}
/**
* Format a simple error message
*/
export function formatSimpleErrorResponse(message) {
return {
content: [{ type: 'text', text: `❌ ${message}` }],
isError: true
};
}
/**
* Format element not found error with consistent styling
*/
export function formatNotFoundError(type, name, listCommand) {
const typeLabel = getElementTypeLabel(type);
const suggestion = listCommand
? `Use \`${listCommand}\` to see available ${getElementTypeLabel(type, { plural: true })}.`
: `Check the ${typeLabel} name and try again.`;
return formatErrorResponse(`${typeLabel.charAt(0).toUpperCase() + typeLabel.slice(1)} Not Found`, `Could not find ${typeLabel}: "${name}"`, suggestion);
}
/**
* Issue #708: Format error for elements that exist on disk but failed validation.
* Distinct from "not found" — the file is present but the server can't load it.
*/
export function formatValidationFailedError(type, name, reason, filePath) {
const typeLabel = getElementTypeLabel(type);
const locationHint = filePath ? ` (file: ${filePath})` : '';
return formatErrorResponse(`${typeLabel.charAt(0).toUpperCase() + typeLabel.slice(1)} Invalid`, `The ${typeLabel} "${name}" exists on disk but failed to load${locationHint}: ${reason}`, 'Fix the file manually or re-create the element. Run `query_logs level="error"` for details.');
}
/**
* Format duplicate element error with consistent styling
*/
export function formatDuplicateError(type, name) {
const typeLabel = getElementTypeLabel(type);
return formatErrorResponse('Element Already Exists', `A ${typeLabel} named "${name}" already exists`, `Choose a different name or delete the existing ${typeLabel} first.`);
}
/**
* Format element creation success
*/
export function formatCreateSuccess(type, name) {
const typeLabel = getElementTypeLabel(type);
return formatSuccessResponse(`Created ${typeLabel} '${name}' successfully`);
}
/**
* Format element update success
*/
export function formatUpdateSuccess(type, name, field) {
const typeLabel = getElementTypeLabel(type);
const fieldInfo = field ? ` (updated ${field})` : '';
return formatSuccessResponse(`Updated ${typeLabel} '${name}'${fieldInfo} successfully`);
}
/**
* Format element deletion success
*/
export function formatDeleteSuccess(type, name) {
const typeLabel = getElementTypeLabel(type);
return formatSuccessResponse(`Deleted ${typeLabel} '${name}' successfully`);
}
/**
* Convert exception to formatted error response.
* Issue #668: When the error is about invalid characters in a name,
* suggest a corrected name so the caller can retry immediately.
*/
export function formatExceptionError(error, operation, type, name) {
const message = error instanceof Error ? error.message : String(error);
const context = type && name
? `Failed to ${operation} ${getElementTypeLabel(type)} '${name}'`
: `Failed to ${operation}`;
let suggestion = '';
if (name && message.includes('invalid characters')) {
// Replace disallowed characters with hyphens, collapse runs, trim edges
const corrected = name
.replace(/[^a-zA-Z0-9\s\-_.]+/g, '-')
.replace(/-{2,}/g, '-')
.replace(/^-|-$/g, '');
if (corrected && corrected !== name) {
suggestion = ` Suggested name: '${corrected}'`;
}
}
return formatSimpleErrorResponse(`${context}: ${message}${suggestion}`);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzcG9uc2VGb3JtYXR0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaGFuZGxlcnMvZWxlbWVudC1jcnVkL3Jlc3BvbnNlRm9ybWF0dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBSUgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBY25EOzs7R0FHRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FDL0IsUUFBeUIsRUFDekIsT0FHQztJQUVELElBQUksUUFBUSxDQUFDLE9BQU8sSUFBSSxRQUFRLENBQUMsSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3BELE1BQU0sSUFBSSxHQUFHLE9BQU8sRUFBRSxVQUFVO1lBQzlCLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDbkMsQ0FBQyxDQUFDLG9DQUFvQyxDQUFDO1FBRXpDLE9BQU87WUFDTCxPQUFPLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDakMsT0FBTyxFQUFFLEtBQUs7U0FDZixDQUFDO0lBQ0osQ0FBQztJQUVELGFBQWE7SUFDYixNQUFNLFdBQVcsR0FBRyxPQUFPLEVBQUUsT0FBTyxJQUFJLGtCQUFrQixDQUFDO0lBQzNELE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxLQUFLLElBQUksZUFBZSxDQUFDO0lBQ3ZELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFFdkUsT0FBTztRQUNMLE9BQU8sRUFBRSxDQUFDO2dCQUNSLElBQUksRUFBRSxNQUFNO2dCQUNaLElBQUksRUFBRSxLQUFLLFdBQVcsS0FBSyxZQUFZLEdBQUcsU0FBUyxFQUFFO2FBQ3RELENBQUM7UUFDRixPQUFP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N0IsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLElBQUksSUFBSSxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDO1FBQ25ELHdFQUF3RTtRQUN4RSxNQUFNLFNBQVMsR0FBRyxJQUFJO2FBQ25CLE9BQU8sQ0FBQyxzQkFBc0IsRUFBRSxHQUFHLENBQUM7YUFDcEMsT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUM7YUFDdEIsT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN6QixJQUFJLFNBQVMsSUFBSSxTQUFTLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDcEMsVUFBVSxHQUFHLHFCQUFxQixTQUFTLEdBQUcsQ0FBQztRQUNqRCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8seUJBQXlCLENBQUMsR0FBRyxPQUFPLEtBQUssT0FBTyxHQUFHLFVBQVUsRUFBRSxDQUFDLENBQUM7QUFDMUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3RhbmRhcmRpemVkIHJlc3BvbnNlIGZvcm1hdHRpbmcgZm9yIGVsZW1lbnQgQ1JVRCBvcGVyYXRpb25zXG4gKlxuICogVGhpcyBtb2R1bGUgcHJvdmlkZXMgY29uc2lzdGVudCByZXNwb25zZSBmb3JtYXR0aW5nIGFjcm9zcyBhbGwgZWxlbWVudCBoYW5kbGVycyxcbiAqIGFkZHJlc3NpbmcgdGhlIHR5cGUgY29uZnVzaW9uIGJldHdlZW4gQ3J1ZFJlc3BvbnNlIGFuZCBNQ1AgcmVzcG9uc2UgZm9ybWF0cy5cbiAqL1xuXG5pbXBvcnQgeyBDcnVkUmVzcG9uc2UgfSBmcm9tICcuLi8uLi90eXBlcy9DcnVkUmVzcG9uc2UuanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuLi8uLi9wb3J0Zm9saW8vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBnZXRFbGVtZW50VHlwZUxhYmVsIH0gZnJvbSAnLi9oZWxwZXJzLmpzJztcblxuLyoqXG4gKiBNQ1AgdG9vbCByZXNwb25zZSBmb3JtYXRcbiAqIFRoaXMgaXMgdGhlIGFjdHVhbCBmb3JtYXQgcmV0dXJuZWQgYnkgTUNQIHRvb2xzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWNwVG9vbFJlc3BvbnNlIHtcbiAgY29udGVudDogQXJyYXk8e1xuICAgIHR5cGU6ICd0ZXh0JztcbiAgICB0ZXh0OiBzdHJpbmc7XG4gIH0+O1xuICBpc0Vycm9yPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBCcmlkZ2UgYmV0d2VlbiBDcnVkUmVzcG9uc2UgYW5kIE1DUCBmb3JtYXRcbiAqIENvbnZlcnRzIHN0cnVjdHVyZWQgQ1JVRCByZXNwb25zZXMgdG8gTUNQIHRvb2wgcmVzcG9uc2VzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcnVkUmVzcG9uc2VUb01jcDxUPihcbiAgcmVzcG9uc2U6IENydWRSZXNwb25zZTxUPixcbiAgb3B0aW9ucz86IHtcbiAgICBmb3JtYXREYXRhPzogKGRhdGE6IFQpID0+IHN0cmluZztcbiAgICBjb250ZXh0Pzogc3RyaW5nO1xuICB9XG4pOiBNY3BUb29sUmVzcG9uc2Uge1xuICBpZiAocmVzcG9uc2Uuc3VjY2VzcyAmJiByZXNwb25zZS5kYXRhICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCB0ZXh0ID0gb3B0aW9ucz8uZm9ybWF0RGF0YVxuICAgICAgPyBvcHRpb25zLmZvcm1hdERhdGEocmVzcG9uc2UuZGF0YSlcbiAgICAgIDogYOKchSBPcGVyYXRpb24gY29tcGxldGVkIHN1Y2Nlc3NmdWxseWA7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3sgdHlwZTogJ3RleHQnLCB0ZXh0IH1dLFxuICAgICAgaXNFcnJvcjogZmFsc2VcbiAgICB9O1xuICB9XG5cbiAgLy8gRXJyb3IgY2FzZVxuICBjb25zdCBlcnJvclByZWZpeCA9IG9wdGlvbnM/LmNvbnRleHQgfHwgJ09wZXJhdGlvbiBmYWlsZWQnO1xuICBjb25zdCBlcnJvck1lc3NhZ2UgPSByZXNwb25zZS5lcnJvciB8fCAnVW5rbm93biBlcnJvcic7XG4gIGNvbnN0IGVycm9yQ29kZSA9IHJlc3BvbnNlLmVycm9yQ29kZSA/IGAgKCR7cmVzcG9uc2UuZXJyb3JDb2RlfSlgIDogJyc7XG5cbiAgcmV0dXJuIHtcbiAgICBjb250ZW50OiBbe1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgdGV4dDogYOKdjCAke2Vycm9yUHJlZml4fTogJHtlcnJvck1lc3NhZ2V9JHtlcnJvckNvZGV9YFxuICAgIH1dLFxuICAgIGlzRXJyb3I6IHRydWVcbiAgfTtcbn1cblxuLyoqXG4gKiBGb3JtYXQgYSBzdHJ1Y3R1cmVkIGVycm9yIHJlc3BvbnNlIHdpdGggY29uc2lzdGVudCBzdHlsaW5nXG4gKlxuICogQHBhcmFtIHRpdGxlIC0gQm9sZCB0aXRsZSBmb3IgdGhlIGVycm9yIChlLmcuLCBcIlBlcnNvbmEgTm90IEZvdW5kXCIpXG4gKiBAcGFyYW0gbWVzc2FnZSAtIE1haW4gZXJyb3IgbWVzc2FnZVxuICogQHBhcmFtIHN1Z2dlc3Rpb24gLSBPcHRpb25hbCBzdWdnZXN0aW9uIGZvciB0aGUgdXNlclxuICogQHJldHVybnMgRm9ybWF0dGVkIE1DUCByZXNwb25zZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0RXJyb3JSZXNwb25zZShcbiAgdGl0bGU6IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBzdWdnZXN0aW9uPzogc3RyaW5nXG4pOiBNY3BUb29sUmVzcG9uc2Uge1xuICBsZXQgdGV4dCA9IGDinYwgKioke3RpdGxlfSoqXFxuXFxuJHttZXNzYWdlfWA7XG5cbiAgaWYgKHN1Z2dlc3Rpb24pIHtcbiAgICB0ZXh0ICs9IGBcXG5cXG4ke3N1Z2dlc3Rpb259YDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgY29udGVudDogW3sgdHlwZTogJ3RleHQnLCB0ZXh0IH1dLFxuICAgIGlzRXJyb3I6IHRydWVcbiAgfTtcbn1cblxuLyoqXG4gKiBGb3JtYXQgYSBzaW1wbGUgc3VjY2VzcyBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRTdWNjZXNzUmVzcG9uc2UobWVzc2FnZTogc3RyaW5nKTogTWNwVG9vbFJlc3BvbnNlIHtcbiAgcmV0dXJuIHtcbiAgICBjb250ZW50OiBbeyB0eXBlOiAndGV4dCcsIHRleHQ6IGDinIUgJHttZXNzYWdlfWAgfV0sXG4gICAgaXNFcnJvcjogZmFsc2VcbiAgfTtcbn1cblxuLyoqXG4gKiBGb3JtYXQgYSBzaW1wbGUgZXJyb3IgbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0U2ltcGxlRXJyb3JSZXNwb25zZShtZXNzYWdlOiBzdHJpbmcpOiBNY3BUb29sUmVzcG9uc2Uge1xuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6IFt7IHR5cGU6ICd0ZXh0JywgdGV4dDogYOKdjCAke21lc3NhZ2V9YCB9XSxcbiAgICBpc0Vycm9yOiB0cnVlXG4gIH07XG59XG5cbi8qKlxuICogRm9ybWF0IGVsZW1lbnQgbm90IGZvdW5kIGVycm9yIHdpdGggY29uc2lzdGVudCBzdHlsaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXROb3RGb3VuZEVycm9yKFxuICB0eXBlOiBFbGVtZW50VHlwZSxcbiAgbmFtZTogc3RyaW5nLFxuICBsaXN0Q29tbWFuZD86IHN0cmluZ1xuKTogTWNwVG9vbFJlc3BvbnNlIHtcbiAgY29uc3QgdHlwZUxhYmVsID0gZ2V0RWxlbWVudFR5cGVMYWJlbCh0eXBlKTtcbiAgY29uc3Qgc3VnZ2VzdGlvbiA9IGxpc3RDb21tYW5kXG4gICAgPyBgVXNlIFxcYCR7bGlzdENvbW1hbmR9XFxgIHRvIHNlZSBhdmFpbGFibGUgJHtnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUsIHsgcGx1cmFsOiB0cnVlIH0pfS5gXG4gICAgOiBgQ2hlY2sgdGhlICR7dHlwZUxhYmVsfSBuYW1lIGFuZCB0cnkgYWdhaW4uYDtcblxuICByZXR1cm4gZm9ybWF0RXJyb3JSZXNwb25zZShcbiAgICBgJHt0eXBlTGFiZWwuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyB0eXBlTGFiZWwuc2xpY2UoMSl9IE5vdCBGb3VuZGAsXG4gICAgYENvdWxkIG5vdCBmaW5kICR7dHlwZUxhYmVsfTogXCIke25hbWV9XCJgLFxuICAgIHN1Z2dlc3Rpb25cbiAgKTtcbn1cblxuLyoqXG4gKiBJc3N1ZSAjNzA4OiBGb3JtYXQgZXJyb3IgZm9yIGVsZW1lbnRzIHRoYXQgZXhpc3Qgb24gZGlzayBidXQgZmFpbGVkIHZhbGlkYXRpb24uXG4gKiBEaXN0aW5jdCBmcm9tIFwibm90IGZvdW5kXCIg4oCUIHRoZSBmaWxlIGlzIHByZXNlbnQgYnV0IHRoZSBzZXJ2ZXIgY2FuJ3QgbG9hZCBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFZhbGlkYXRpb25GYWlsZWRFcnJvcihcbiAgdHlwZTogRWxlbWVudFR5cGUsXG4gIG5hbWU6IHN0cmluZyxcbiAgcmVhc29uOiBzdHJpbmcsXG4gIGZpbGVQYXRoPzogc3RyaW5nXG4pOiBNY3BUb29sUmVzcG9uc2Uge1xuICBjb25zdCB0eXBlTGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuICBjb25zdCBsb2NhdGlvbkhpbnQgPSBmaWxlUGF0aCA/IGAgKGZpbGU6ICR7ZmlsZVBhdGh9KWAgOiAnJztcbiAgcmV0dXJuIGZvcm1hdEVycm9yUmVzcG9uc2UoXG4gICAgYCR7dHlwZUxhYmVsLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgdHlwZUxhYmVsLnNsaWNlKDEpfSBJbnZhbGlkYCxcbiAgICBgVGhlICR7dHlwZUxhYmVsfSBcIiR7bmFtZX1cIiBleGlzdHMgb24gZGlzayBidXQgZmFpbGVkIHRvIGxvYWQke2xvY2F0aW9uSGludH06ICR7cmVhc29ufWAsXG4gICAgJ0ZpeCB0aGUgZmlsZSBtYW51YWxseSBvciByZS1jcmVhdGUgdGhlIGVsZW1lbnQuIFJ1biBgcXVlcnlfbG9ncyBsZXZlbD1cImVycm9yXCJgIGZvciBkZXRhaWxzLidcbiAgKTtcbn1cblxuLyoqXG4gKiBGb3JtYXQgZHVwbGljYXRlIGVsZW1lbnQgZXJyb3Igd2l0aCBjb25zaXN0ZW50IHN0eWxpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdER1cGxpY2F0ZUVycm9yKFxuICB0eXBlOiBFbGVtZW50VHlwZSxcbiAgbmFtZTogc3RyaW5nXG4pOiBNY3BUb29sUmVzcG9uc2Uge1xuICBjb25zdCB0eXBlTGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuXG4gIHJldHVybiBmb3JtYXRFcnJvclJlc3BvbnNlKFxuICAgICdFbGVtZW50IEFscmVhZHkgRXhpc3RzJyxcbiAgICBgQSAke3R5cGVMYWJlbH0gbmFtZWQgXCIke25hbWV9XCIgYWxyZWFkeSBleGlzdHNgLFxuICAgIGBDaG9vc2UgYSBkaWZmZXJlbnQgbmFtZSBvciBkZWxldGUgdGhlIGV4aXN0aW5nICR7dHlwZUxhYmVsfSBmaXJzdC5gXG4gICk7XG59XG5cbi8qKlxuICogRm9ybWF0IGVsZW1lbnQgY3JlYXRpb24gc3VjY2Vzc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0Q3JlYXRlU3VjY2VzcyhcbiAgdHlwZTogRWxlbWVudFR5cGUsXG4gIG5hbWU6IHN0cmluZ1xuKTogTWNwVG9vbFJlc3BvbnNlIHtcbiAgY29uc3QgdHlwZUxhYmVsID0gZ2V0RWxlbWVudFR5cGVMYWJlbCh0eXBlKTtcbiAgcmV0dXJuIGZvcm1hdFN1Y2Nlc3NSZXNwb25zZShgQ3JlYXRlZCAke3R5cGVMYWJlbH0gJyR7bmFtZX0nIHN1Y2Nlc3NmdWxseWApO1xufVxuXG4vKipcbiAqIEZvcm1hdCBlbGVtZW50IHVwZGF0ZSBzdWNjZXNzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRVcGRhdGVTdWNjZXNzKFxuICB0eXBlOiBFbGVtZW50VHlwZSxcbiAgbmFtZTogc3RyaW5nLFxuICBmaWVsZD86IHN0cmluZ1xuKTogTWNwVG9vbFJlc3BvbnNlIHtcbiAgY29uc3QgdHlwZUxhYmVsID0gZ2V0RWxlbWVudFR5cGVMYWJlbCh0eXBlKTtcbiAgY29uc3QgZmllbGRJbmZvID0gZmllbGQgPyBgICh1cGRhdGVkICR7ZmllbGR9KWAgOiAnJztcbiAgcmV0dXJuIGZvcm1hdFN1Y2Nlc3NSZXNwb25zZShgVXBkYXRlZCAke3R5cGVMYWJlbH0gJyR7bmFtZX0nJHtmaWVsZEluZm99IHN1Y2Nlc3NmdWxseWApO1xufVxuXG4vKipcbiAqIEZvcm1hdCBlbGVtZW50IGRlbGV0aW9uIHN1Y2Nlc3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdERlbGV0ZVN1Y2Nlc3MoXG4gIHR5cGU6IEVsZW1lbnRUeXBlLFxuICBuYW1lOiBzdHJpbmdcbik6IE1jcFRvb2xSZXNwb25zZSB7XG4gIGNvbnN0IHR5cGVMYWJlbCA9IGdldEVsZW1lbnRUeXBlTGFiZWwodHlwZSk7XG4gIHJldHVybiBmb3JtYXRTdWNjZXNzUmVzcG9uc2UoYERlbGV0ZWQgJHt0eXBlTGFiZWx9ICcke25hbWV9JyBzdWNjZXNzZnVsbHlgKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGV4Y2VwdGlvbiB0byBmb3JtYXR0ZWQgZXJyb3IgcmVzcG9uc2UuXG4gKiBJc3N1ZSAjNjY4OiBXaGVuIHRoZSBlcnJvciBpcyBhYm91dCBpbnZhbGlkIGNoYXJhY3RlcnMgaW4gYSBuYW1lLFxuICogc3VnZ2VzdCBhIGNvcnJlY3RlZCBuYW1lIHNvIHRoZSBjYWxsZXIgY2FuIHJldHJ5IGltbWVkaWF0ZWx5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0RXhjZXB0aW9uRXJyb3IoXG4gIGVycm9yOiB1bmtub3duLFxuICBvcGVyYXRpb246IHN0cmluZyxcbiAgdHlwZT86IEVsZW1lbnRUeXBlLFxuICBuYW1lPzogc3RyaW5nXG4pOiBNY3BUb29sUmVzcG9uc2Uge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICBjb25zdCBjb250ZXh0ID0gdHlwZSAmJiBuYW1lXG4gICAgPyBgRmFpbGVkIHRvICR7b3BlcmF0aW9ufSAke2dldEVsZW1lbnRUeXBlTGFiZWwodHlwZSl9ICcke25hbWV9J2BcbiAgICA6IGBGYWlsZWQgdG8gJHtvcGVyYXRpb259YDtcblxuICBsZXQgc3VnZ2VzdGlvbiA9ICcnO1xuICBpZiAobmFtZSAmJiBtZXNzYWdlLmluY2x1ZGVzKCdpbnZhbGlkIGNoYXJhY3RlcnMnKSkge1xuICAgIC8vIFJlcGxhY2UgZGlzYWxsb3dlZCBjaGFyYWN0ZXJzIHdpdGggaHlwaGVucywgY29sbGFwc2UgcnVucywgdHJpbSBlZGdlc1xuICAgIGNvbnN0IGNvcnJlY3RlZCA9IG5hbWVcbiAgICAgIC5yZXBsYWNlKC9bXmEtekEtWjAtOVxcc1xcLV8uXSsvZywgJy0nKVxuICAgICAgLnJlcGxhY2UoLy17Mix9L2csICctJylcbiAgICAgIC5yZXBsYWNlKC9eLXwtJC9nLCAnJyk7XG4gICAgaWYgKGNvcnJlY3RlZCAmJiBjb3JyZWN0ZWQgIT09IG5hbWUpIHtcbiAgICAgIHN1Z2dlc3Rpb24gPSBgIFN1Z2dlc3RlZCBuYW1lOiAnJHtjb3JyZWN0ZWR9J2A7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGZvcm1hdFNpbXBsZUVycm9yUmVzcG9uc2UoYCR7Y29udGV4dH06ICR7bWVzc2FnZX0ke3N1Z2dlc3Rpb259YCk7XG59XG4iXX0=