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.

112 lines 15.1 kB
import { formatIndicator } from '../config/indicator-config.js'; import { ElementType } from '../portfolio/types.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; /** * SOURCE OF TRUTH for persona indicator formatting. Mirrors the * HandlerContext.getPersonaIndicator responsibility so handlers can rely on * explicit constructor injection instead of the service locator pattern. */ export class PersonaIndicatorService { personaManager; indicatorConfig; notifier; eventDispatcher; cachedIndicator = null; cachedPersonaId = null; boundListener; boundElementListener; elementUnsubscribes = []; fallbackProvider; constructor(personaManager, indicatorConfig, notifier, eventDispatcher) { this.personaManager = personaManager; this.indicatorConfig = indicatorConfig; this.notifier = notifier; this.eventDispatcher = eventDispatcher; if (this.notifier) { this.boundListener = this.handlePersonaChange.bind(this); this.notifier.on('state-change:persona-activated', this.boundListener); this.notifier.on('state-change:persona-deactivated', this.boundListener); this.notifier.on('state-change:user-changed', this.boundListener); } if (this.eventDispatcher) { this.boundElementListener = this.handleElementEvent.bind(this); this.elementUnsubscribes.push(this.eventDispatcher.on('element:activate', this.boundElementListener), this.eventDispatcher.on('element:deactivate', this.boundElementListener)); } } getPersonaIndicator() { const persona = this.personaManager.getActivePersona(); if (!persona) { return this.fallbackProvider ? this.fallbackProvider() : ''; } if (this.cachedIndicator !== null && this.cachedPersonaId === persona.filename) { return this.cachedIndicator; } const indicator = formatIndicator(this.indicatorConfig, { name: persona.metadata.name, version: persona.metadata.version, author: persona.metadata.author, category: persona.metadata.category, }); this.cachedIndicator = indicator; this.cachedPersonaId = persona.filename; return indicator; } /** * Get the current indicator configuration. * Used by ConfigHandler to read current settings before applying updates. * * @returns Current IndicatorConfig */ getConfig() { return { ...this.indicatorConfig }; } updateConfig(config) { // FIX: DMCP-SEC-006 - Add security audit logging for configuration changes SecurityMonitor.logSecurityEvent({ type: 'CONFIG_UPDATED', severity: 'LOW', source: 'PersonaIndicatorService.updateConfig', details: `Indicator configuration updated: style=${config.style}, enabled=${config.enabled}`, additionalData: { style: config.style, enabled: config.enabled, showVersion: config.showVersion, showAuthor: config.showAuthor } }); this.indicatorConfig = config; this.invalidateCache(); } setFallbackProvider(provider) { this.fallbackProvider = provider; this.invalidateCache(); } invalidateCache() { this.cachedIndicator = null; this.cachedPersonaId = null; } async dispose() { if (this.boundListener && this.notifier) { this.notifier.off('state-change:persona-activated', this.boundListener); this.notifier.off('state-change:persona-deactivated', this.boundListener); this.notifier.off('state-change:user-changed', this.boundListener); } while (this.elementUnsubscribes.length > 0) { const unsubscribe = this.elementUnsubscribes.pop(); if (unsubscribe) { unsubscribe(); } } this.invalidateCache(); } handlePersonaChange(_event) { this.invalidateCache(); } handleElementEvent(payload) { if (payload.elementType !== ElementType.PERSONA) { return; } this.invalidateCache(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYUluZGljYXRvclNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvUGVyc29uYUluZGljYXRvclNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFtQixlQUFlLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQU9qRixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWpFOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sdUJBQXVCO0lBU3hCO0lBQ0E7SUFDQTtJQUNBO0lBWEYsZUFBZSxHQUFrQixJQUFJLENBQUM7SUFDdEMsZUFBZSxHQUFrQixJQUFJLENBQUM7SUFDN0IsYUFBYSxDQUE0QztJQUN6RCxvQkFBb0IsQ0FBMEM7SUFDOUQsbUJBQW1CLEdBQXNCLEVBQUUsQ0FBQztJQUNyRCxnQkFBZ0IsQ0FBZ0I7SUFFeEMsWUFDVSxjQUE4QixFQUM5QixlQUFnQyxFQUNoQyxRQUE4QixFQUM5QixlQUF3QztRQUh4QyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBQ2hDLGFBQVEsR0FBUixRQUFRLENBQXNCO1FBQzlCLG9CQUFlLEdBQWYsZUFBZSxDQUF5QjtRQUVoRCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNsQixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDekQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsZ0NBQWdDLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQ3ZFLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLGtDQUFrQyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUN6RSxJQUFJ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LENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN4QyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDeEUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsa0NBQWtDLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzFFLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLDJCQUEyQixFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNyRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzNDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNuRCxJQUFJLFdBQVcsRUFBRSxDQUFDO2dCQUNoQixXQUFXLEVBQUUsQ0FBQztZQUNoQixDQUFDO1FBQ0gsQ0FBQztRQUNELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRU8sbUJBQW1CLENBQUMsTUFBK0I7UUFDekQsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTyxrQkFBa0IsQ0FBQyxPQUE0QjtRQUNyRCxJQUFJLE9BQU8sQ0FBQyxXQUFXLEtBQUssV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2hELE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluZGljYXRvckNvbmZpZywgZm9ybWF0SW5kaWNhdG9yIH0gZnJvbSAnLi4vY29uZmlnL2luZGljYXRvci1jb25maWcuanMnO1xuaW1wb3J0IHsgUGVyc29uYU1hbmFnZXIgfSBmcm9tICcuLi9wZXJzb25hL1BlcnNvbmFNYW5hZ2VyLmpzJztcbmltcG9ydCB7XG4gIFN0YXRlQ2hhbmdlTm90aWZpZXIsXG4gIHR5cGUgUGVyc29uYVN0YXRlQ2hhbmdlRXZlbnQsXG59IGZyb20gJy4vU3RhdGVDaGFuZ2VOb3RpZmllci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50RXZlbnREaXNwYXRjaGVyLCB0eXBlIEVsZW1lbnRFdmVudFBheWxvYWQgfSBmcm9tICcuLi9ldmVudHMvRWxlbWVudEV2ZW50RGlzcGF0Y2hlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuXG4vKipcbiAqIFNPVVJDRSBPRiBUUlVUSCBmb3IgcGVyc29uYSBpbmRpY2F0b3IgZm9ybWF0dGluZy4gTWlycm9ycyB0aGVcbiAqIEhhbmRsZXJDb250ZXh0LmdldFBlcnNvbmFJbmRpY2F0b3IgcmVzcG9uc2liaWxpdHkgc28gaGFuZGxlcnMgY2FuIHJlbHkgb25cbiAqIGV4cGxpY2l0IGNvbnN0cnVjdG9yIGluamVjdGlvbiBpbnN0ZWFkIG9mIHRoZSBzZXJ2aWNlIGxvY2F0b3IgcGF0dGVybi5cbiAqL1xuZXhwb3J0IGNsYXNzIFBlcnNvbmFJbmRpY2F0b3JTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBjYWNoZWRJbmRpY2F0b3I6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGNhY2hlZFBlcnNvbmFJZDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcmVhZG9ubHkgYm91bmRMaXN0ZW5lcj86IChldmVudDogUGVyc29uYVN0YXRlQ2hhbmdlRXZlbnQpID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgYm91bmRFbGVtZW50TGlzdGVuZXI/OiAocGF5bG9hZDogRWxlbWVudEV2ZW50UGF5bG9hZCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBlbGVtZW50VW5zdWJzY3JpYmVzOiBBcnJheTwoKSA9PiB2b2lkPiA9IFtdO1xuICBwcml2YXRlIGZhbGxiYWNrUHJvdmlkZXI/OiAoKSA9PiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBwZXJzb25hTWFuYWdlcjogUGVyc29uYU1hbmFnZXIsXG4gICAgcHJpdmF0ZSBpbmRpY2F0b3JDb25maWc6IEluZGljYXRvckNvbmZpZyxcbiAgICBwcml2YXRlIG5vdGlmaWVyPzogU3RhdGVDaGFuZ2VOb3RpZmllcixcbiAgICBwcml2YXRlIGV2ZW50RGlzcGF0Y2hlcj86IEVsZW1lbnRFdmVudERpc3BhdGNoZXJcbiAgKSB7XG4gICAgaWYgKHRoaXMubm90aWZpZXIpIHtcbiAgICAgIHRoaXMuYm91bmRMaXN0ZW5lciA9IHRoaXMuaGFuZGxlUGVyc29uYUNoYW5nZS5iaW5kKHRoaXMpO1xuICAgICAgdGhpcy5ub3RpZmllci5vbignc3RhdGUtY2hhbmdlOnBlcnNvbmEtYWN0aXZhdGVkJywgdGhpcy5ib3VuZExpc3RlbmVyKTtcbiAgICAgIHRoaXMubm90aWZpZXIub24oJ3N0YXRlLWNoYW5nZTpwZXJzb25hLWRlYWN0aXZhdGVkJywgdGhpcy5ib3VuZExpc3RlbmVyKTtcbiAgICAgIHRoaXMubm90aWZpZXIub24oJ3N0YXRlLWNoYW5nZTp1c2VyLWNoYW5nZWQnLCB0aGlzLmJvdW5kTGlzdGVuZXIpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmV2ZW50RGlzcGF0Y2hlcikge1xuICAgICAgdGhpcy5ib3VuZEVsZW1lbnRMaXN0ZW5lciA9IHRoaXMuaGFuZGxlRWxlbWVudEV2ZW50LmJpbmQodGhpcyk7XG4gICAgICB0aGlzLmVsZW1lbnRVbnN1YnNjcmliZXMucHVzaChcbiAgICAgICAgdGhpcy5ldmVudERpc3BhdGNoZXIub24oJ2VsZW1lbnQ6YWN0aXZhdGUnLCB0aGlzLmJvdW5kRWxlbWVudExpc3RlbmVyKSxcbiAgICAgICAgdGhpcy5ldmVudERpc3BhdGNoZXIub24oJ2VsZW1lbnQ6ZGVhY3RpdmF0ZScsIHRoaXMuYm91bmRFbGVtZW50TGlzdGVuZXIpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGdldFBlcnNvbmFJbmRpY2F0b3IoKTogc3RyaW5nIHtcbiAgICBjb25zdCBwZXJzb25hID0gdGhpcy5wZXJzb25hTWFuYWdlci5nZXRBY3RpdmVQZXJzb25hKCk7XG5cbiAgICBpZiAoIXBlcnNvbmEpIHtcbiAgICAgIHJldHVybiB0aGlzLmZhbGxiYWNrUHJvdmlkZXIgPyB0aGlzLmZhbGxiYWNrUHJvdmlkZXIoKSA6ICcnO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmNhY2hlZEluZGljYXRvciAhPT0gbnVsbCAmJiB0aGlzLmNhY2hlZFBlcnNvbmFJZCA9PT0gcGVyc29uYS5maWxlbmFtZSkge1xuICAgICAgcmV0dXJuIHRoaXMuY2FjaGVkSW5kaWNhdG9yO1xuICAgIH1cblxuICAgIGNvbnN0IGluZGljYXRvciA9IGZvcm1hdEluZGljYXRvcih0aGlzLmluZGljYXRvckNvbmZpZywge1xuICAgICAgbmFtZTogcGVyc29uYS5tZXRhZGF0YS5uYW1lLFxuICAgICAgdmVyc2lvbjogcGVyc29uYS5tZXRhZGF0YS52ZXJzaW9uLFxuICAgICAgYXV0aG9yOiBwZXJzb25hLm1ldGFkYXRhLmF1dGhvcixcbiAgICAgIGNhdGVnb3J5OiBwZXJzb25hLm1ldGFkYXRhLmNhdGVnb3J5LFxuICAgIH0pO1xuXG4gICAgdGhpcy5jYWNoZWRJbmRpY2F0b3IgPSBpbmRpY2F0b3I7XG4gICAgdGhpcy5jYWNoZWRQZXJzb25hSWQgPSBwZXJzb25hLmZpbGVuYW1lO1xuICAgIHJldHVybiBpbmRpY2F0b3I7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjdXJyZW50IGluZGljYXRvciBjb25maWd1cmF0aW9uLlxuICAgKiBVc2VkIGJ5IENvbmZpZ0hhbmRsZXIgdG8gcmVhZCBjdXJyZW50IHNldHRpbmdzIGJlZm9yZSBhcHBseWluZyB1cGRhdGVzLlxuICAgKlxuICAgKiBAcmV0dXJucyBDdXJyZW50IEluZGljYXRvckNvbmZpZ1xuICAgKi9cbiAgZ2V0Q29uZmlnKCk6IEluZGljYXRvckNvbmZpZyB7XG4gICAgcmV0dXJuIHsgLi4udGhpcy5pbmRpY2F0b3JDb25maWcgfTtcbiAgfVxuXG4gIHVwZGF0ZUNvbmZpZyhjb25maWc6IEluZGljYXRvckNvbmZpZyk6IHZvaWQge1xuICAgIC8vIEZJWDogRE1DUC1TRUMtMDA2IC0gQWRkIHNlY3VyaXR5IGF1ZGl0IGxvZ2dpbmcgZm9yIGNvbmZpZ3VyYXRpb24gY2hhbmdlc1xuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdDT05GSUdfVVBEQVRFRCcsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdQZXJzb25hSW5kaWNhdG9yU2VydmljZS51cGRhdGVDb25maWcnLFxuICAgICAgZGV0YWlsczogYEluZGljYXRvciBjb25maWd1cmF0aW9uIHVwZGF0ZWQ6IHN0eWxlPSR7Y29uZmlnLnN0eWxlfSwgZW5hYmxlZD0ke2NvbmZpZy5lbmFibGVkfWAsXG4gICAgICBhZGRpdGlvbmFsRGF0YToge1xuICAgICAgICBzdHlsZTogY29uZmlnLnN0eWxlLFxuICAgICAgICBlbmFibGVkOiBjb25maWcuZW5hYmxlZCxcbiAgICAgICAgc2hvd1ZlcnNpb246IGNvbmZpZy5zaG93VmVyc2lvbixcbiAgICAgICAgc2hvd0F1dGhvcjogY29uZmlnLnNob3dBdXRob3JcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuaW5kaWNhdG9yQ29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMuaW52YWxpZGF0ZUNhY2hlKCk7XG4gIH1cblxuICBzZXRGYWxsYmFja1Byb3ZpZGVyKHByb3ZpZGVyPzogKCkgPT4gc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5mYWxsYmFja1Byb3ZpZGVyID0gcHJvdmlkZXI7XG4gICAgdGhpcy5pbnZhbGlkYXRlQ2FjaGUoKTtcbiAgfVxuXG4gIGludmFsaWRhdGVDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLmNhY2hlZEluZGljYXRvciA9IG51bGw7XG4gICAgdGhpcy5jYWNoZWRQZXJzb25hSWQgPSBudWxsO1xuICB9XG5cbiAgYXN5bmMgZGlzcG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5ib3VuZExpc3RlbmVyICYmIHRoaXMubm90aWZpZXIpIHtcbiAgICAgIHRoaXMubm90aWZpZXIub2ZmKCdzdGF0ZS1jaGFuZ2U6cGVyc29uYS1hY3RpdmF0ZWQnLCB0aGlzLmJvdW5kTGlzdGVuZXIpO1xuICAgICAgdGhpcy5ub3RpZmllci5vZmYoJ3N0YXRlLWNoYW5nZTpwZXJzb25hLWRlYWN0aXZhdGVkJywgdGhpcy5ib3VuZExpc3RlbmVyKTtcbiAgICAgIHRoaXMubm90aWZpZXIub2ZmKCdzdGF0ZS1jaGFuZ2U6dXNlci1jaGFuZ2VkJywgdGhpcy5ib3VuZExpc3RlbmVyKTtcbiAgICB9XG4gICAgd2hpbGUgKHRoaXMuZWxlbWVudFVuc3Vic2NyaWJlcy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCB1bnN1YnNjcmliZSA9IHRoaXMuZWxlbWVudFVuc3Vic2NyaWJlcy5wb3AoKTtcbiAgICAgIGlmICh1bnN1YnNjcmliZSkge1xuICAgICAgICB1bnN1YnNjcmliZSgpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmludmFsaWRhdGVDYWNoZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVQZXJzb25hQ2hhbmdlKF9ldmVudDogUGVyc29uYVN0YXRlQ2hhbmdlRXZlbnQpOiB2b2lkIHtcbiAgICB0aGlzLmludmFsaWRhdGVDYWNoZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVFbGVtZW50RXZlbnQocGF5bG9hZDogRWxlbWVudEV2ZW50UGF5bG9hZCk6IHZvaWQge1xuICAgIGlmIChwYXlsb2FkLmVsZW1lbnRUeXBlICE9PSBFbGVtZW50VHlwZS5QRVJTT05BKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuaW52YWxpZGF0ZUNhY2hlKCk7XG4gIH1cbn1cbiJdfQ==