UNPKG

@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.

120 lines 16.4 kB
/** * PortfolioDownloader - Downloads elements from GitHub repositories * * Handles fetching file contents from GitHub, decoding base64 content, * and returning structured element data ready for local storage. */ import { logger } from '../utils/logger.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; export class PortfolioDownloader { /** * Download an element from GitHub */ async downloadFromGitHub(repoManager, elementPath, username, repository) { try { logger.info('Downloading element from GitHub', { path: elementPath, username, repository }); // Fetch the file content from GitHub const response = await repoManager.githubRequest(`/repos/${username}/${repository}/contents/${elementPath}`); if (!response || !response.content) { throw new Error(`No content found at path: ${elementPath}`); } // Decode base64 content const decodedContent = Buffer.from(response.content, 'base64').toString('utf-8'); // Normalize Unicode for security const normalized = UnicodeValidator.normalize(decodedContent); // Log download for audit trail logger.info('Element downloaded successfully', { path: elementPath, repository: `${username}/${repository}`, sha: response.sha }); // Parse metadata from frontmatter if present const metadata = this.extractMetadata(normalized.normalizedContent); return { content: normalized.normalizedContent, metadata, sha: response.sha }; } catch (error) { logger.error('Failed to download element from GitHub', { error, path: elementPath }); // Re-throw with more context if (error instanceof Error) { if (error.message.includes('404')) { throw new Error(`Element not found at path: ${elementPath}`); } if (error.message.includes('401') || error.message.includes('403')) { throw new Error(`Authentication failed. Please check your GitHub token.`); } throw error; } throw new Error(`Failed to download ${elementPath}: ${String(error)}`); } } /** * Extract metadata from frontmatter */ extractMetadata(content) { const metadata = {}; // Check for YAML frontmatter const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/); if (frontmatterMatch) { try { // Parse the frontmatter as simple key-value pairs // (avoiding using yaml.load for security) const frontmatterContent = frontmatterMatch[1]; const lines = frontmatterContent.split('\n'); for (const line of lines) { const colonIndex = line.indexOf(':'); if (colonIndex > 0) { const key = line.substring(0, colonIndex).trim(); const value = line.substring(colonIndex + 1).trim(); // Remove quotes if present (e.g., "value" -> value, 'value' -> value) const cleanValue = value.replaceAll(/(^["'])|(['"]$)/g, ''); // Try to parse as JSON for arrays/objects, otherwise use as string try { metadata[key] = JSON.parse(cleanValue); } catch { metadata[key] = cleanValue; } } } } catch (error) { logger.warn('Failed to parse frontmatter metadata', { error }); } } return metadata; } /** * Download multiple elements in batch */ async downloadBatch(repoManager, elementPaths, username, repository, onProgress) { const results = new Map(); let downloaded = 0; for (const path of elementPaths) { try { const elementData = await this.downloadFromGitHub(repoManager, path, username, repository); results.set(path, elementData); downloaded++; if (onProgress) { onProgress(downloaded, elementPaths.length); } } catch (error) { logger.error(`Failed to download ${path}`, { error }); // Continue with other downloads even if one fails } } return results; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvRG93bmxvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jL1BvcnRmb2xpb0Rvd25sb2FkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFHSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFROUUsTUFBTSxPQUFPLG1CQUFtQjtJQUM5Qjs7T0FFRztJQUNILEtBQUssQ0FBQyxrQkFBa0IsQ0FDdEIsV0FBaUMsRUFDakMsV0FBbUIsRUFDbkIsUUFBZ0IsRUFDaEIsVUFBa0I7UUFFbEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRTtnQkFDN0MsSUFBSSxFQUFFLFdBQVc7Z0JBQ2pCLFFBQVE7Z0JBQ1IsVUFBVTthQUNYLENBQUMsQ0FBQztZQUVILHFDQUFxQztZQUNyQyxNQUFNLFFBQVEsR0FBRyxNQUFNLFdBQVcsQ0FBQyxhQUFhLENBQzlDLFVBQVUsUUFBUSxJQUFJLFVBQVUsYUFBYSxXQUFXLEVBQUUsQ0FDM0QsQ0FBQztZQUVGLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDOUQsQ0FBQztZQUVELHdCQUF3QjtZQUN4QixNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRWpGLGlDQUFpQztZQUNqQyxNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLENBQUM7WUFFOUQsK0JBQStCO1lBQy9CLE1BQU0sQ0FBQyxJQUFJLENB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QUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0NBQXNDLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ2pFLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGFBQWEsQ0FDakIsV0FBaUMsRUFDakMsWUFBc0IsRUFDdEIsUUFBZ0IsRUFDaEIsVUFBa0IsRUFDbEIsVUFBd0Q7UUFFeEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFDL0MsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBRW5CLEtBQUssTUFBTSxJQUFJLElBQUksWUFBWSxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDO2dCQUNILE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUMvQyxXQUFXLEVBQ1gsSUFBSSxFQUNKLFFBQVEsRUFDUixVQUFVLENBQ1gsQ0FBQztnQkFFRixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQztnQkFDL0IsVUFBVSxFQUFFLENBQUM7Z0JBRWIsSUFBSSxVQUFVLEVBQUUsQ0FBQztvQkFDZixVQUFVLENBQUMsVUFBVSxFQUFFLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDOUMsQ0FBQztZQUNILENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLElBQUksRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDdEQsa0RBQWtEO1lBQ3BELENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQb3J0Zm9saW9Eb3dubG9hZGVyIC0gRG93bmxvYWRzIGVsZW1lbnRzIGZyb20gR2l0SHViIHJlcG9zaXRvcmllc1xuICogXG4gKiBIYW5kbGVzIGZldGNoaW5nIGZpbGUgY29udGVudHMgZnJvbSBHaXRIdWIsIGRlY29kaW5nIGJhc2U2NCBjb250ZW50LFxuICogYW5kIHJldHVybmluZyBzdHJ1Y3R1cmVkIGVsZW1lbnQgZGF0YSByZWFkeSBmb3IgbG9jYWwgc3RvcmFnZS5cbiAqL1xuXG5pbXBvcnQgeyBQb3J0Zm9saW9SZXBvTWFuYWdlciB9IGZyb20gJy4uL3BvcnRmb2xpby9Qb3J0Zm9saW9SZXBvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRWxlbWVudERhdGEge1xuICBjb250ZW50OiBzdHJpbmc7XG4gIG1ldGFkYXRhOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICBzaGE6IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb0Rvd25sb2FkZXIge1xuICAvKipcbiAgICogRG93bmxvYWQgYW4gZWxlbWVudCBmcm9tIEdpdEh1YlxuICAgKi9cbiAgYXN5bmMgZG93bmxvYWRGcm9tR2l0SHViKFxuICAgIHJlcG9NYW5hZ2VyOiBQb3J0Zm9saW9SZXBvTWFuYWdlcixcbiAgICBlbGVtZW50UGF0aDogc3RyaW5nLFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcmVwb3NpdG9yeTogc3RyaW5nXG4gICk6IFByb21pc2U8RWxlbWVudERhdGE+IHtcbiAgICB0cnkge1xuICAgICAgbG9nZ2VyLmluZm8oJ0Rvd25sb2FkaW5nIGVsZW1lbnQgZnJvbSBHaXRIdWInLCB7XG4gICAgICAgIHBhdGg6IGVsZW1lbnRQYXRoLFxuICAgICAgICB1c2VybmFtZSxcbiAgICAgICAgcmVwb3NpdG9yeVxuICAgICAgfSk7XG5cbiAgICAgIC8vIEZldGNoIHRoZSBmaWxlIGNvbnRlbnQgZnJvbSBHaXRIdWJcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgcmVwb01hbmFnZXIuZ2l0aHViUmVxdWVzdChcbiAgICAgICAgYC9yZXBvcy8ke3VzZXJuYW1lfS8ke3JlcG9zaXRvcnl9L2NvbnRlbnRzLyR7ZWxlbWVudFBhdGh9YFxuICAgICAgKTtcblxuICAgICAgaWYgKCFyZXNwb25zZSB8fCAhcmVzcG9uc2UuY29udGVudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbnRlbnQgZm91bmQgYXQgcGF0aDogJHtlbGVtZW50UGF0aH1gKTtcbiAgICAgIH1cblxuICAgICAgLy8gRGVjb2RlIGJhc2U2NCBjb250ZW50XG4gICAgICBjb25zdCBkZWNvZGVkQ29udGVudCA9IEJ1ZmZlci5mcm9tKHJlc3BvbnNlLmNvbnRlbnQsICdiYXNlNjQnKS50b1N0cmluZygndXRmLTgnKTtcbiAgICAgIFxuICAgICAgLy8gTm9ybWFsaXplIFVuaWNvZGUgZm9yIHNlY3VyaXR5XG4gICAgICBjb25zdCBub3JtYWxpemVkID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoZGVjb2RlZENvbnRlbnQpO1xuICAgICAgXG4gICAgICAvLyBMb2cgZG93bmxvYWQgZm9yIGF1ZGl0IHRyYWlsXG4gICAgICBsb2dnZXIuaW5mbygnRWxlbWVudCBkb3dubG9hZGVkIHN1Y2Nlc3NmdWxseScsIHtcbiAgICAgICAgcGF0aDogZWxlbWVudFBhdGgsXG4gICAgICAgIHJlcG9zaXRvcnk6IGAke3VzZXJuYW1lfS8ke3JlcG9zaXRvcnl9YCxcbiAgICAgICAgc2hhOiByZXNwb25zZS5zaGFcbiAgICAgIH0pO1xuXG4gICAgICAvLyBQYXJzZSBtZXRhZGF0YSBmcm9tIGZyb250bWF0dGVyIGlmIHByZXNlbnRcbiAgICAgIGNvbnN0IG1ldGFkYXRhID0gdGhpcy5leHRyYWN0TWV0YWRhdGEobm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQsXG4gICAgICAgIG1ldGFkYXRhLFxuICAgICAgICBzaGE6IHJlc3BvbnNlLnNoYVxuICAgICAgfTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBkb3dubG9hZCBlbGVtZW50IGZyb20gR2l0SHViJywgeyBcbiAgICAgICAgZXJyb3IsIFxuICAgICAgICBwYXRoOiBlbGVtZW50UGF0aCBcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBSZS10aHJvdyB3aXRoIG1vcmUgY29udGV4dFxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJzQwNCcpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbGVtZW50IG5vdCBmb3VuZCBhdCBwYXRoOiAke2VsZW1lbnRQYXRofWApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCc0MDEnKSB8fCBlcnJvci5tZXNzYWdlLmluY2x1ZGVzKCc0MDMnKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQXV0aGVudGljYXRpb24gZmFpbGVkLiBQbGVhc2UgY2hlY2sgeW91ciBHaXRIdWIgdG9rZW4uYCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGRvd25sb2FkICR7ZWxlbWVudFBhdGh9OiAke1N0cmluZyhlcnJvcil9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgbWV0YWRhdGEgZnJvbSBmcm9udG1hdHRlclxuICAgKi9cbiAgcHJpdmF0ZSBleHRyYWN0TWV0YWRhdGEoY29udGVudDogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgY29uc3QgbWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICBcbiAgICAvLyBDaGVjayBmb3IgWUFNTCBmcm9udG1hdHRlclxuICAgIGNvbnN0IGZyb250bWF0dGVyTWF0Y2ggPSBjb250ZW50Lm1hdGNoKC9eLS0tXFxuKFtcXHNcXFNdKj8pXFxuLS0tLyk7XG4gICAgXG4gICAgaWYgKGZyb250bWF0dGVyTWF0Y2gpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFBhcnNlIHRoZSBmcm9udG1hdHRlciBhcyBzaW1wbGUga2V5LXZhbHVlIHBhaXJzXG4gICAgICAgIC8vIChhdm9pZGluZyB1c2luZyB5YW1sLmxvYWQgZm9yIHNlY3VyaXR5KVxuICAgICAgICBjb25zdCBmcm9udG1hdHRlckNvbnRlbnQgPSBmcm9udG1hdHRlck1hdGNoWzFdO1xuICAgICAgICBjb25zdCBsaW5lcyA9IGZyb250bWF0dGVyQ29udGVudC5zcGxpdCgnXFxuJyk7XG4gICAgICAgIFxuICAgICAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgICAgICBjb25zdCBjb2xvbkluZGV4ID0gbGluZS5pbmRleE9mKCc6Jyk7XG4gICAgICAgICAgaWYgKGNvbG9uSW5kZXggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBrZXkgPSBsaW5lLnN1YnN0cmluZygwLCBjb2xvbkluZGV4KS50cmltKCk7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGxpbmUuc3Vic3RyaW5nKGNvbG9uSW5kZXggKyAxKS50cmltKCk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIFJlbW92ZSBxdW90ZXMgaWYgcHJlc2VudCAoZS5nLiwgXCJ2YWx1ZVwiIC0+IHZhbHVlLCAndmFsdWUnIC0+IHZhbHVlKVxuICAgICAgICAgICAgY29uc3QgY2xlYW5WYWx1ZSA9IHZhbHVlLnJlcGxhY2VBbGwoLyheW1wiJ10pfChbJ1wiXSQpL2csICcnKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgLy8gVHJ5IHRvIHBhcnNlIGFzIEpTT04gZm9yIGFycmF5cy9vYmplY3RzLCBvdGhlcndpc2UgdXNlIGFzIHN0cmluZ1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgbWV0YWRhdGFba2V5XSA9IEpTT04ucGFyc2UoY2xlYW5WYWx1ZSk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgbWV0YWRhdGFba2V5XSA9IGNsZWFuVmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybignRmFpbGVkIHRvIHBhcnNlIGZyb250bWF0dGVyIG1ldGFkYXRhJywgeyBlcnJvciB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIG1ldGFkYXRhO1xuICB9XG5cbiAgLyoqXG4gICAqIERvd25sb2FkIG11bHRpcGxlIGVsZW1lbnRzIGluIGJhdGNoXG4gICAqL1xuICBhc3luYyBkb3dubG9hZEJhdGNoKFxuICAgIHJlcG9NYW5hZ2VyOiBQb3J0Zm9saW9SZXBvTWFuYWdlcixcbiAgICBlbGVtZW50UGF0aHM6IHN0cmluZ1tdLFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcmVwb3NpdG9yeTogc3RyaW5nLFxuICAgIG9uUHJvZ3Jlc3M/OiAoZG93bmxvYWRlZDogbnVtYmVyLCB0b3RhbDogbnVtYmVyKSA9PiB2b2lkXG4gICk6IFByb21pc2U8TWFwPHN0cmluZywgRWxlbWVudERhdGE+PiB7XG4gICAgY29uc3QgcmVzdWx0cyA9IG5ldyBNYXA8c3RyaW5nLCBFbGVtZW50RGF0YT4oKTtcbiAgICBsZXQgZG93bmxvYWRlZCA9IDA7XG4gICAgXG4gICAgZm9yIChjb25zdCBwYXRoIG9mIGVsZW1lbnRQYXRocykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZWxlbWVudERhdGEgPSBhd2FpdCB0aGlzLmRvd25sb2FkRnJvbUdpdEh1YihcbiAgICAgICAgICByZXBvTWFuYWdlcixcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIHVzZXJuYW1lLFxuICAgICAgICAgIHJlcG9zaXRvcnlcbiAgICAgICAgKTtcbiAgICAgICAgXG4gICAgICAgIHJlc3VsdHMuc2V0KHBhdGgsIGVsZW1lbnREYXRhKTtcbiAgICAgICAgZG93bmxvYWRlZCsrO1xuICAgICAgICBcbiAgICAgICAgaWYgKG9uUHJvZ3Jlc3MpIHtcbiAgICAgICAgICBvblByb2dyZXNzKGRvd25sb2FkZWQsIGVsZW1lbnRQYXRocy5sZW5ndGgpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBkb3dubG9hZCAke3BhdGh9YCwgeyBlcnJvciB9KTtcbiAgICAgICAgLy8gQ29udGludWUgd2l0aCBvdGhlciBkb3dubG9hZHMgZXZlbiBpZiBvbmUgZmFpbHNcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cbn0iXX0=