@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.
196 lines • 26.3 kB
JavaScript
/**
* V1→V2 Agent Converter
*
* Provides automatic in-memory conversion from V1 agent format (legacy goals/constraints)
* to V2 agent format (goal.template with parameters).
*
* UPGRADE STRATEGY:
* - V1 agents are auto-upgraded to V2 in place when executed
* - The original file is overwritten with the V2 format
* - Conversion is triggered by executeAgent(), not by read() or edit()
*
* @since v2.0.0 - Agent V2 Infrastructure
*/
import { logger } from '../../utils/logger.js';
/**
* Check if an agent is a V1 agent (legacy format without goal.template)
*
* @param metadata - Agent metadata to check
* @returns true if this is a V1 agent that needs conversion
*/
export function isV1Agent(metadata) {
const metadataV2 = metadata;
// V2 agents have goal.template defined
if (metadataV2.goal && typeof metadataV2.goal.template === 'string') {
return false;
}
// V1 agents might have goals (array) or decision framework but no goal.template
return true;
}
/**
* Convert V1 agent metadata to V2 format
*
* Generates a goal.template from the agent's instructions and creates
* a default parameter for the objective.
*
* @param metadata - V1 agent metadata
* @param instructions - Agent instructions content (from extensions.instructions)
* @returns Conversion result with V2 metadata
*/
export function convertV1ToV2(metadata, instructions) {
const warnings = [];
// Don't convert if already V2
if (!isV1Agent(metadata)) {
return {
converted: false,
metadata: {},
warnings: ['Agent is already V2 format, no conversion needed'],
};
}
// Log deprecation warnings for V1 fields
if (metadata.decisionFramework) {
warnings.push(`V1 field 'decisionFramework' (${metadata.decisionFramework}) preserved but deprecated. V2 uses LLM-driven decisions.`);
}
if (metadata.ruleEngineConfig) {
warnings.push(`V1 field 'ruleEngineConfig' preserved but deprecated. V2 constraints are handled by evaluateConstraints().`);
}
if (metadata.learningEnabled !== undefined) {
warnings.push(`V1 field 'learningEnabled' preserved but deprecated. LLM handles learning naturally in V2.`);
}
// Generate goal template from instructions
const goalTemplate = generateGoalTemplate(instructions, metadata.name);
// Create default parameter for objective
const defaultParameter = {
name: 'objective',
type: 'string',
required: true,
description: 'The specific objective or task to accomplish',
};
// Extract success criteria from instructions if present
const successCriteria = extractSuccessCriteria(instructions, metadata.name);
if (successCriteria.length === 0) {
warnings.push('No success criteria found in instructions. Consider adding explicit success criteria for better goal tracking.');
}
// Build the goal configuration
const goalConfig = {
template: goalTemplate,
parameters: [defaultParameter],
successCriteria: successCriteria.length > 0 ? successCriteria : undefined,
};
// Build V2 metadata (preserving V1 fields for backward compatibility)
const v2Metadata = {
goal: goalConfig,
// Preserve V1 fields
decisionFramework: metadata.decisionFramework,
specializations: metadata.specializations,
riskTolerance: metadata.riskTolerance,
learningEnabled: metadata.learningEnabled,
maxConcurrentGoals: metadata.maxConcurrentGoals,
triggers: metadata.triggers,
};
logger.info(`V1→V2 conversion completed for agent '${metadata.name}': template="${goalConfig.template}"`, {
agentName: metadata.name,
warningCount: warnings.length,
successCriteriaCount: successCriteria.length,
goalTemplate: goalConfig.template,
});
return {
converted: true,
metadata: v2Metadata,
warnings,
};
}
/**
* Generate a goal template from V1 instructions
*
* The template uses {objective} as the primary parameter placeholder.
*
* @param instructions - V1 agent instructions
* @returns Goal template string
*/
function generateGoalTemplate(instructions, agentName) {
// If instructions are empty, use a generic template
if (!instructions || instructions.trim().length === 0) {
logger.debug(`V1→V2 goal template [${agentName}]: empty instructions, using generic "Execute: {objective}" template`);
return 'Execute: {objective}';
}
// Check if instructions already contain a goal-like structure
const goalMatch = instructions.match(/^#?\s*goal:?\s*(.+)$/im);
if (goalMatch) {
// Extract the goal line and make it parameterized
const goalLine = goalMatch[1].trim();
logger.debug(`V1→V2 goal template [${agentName}]: extracted goal header from instructions`, { goalLine });
// Replace generic terms with parameter placeholder
if (!goalLine.includes('{objective}')) {
return `${goalLine}: {objective}`;
}
return goalLine;
}
// Check for a clear action statement in the first line
const firstLine = instructions.split('\n')[0].trim();
if (firstLine.length > 0 && firstLine.length <= 200) {
logger.debug(`V1→V2 goal template [${agentName}]: using first line of instructions as goal context`, { firstLine: firstLine.slice(0, 80) });
// Use first line as context, add objective parameter
return `${firstLine} - Objective: {objective}`;
}
// Default: generic template
logger.debug(`V1→V2 goal template [${agentName}]: no extractable goal pattern found (first line too long or empty), using generic template`, { instructionLength: instructions.length, preview: instructions.slice(0, 100) });
return 'Execute the following objective: {objective}';
}
/**
* Extract success criteria from V1 instructions
*
* Looks for common patterns:
* - "Success criteria:" followed by list
* - "Completed when:" statements
* - "Goals:" with list items
*
* @param instructions - V1 agent instructions
* @returns Array of success criteria strings
*/
function extractSuccessCriteria(instructions, agentName) {
const criteria = [];
// Look for "Success criteria:" section
const successMatch = instructions.match(/success\s+criteria:?\s*\n((?:[-*]\s*.+\n?)+)/im);
if (successMatch) {
const items = successMatch[1].match(/[-*]\s*(.+)/g);
if (items) {
for (const item of items) {
const text = item.replace(/^[-*]\s*/, '').trim();
if (text.length > 0) {
criteria.push(text);
}
}
}
}
// Look for "Completed when:" statements
const completedMatch = instructions.match(/completed?\s+when:?\s*(.+)/gi);
if (completedMatch) {
for (const match of completedMatch) {
const text = match.replace(/completed?\s+when:?\s*/i, '').trim();
if (text.length > 0 && !criteria.includes(text)) {
criteria.push(text);
}
}
}
// Look for numbered goals
const numberedGoals = instructions.match(/^\d+\.\s+(.+)$/gm);
if (numberedGoals && criteria.length === 0) {
// Only use numbered items if we haven't found other criteria
for (const goal of numberedGoals.slice(0, 5)) {
// Limit to first 5
const text = goal.replace(/^\d+\.\s+/, '').trim();
if (text.length > 0) {
criteria.push(text);
}
}
}
if (criteria.length === 0) {
logger.debug(`V1→V2 success criteria [${agentName}]: no patterns found (checked: 'Success criteria:' section, 'Completed when:' statements, numbered items)`, { instructionLength: instructions.length });
}
else {
logger.debug(`V1→V2 success criteria [${agentName}]: extracted ${criteria.length} criteria from instructions`, { criteria });
}
return criteria;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidjFUb1YyQ29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VsZW1lbnRzL2FnZW50cy92MVRvVjJDb252ZXJ0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBR0gsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBYy9DOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxRQUF5QztJQUNqRSxNQUFNLFVBQVUsR0FBRyxRQUEyQixDQUFDO0lBRS9DLHVDQUF1QztJQUN2QyxJQUFJLFVBQVUsQ0FBQyxJQUFJLElBQUksT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNwRSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxnRkFBZ0Y7SUFDaEYsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FDM0IsUUFBdUIsRUFDdkIsWUFBb0I7SUFFcEIsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBRTlCLDhCQUE4QjtJQUM5QixJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDekIsT0FBTztZQUNMLFNBQVMsRUFBRSxLQUFLO1lBQ2hCLFFBQVEsRUFBRSxFQUFFO1lBQ1osUUFBUSxFQUFFLENBQUMsa0RBQWtELENBQUM7U0FDL0QsQ0FBQztJQUNKLENBQUM7SUFFRCx5Q0FBeUM7SUFDekMsSUFBSSxRQUFRLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUMvQixRQUFRLENBQUMsSUFBSSxDQUNYLGlDQUFpQyxRQUFRLENBQUMsaUJBQWlCLDJEQUEyRCxDQUN2SCxDQUFDO0lBQ0osQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDOUIsUUFBUSxDQUFDLElBQUksQ0FDWCw0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R0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsRCxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BCLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdEIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLFNBQVMsMkdBQTJHLEVBQUUsRUFBRSxpQkFBaUIsRUFBRSxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM1TSxDQUFDO1NBQU0sQ0FBQztRQUNOLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLFNBQVMsZ0JBQWdCLFFBQVEsQ0FBQyxNQUFNLDZCQUE2QixFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUMvSCxDQUFDO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVjHihpJWMiBBZ2VudCBDb252ZXJ0ZXJcbiAqXG4gKiBQcm92aWRlcyBhdXRvbWF0aWMgaW4tbWVtb3J5IGNvbnZlcnNpb24gZnJvbSBWMSBhZ2VudCBmb3JtYXQgKGxlZ2FjeSBnb2Fscy9jb25zdHJhaW50cylcbiAqIHRvIFYyIGFnZW50IGZvcm1hdCAoZ29hbC50ZW1wbGF0ZSB3aXRoIHBhcmFtZXRlcnMpLlxuICpcbiAqIFVQR1JBREUgU1RSQVRFR1k6XG4gKiAtIFYxIGFnZW50cyBhcmUgYXV0by11cGdyYWRlZCB0byBWMiBpbiBwbGFjZSB3aGVuIGV4ZWN1dGVkXG4gKiAtIFRoZSBvcmlnaW5hbCBmaWxlIGlzIG92ZXJ3cml0dGVuIHdpdGggdGhlIFYyIGZvcm1hdFxuICogLSBDb252ZXJzaW9uIGlzIHRyaWdnZXJlZCBieSBleGVjdXRlQWdlbnQoKSwgbm90IGJ5IHJlYWQoKSBvciBlZGl0KClcbiAqXG4gKiBAc2luY2UgdjIuMC4wIC0gQWdlbnQgVjIgSW5mcmFzdHJ1Y3R1cmVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IEFnZW50TWV0YWRhdGEsIEFnZW50TWV0YWRhdGFWMiwgQWdlbnRHb2FsQ29uZmlnLCBBZ2VudEdvYWxQYXJhbWV0ZXIgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogUmVzdWx0IG9mIFYx4oaSVjIgY29udmVyc2lvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbnZlcnNpb25SZXN1bHQge1xuICAvKiogV2hldGhlciBjb252ZXJzaW9uIHdhcyBzdWNjZXNzZnVsICovXG4gIGNvbnZlcnRlZDogYm9vbGVhbjtcbiAgLyoqIFRoZSBjb252ZXJ0ZWQgVjIgbWV0YWRhdGEgKHBhcnRpYWwsIHRvIGJlIG1lcmdlZCB3aXRoIGV4aXN0aW5nKSAqL1xuICBtZXRhZGF0YTogUGFydGlhbDxBZ2VudE1ldGFkYXRhVjI+O1xuICAvKiogV2FybmluZ3MgZ2VuZXJhdGVkIGR1cmluZyBjb252ZXJzaW9uICovXG4gIHdhcm5pbmdzOiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhbiBhZ2VudCBpcyBhIFYxIGFnZW50IChsZWdhY3kgZm9ybWF0IHdpdGhvdXQgZ29hbC50ZW1wbGF0ZSlcbiAqXG4gKiBAcGFyYW0gbWV0YWRhdGEgLSBBZ2VudCBtZXRhZGF0YSB0byBjaGVja1xuICogQHJldHVybnMgdHJ1ZSBpZiB0aGlzIGlzIGEgVjEgYWdlbnQgdGhhdCBuZWVkcyBjb252ZXJzaW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1YxQWdlbnQobWV0YWRhdGE6IEFnZW50TWV0YWRhdGEgfCBBZ2VudE1ldGFkYXRhVjIpOiBib29sZWFuIHtcbiAgY29uc3QgbWV0YWRhdGFWMiA9IG1ldGFkYXRhIGFzIEFnZW50TWV0YWRhdGFWMjtcblxuICAvLyBWMiBhZ2VudHMgaGF2ZSBnb2FsLnRlbXBsYXRlIGRlZmluZWRcbiAgaWYgKG1ldGFkYXRhVjIuZ29hbCAmJiB0eXBlb2YgbWV0YWRhdGFWMi5nb2FsLnRlbXBsYXRlID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFYxIGFnZW50cyBtaWdodCBoYXZlIGdvYWxzIChhcnJheSkgb3IgZGVjaXNpb24gZnJhbWV3b3JrIGJ1dCBubyBnb2FsLnRlbXBsYXRlXG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIENvbnZlcnQgVjEgYWdlbnQgbWV0YWRhdGEgdG8gVjIgZm9ybWF0XG4gKlxuICogR2VuZXJhdGVzIGEgZ29hbC50ZW1wbGF0ZSBmcm9tIHRoZSBhZ2VudCdzIGluc3RydWN0aW9ucyBhbmQgY3JlYXRlc1xuICogYSBkZWZhdWx0IHBhcmFtZXRlciBmb3IgdGhlIG9iamVjdGl2ZS5cbiAqXG4gKiBAcGFyYW0gbWV0YWRhdGEgLSBWMSBhZ2VudCBtZXRhZGF0YVxuICogQHBhcmFtIGluc3RydWN0aW9ucyAtIEFnZW50IGluc3RydWN0aW9ucyBjb250ZW50IChmcm9tIGV4dGVuc2lvbnMuaW5zdHJ1Y3Rpb25zKVxuICogQHJldHVybnMgQ29udmVyc2lvbiByZXN1bHQgd2l0aCBWMiBtZXRhZGF0YVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udmVydFYxVG9WMihcbiAgbWV0YWRhdGE6IEFnZW50TWV0YWRhdGEsXG4gIGluc3RydWN0aW9uczogc3RyaW5nXG4pOiBDb252ZXJzaW9uUmVzdWx0IHtcbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gRG9uJ3QgY29udmVydCBpZiBhbHJlYWR5IFYyXG4gIGlmICghaXNWMUFnZW50KG1ldGFkYXRhKSkge1xuICAgIHJldHVybiB7XG4gICAgICBjb252ZXJ0ZWQ6IGZhbHNlLFxuICAgICAgbWV0YWRhdGE6IHt9LFxuICAgICAgd2FybmluZ3M6IFsnQWdlbnQgaXMgYWxyZWFkeSBWMiBmb3JtYXQsIG5vIGNvbnZlcnNpb24gbmVlZGVkJ10sXG4gICAgfTtcbiAgfVxuXG4gIC8vIExvZyBkZXByZWNhdGlvbiB3YXJuaW5ncyBmb3IgVjEgZmllbGRzXG4gIGlmIChtZXRhZGF0YS5kZWNpc2lvbkZyYW1ld29yaykge1xuICAgIHdhcm5pbmdzLnB1c2goXG4gICAgICBgVjEgZmllbGQgJ2RlY2lzaW9uRnJhbWV3b3JrJyAoJHttZXRhZGF0YS5kZWNpc2lvbkZyYW1ld29ya30pIHByZXNlcnZlZCBidXQgZGVwcmVjYXRlZC4gVjIgdXNlcyBMTE0tZHJpdmVuIGRlY2lzaW9ucy5gXG4gICAgKTtcbiAgfVxuICBpZiAobWV0YWRhdGEucnVsZUVuZ2luZUNvbmZpZykge1xuICAgIHdhcm5pbmdzLnB1c2goXG4gICAgICBgVjEgZmllbGQgJ3J1bGVFbmdpbmVDb25maWcnIHByZXNlcnZlZCBidXQgZGVwcmVjYXRlZC4gVjIgY29uc3RyYWludHMgYXJlIGhhbmRsZWQgYnkgZXZhbHVhdGVDb25zdHJhaW50cygpLmBcbiAgICApO1xuICB9XG4gIGlmIChtZXRhZGF0YS5sZWFybmluZ0VuYWJsZWQgIT09IHVuZGVmaW5lZCkge1xuICAgIHdhcm5pbmdzLnB1c2goXG4gICAgICBgVjEgZmllbGQgJ2xlYXJuaW5nRW5hYmxlZCcgcHJlc2VydmVkIGJ1dCBkZXByZWNhdGVkLiBMTE0gaGFuZGxlcyBsZWFybmluZyBuYXR1cmFsbHkgaW4gVjIuYFxuICAgICk7XG4gIH1cblxuICAvLyBHZW5lcmF0ZSBnb2FsIHRlbXBsYXRlIGZyb20gaW5zdHJ1Y3Rpb25zXG4gIGNvbnN0IGdvYWxUZW1wbGF0ZSA9IGdlbmVyYXRlR29hbFRlbXBsYXRlKGluc3RydWN0aW9ucywgbWV0YWRhdGEubmFtZSk7XG5cbiAgLy8gQ3JlYXRlIGRlZmF1bHQgcGFyYW1ldGVyIGZvciBvYmplY3RpdmVcbiAgY29uc3QgZGVmYXVsdFBhcmFtZXRlcjogQWdlbnRHb2FsUGFyYW1ldGVyID0ge1xuICAgIG5hbWU6ICdvYmplY3RpdmUnLFxuICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNwZWNpZmljIG9iamVjdGl2ZSBvciB0YXNrIHRvIGFjY29tcGxpc2gnLFxuICB9O1xuXG4gIC8vIEV4dHJhY3Qgc3VjY2VzcyBjcml0ZXJpYSBmcm9tIGluc3RydWN0aW9ucyBpZiBwcmVzZW50XG4gIGNvbnN0IHN1Y2Nlc3NDcml0ZXJpYSA9IGV4dHJhY3RTdWNjZXNzQ3JpdGVyaWEoaW5zdHJ1Y3Rpb25zLCBtZXRhZGF0YS5uYW1lKTtcbiAgaWYgKHN1Y2Nlc3NDcml0ZXJpYS5sZW5ndGggPT09IDApIHtcbiAgICB3YXJuaW5ncy5wdXNoKFxuICAgICAgJ05vIHN1Y2Nlc3MgY3JpdGVyaWEgZm91bmQgaW4gaW5zdHJ1Y3Rpb25zLiBDb25zaWRlciBhZGRpbmcgZXhwbGljaXQgc3VjY2VzcyBjcml0ZXJpYSBmb3IgYmV0dGVyIGdvYWwgdHJhY2tpbmcuJ1xuICAgICk7XG4gIH1cblxuICAvLyBCdWlsZCB0aGUgZ29hbCBjb25maWd1cmF0aW9uXG4gIGNvbnN0IGdvYWxDb25maWc6IEFnZW50R29hbENvbmZpZyA9IHtcbiAgICB0ZW1wbGF0ZTogZ29hbFRlbXBsYXRlLFxuICAgIHBhcmFtZXRlcnM6IFtkZWZhdWx0UGFyYW1ldGVyXSxcbiAgICBzdWNjZXNzQ3JpdGVyaWE6IHN1Y2Nlc3NDcml0ZXJpYS5sZW5ndGggPiAwID8gc3VjY2Vzc0NyaXRlcmlhIDogdW5kZWZpbmVkLFxuICB9O1xuXG4gIC8vIEJ1aWxkIFYyIG1ldGFkYXRhIChwcmVzZXJ2aW5nIFYxIGZpZWxkcyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSlcbiAgY29uc3QgdjJNZXRhZGF0YTogUGFydGlhbDxBZ2VudE1ldGFkYXRhVjI+ID0ge1xuICAgIGdvYWw6IGdvYWxDb25maWcsXG4gICAgLy8gUHJlc2VydmUgVjEgZmllbGRzXG4gICAgZGVjaXNpb25GcmFtZXdvcms6IG1ldGFkYXRhLmRlY2lzaW9uRnJhbWV3b3JrLFxuICAgIHNwZWNpYWxpemF0aW9uczogbWV0YWRhdGEuc3BlY2lhbGl6YXRpb25zLFxuICAgIHJpc2tUb2xlcmFuY2U6IG1ldGFkYXRhLnJpc2tUb2xlcmFuY2UsXG4gICAgbGVhcm5pbmdFbmFibGVkOiBtZXRhZGF0YS5sZWFybmluZ0VuYWJsZWQsXG4gICAgbWF4Q29uY3VycmVudEdvYWxzOiBtZXRhZGF0YS5tYXhDb25jdXJyZW50R29hbHMsXG4gICAgdHJpZ2dlcnM6IG1ldGFkYXRhLnRyaWdnZXJzLFxuICB9O1xuXG4gIGxvZ2dlci5pbmZvKGBWMeKGklYyIGNvbnZlcnNpb24gY29tcGxldGVkIGZvciBhZ2VudCAnJHttZXRhZGF0YS5uYW1lfSc6IHRlbXBsYXRlPVwiJHtnb2FsQ29uZmlnLnRlbXBsYXRlfVwiYCwge1xuICAgIGFnZW50TmFtZTogbWV0YWRhdGEubmFtZSxcbiAgICB3YXJuaW5nQ291bnQ6IHdhcm5pbmdzLmxlbmd0aCxcbiAgICBzdWNjZXNzQ3JpdGVyaWFDb3VudDogc3VjY2Vzc0NyaXRlcmlhLmxlbmd0aCxcbiAgICBnb2FsVGVtcGxhdGU6IGdvYWxDb25maWcudGVtcGxhdGUsXG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgY29udmVydGVkOiB0cnVlLFxuICAgIG1ldGFkYXRhOiB2Mk1ldGFkYXRhLFxuICAgIHdhcm5pbmdzLFxuICB9O1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgZ29hbCB0ZW1wbGF0ZSBmcm9tIFYxIGluc3RydWN0aW9uc1xuICpcbiAqIFRoZSB0ZW1wbGF0ZSB1c2VzIHtvYmplY3RpdmV9IGFzIHRoZSBwcmltYXJ5IHBhcmFtZXRlciBwbGFjZWhvbGRlci5cbiAqXG4gKiBAcGFyYW0gaW5zdHJ1Y3Rpb25zIC0gVjEgYWdlbnQgaW5zdHJ1Y3Rpb25zXG4gKiBAcmV0dXJucyBHb2FsIHRlbXBsYXRlIHN0cmluZ1xuICovXG5mdW5jdGlvbiBnZW5lcmF0ZUdvYWxUZW1wbGF0ZShpbnN0cnVjdGlvbnM6IHN0cmluZywgYWdlbnROYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAvLyBJZiBpbnN0cnVjdGlvbnMgYXJlIGVtcHR5LCB1c2UgYSBnZW5lcmljIHRlbXBsYXRlXG4gIGlmICghaW5zdHJ1Y3Rpb25zIHx8IGluc3RydWN0aW9ucy50cmltKCkubGVuZ3RoID09PSAwKSB7XG4gICAgbG9nZ2VyLmRlYnVnKGBWMeKGklYyIGdvYWwgdGVtcGxhdGUgWyR7YWdlbnROYW1lfV06IGVtcHR5IGluc3RydWN0aW9ucywgdXNpbmcgZ2VuZXJpYyBcIkV4ZWN1dGU6IHtvYmplY3RpdmV9XCIgdGVtcGxhdGVgKTtcbiAgICByZXR1cm4gJ0V4ZWN1dGU6IHtvYmplY3RpdmV9JztcbiAgfVxuXG4gIC8vIENoZWNrIGlmIGluc3RydWN0aW9ucyBhbHJlYWR5IGNvbnRhaW4gYSBnb2FsLWxpa2Ugc3RydWN0dXJlXG4gIGNvbnN0IGdvYWxNYXRjaCA9IGluc3RydWN0aW9ucy5tYXRjaCgvXiM/XFxzKmdvYWw6P1xccyooLispJC9pbSk7XG4gIGlmIChnb2FsTWF0Y2gpIHtcbiAgICAvLyBFeHRyYWN0IHRoZSBnb2FsIGxpbmUgYW5kIG1ha2UgaXQgcGFyYW1ldGVyaXplZFxuICAgIGNvbnN0IGdvYWxMaW5lID0gZ29hbE1hdGNoWzFdLnRyaW0oKTtcbiAgICBsb2dnZXIuZGVidWcoYFYx4oaSVjIgZ29hbCB0ZW1wbGF0ZSBbJHthZ2VudE5hbWV9XTogZXh0cmFjdGVkIGdvYWwgaGVhZGVyIGZyb20gaW5zdHJ1Y3Rpb25zYCwgeyBnb2FsTGluZSB9KTtcbiAgICAvLyBSZXBsYWNlIGdlbmVyaWMgdGVybXMgd2l0aCBwYXJhbWV0ZXIgcGxhY2Vob2xkZXJcbiAgICBpZiAoIWdvYWxMaW5lLmluY2x1ZGVzKCd7b2JqZWN0aXZlfScpKSB7XG4gICAgICByZXR1cm4gYCR7Z29hbExpbmV9OiB7b2JqZWN0aXZlfWA7XG4gICAgfVxuICAgIHJldHVybiBnb2FsTGluZTtcbiAgfVxuXG4gIC8vIENoZWNrIGZvciBhIGNsZWFyIGFjdGlvbiBzdGF0ZW1lbnQgaW4gdGhlIGZpcnN0IGxpbmVcbiAgY29uc3QgZmlyc3RMaW5lID0gaW5zdHJ1Y3Rpb25zLnNwbGl0KCdcXG4nKVswXS50cmltKCk7XG4gIGlmIChmaXJzdExpbmUubGVuZ3RoID4gMCAmJiBmaXJzdExpbmUubGVuZ3RoIDw9IDIwMCkge1xuICAgIGxvZ2dlci5kZWJ1ZyhgVjHihpJWMiBnb2FsIHRlbXBsYXRlIFske2FnZW50TmFtZX1dOiB1c2luZyBmaXJzdCBsaW5lIG9mIGluc3RydWN0aW9ucyBhcyBnb2FsIGNvbnRleHRgLCB7IGZpcnN0TGluZTogZmlyc3RMaW5lLnNsaWNlKDAsIDgwKSB9KTtcbiAgICAvLyBVc2UgZmlyc3QgbGluZSBhcyBjb250ZXh0LCBhZGQgb2JqZWN0aXZlIHBhcmFtZXRlclxuICAgIHJldHVybiBgJHtmaXJzdExpbmV9IC0gT2JqZWN0aXZlOiB7b2JqZWN0aXZlfWA7XG4gIH1cblxuICAvLyBEZWZhdWx0OiBnZW5lcmljIHRlbXBsYXRlXG4gIGxvZ2dlci5kZWJ1ZyhgVjHihpJWMiBnb2FsIHRlbXBsYXRlIFske2FnZW50TmFtZX1dOiBubyBleHRyYWN0YWJsZSBnb2FsIHBhdHRlcm4gZm91bmQgKGZpcnN0IGxpbmUgdG9vIGxvbmcgb3IgZW1wdHkpLCB1c2luZyBnZW5lcmljIHRlbXBsYXRlYCwgeyBpbnN0cnVjdGlvbkxlbmd0aDogaW5zdHJ1Y3Rpb25zLmxlbmd0aCwgcHJldmlldzogaW5zdHJ1Y3Rpb25zLnNsaWNlKDAsIDEwMCkgfSk7XG4gIHJldHVybiAnRXhlY3V0ZSB0aGUgZm9sbG93aW5nIG9iamVjdGl2ZToge29iamVjdGl2ZX0nO1xufVxuXG4vKipcbiAqIEV4dHJhY3Qgc3VjY2VzcyBjcml0ZXJpYSBmcm9tIFYxIGluc3RydWN0aW9uc1xuICpcbiAqIExvb2tzIGZvciBjb21tb24gcGF0dGVybnM6XG4gKiAtIFwiU3VjY2VzcyBjcml0ZXJpYTpcIiBmb2xsb3dlZCBieSBsaXN0XG4gKiAtIFwiQ29tcGxldGVkIHdoZW46XCIgc3RhdGVtZW50c1xuICogLSBcIkdvYWxzOlwiIHdpdGggbGlzdCBpdGVtc1xuICpcbiAqIEBwYXJhbSBpbnN0cnVjdGlvbnMgLSBWMSBhZ2VudCBpbnN0cnVjdGlvbnNcbiAqIEByZXR1cm5zIEFycmF5IG9mIHN1Y2Nlc3MgY3JpdGVyaWEgc3RyaW5nc1xuICovXG5mdW5jdGlvbiBleHRyYWN0U3VjY2Vzc0NyaXRlcmlhKGluc3RydWN0aW9uczogc3RyaW5nLCBhZ2VudE5hbWU6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgY29uc3QgY3JpdGVyaWE6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gTG9vayBmb3IgXCJTdWNjZXNzIGNyaXRlcmlhOlwiIHNlY3Rpb25cbiAgY29uc3Qgc3VjY2Vzc01hdGNoID0gaW5zdHJ1Y3Rpb25zLm1hdGNoKC9zdWNjZXNzXFxzK2NyaXRlcmlhOj9cXHMqXFxuKCg/OlstKl1cXHMqLitcXG4/KSspL2ltKTtcbiAgaWYgKHN1Y2Nlc3NNYXRjaCkge1xuICAgIGNvbnN0IGl0ZW1zID0gc3VjY2Vzc01hdGNoWzFdLm1hdGNoKC9bLSpdXFxzKiguKykvZyk7XG4gICAgaWYgKGl0ZW1zKSB7XG4gICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgaXRlbXMpIHtcbiAgICAgICAgY29uc3QgdGV4dCA9IGl0ZW0ucmVwbGFjZSgvXlstKl1cXHMqLywgJycpLnRyaW0oKTtcbiAgICAgICAgaWYgKHRleHQubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNyaXRlcmlhLnB1c2godGV4dCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBMb29rIGZvciBcIkNvbXBsZXRlZCB3aGVuOlwiIHN0YXRlbWVudHNcbiAgY29uc3QgY29tcGxldGVkTWF0Y2ggPSBpbnN0cnVjdGlvbnMubWF0Y2goL2NvbXBsZXRlZD9cXHMrd2hlbjo/XFxzKiguKykvZ2kpO1xuICBpZiAoY29tcGxldGVkTWF0Y2gpIHtcbiAgICBmb3IgKGNvbnN0IG1hdGNoIG9mIGNvbXBsZXRlZE1hdGNoKSB7XG4gICAgICBjb25zdCB0ZXh0ID0gbWF0Y2gucmVwbGFjZSgvY29tcGxldGVkP1xccyt3aGVuOj9cXHMqL2ksICcnKS50cmltKCk7XG4gICAgICBpZiAodGV4dC5sZW5ndGggPiAwICYmICFjcml0ZXJpYS5pbmNsdWRlcyh0ZXh0KSkge1xuICAgICAgICBjcml0ZXJpYS5wdXNoKHRleHQpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIExvb2sgZm9yIG51bWJlcmVkIGdvYWxzXG4gIGNvbnN0IG51bWJlcmVkR29hbHMgPSBpbnN0cnVjdGlvbnMubWF0Y2goL15cXGQrXFwuXFxzKyguKykkL2dtKTtcbiAgaWYgKG51bWJlcmVkR29hbHMgJiYgY3JpdGVyaWEubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gT25seSB1c2UgbnVtYmVyZWQgaXRlbXMgaWYgd2UgaGF2ZW4ndCBmb3VuZCBvdGhlciBjcml0ZXJpYVxuICAgIGZvciAoY29uc3QgZ29hbCBvZiBudW1iZXJlZEdvYWxzLnNsaWNlKDAsIDUpKSB7XG4gICAgICAvLyBMaW1pdCB0byBmaXJzdCA1XG4gICAgICBjb25zdCB0ZXh0ID0gZ29hbC5yZXBsYWNlKC9eXFxkK1xcLlxccysvLCAnJykudHJpbSgpO1xuICAgICAgaWYgKHRleHQubGVuZ3RoID4gMCkge1xuICAgICAgICBjcml0ZXJpYS5wdXNoKHRleHQpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmIChjcml0ZXJpYS5sZW5ndGggPT09IDApIHtcbiAgICBsb2dnZXIuZGVidWcoYFYx4oaSVjIgc3VjY2VzcyBjcml0ZXJpYSBbJHthZ2VudE5hbWV9XTogbm8gcGF0dGVybnMgZm91bmQgKGNoZWNrZWQ6ICdTdWNjZXNzIGNyaXRlcmlhOicgc2VjdGlvbiwgJ0NvbXBsZXRlZCB3aGVuOicgc3RhdGVtZW50cywgbnVtYmVyZWQgaXRlbXMpYCwgeyBpbnN0cnVjdGlvbkxlbmd0aDogaW5zdHJ1Y3Rpb25zLmxlbmd0aCB9KTtcbiAgfSBlbHNlIHtcbiAgICBsb2dnZXIuZGVidWcoYFYx4oaSVjIgc3VjY2VzcyBjcml0ZXJpYSBbJHthZ2VudE5hbWV9XTogZXh0cmFjdGVkICR7Y3JpdGVyaWEubGVuZ3RofSBjcml0ZXJpYSBmcm9tIGluc3RydWN0aW9uc2AsIHsgY3JpdGVyaWEgfSk7XG4gIH1cblxuICByZXR1cm4gY3JpdGVyaWE7XG59XG5cbiJdfQ==