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.

363 lines 11.2 kB
/** * ConfigManager - Centralized configuration management for DollhouseMCP * * Features: * - YAML-based configuration file * - Default values with user overrides * - Migration from environment variables * - Validation and type safety * - Atomic updates with backup * - Privacy-first defaults * - OAuth client ID storage for MCP client integration */ import * as os from 'os'; import { IFileOperationsService } from '../services/FileOperationsService.js'; export interface UserConfig { username: string | null; email: string | null; display_name: string | null; } export interface GitHubPortfolioConfig { repository_url: string | null; repository_name: string; default_branch: string; auto_create: boolean; } export interface GitHubAuthConfig { use_oauth: boolean; token_source: 'environment' | 'oauth' | 'config'; client_id?: string; } export interface GitHubConfig { portfolio: GitHubPortfolioConfig; auth: GitHubAuthConfig; } export interface SyncIndividualConfig { require_confirmation: boolean; show_diff_before_sync: boolean; track_versions: boolean; keep_history: number; } export interface SyncBulkConfig { upload_enabled: boolean; download_enabled: boolean; require_preview: boolean; respect_local_only: boolean; } export interface SyncPrivacyConfig { scan_for_secrets: boolean; scan_for_pii: boolean; warn_on_sensitive: boolean; excluded_patterns: string[]; } export interface SyncConfig { enabled: boolean; individual: SyncIndividualConfig; bulk: SyncBulkConfig; privacy: SyncPrivacyConfig; } export interface CollectionConfig { auto_submit: boolean; require_review: boolean; add_attribution: boolean; } export interface AutoLoadConfig { enabled: boolean; maxTokenBudget: number; maxSingleMemoryTokens?: number; suppressLargeMemoryWarnings?: boolean; memories: string[]; } /** * Retention Policy Configuration (Issue #51) * * Controls automatic deletion of expired memory entries. * IMPORTANT: Disabled by default - nothing is auto-deleted without explicit consent. * * Use cases: * - Legal/compliance: Law firms, accountants (7-year retention) * - Privacy-focused: Signal-like auto-expiring messages * - Storage management: Cleanup of old logs * - GDPR: Right-to-be-forgotten implementations */ export interface RetentionPolicyConfig { /** * Master switch for retention enforcement. * If false, no automatic retention enforcement happens anywhere. * Default: false (nothing auto-deleted) */ enabled: boolean; /** * When retention enforcement happens: * - 'disabled': Never enforce automatically (only via explicit command) * - 'manual': Only when user explicitly requests enforcement * - 'on_load': Enforce when memory is loaded (CURRENT BEHAVIOR - not recommended) * - 'scheduled': Run on a schedule (future implementation) */ enforcement_mode: 'disabled' | 'manual' | 'on_load' | 'scheduled'; /** * Safety controls to prevent accidental data loss */ safety: { /** Require explicit confirmation before any deletion */ require_confirmation: boolean; /** Always preview what would be deleted before doing it */ dry_run_first: boolean; /** Show warning when entries are approaching expiration */ warn_on_expiring: boolean; /** Days before expiration to start warning */ warning_threshold_days: number; }; /** * Audit and logging */ audit: { /** Log all retention deletions for audit trail */ log_deletions: boolean; /** Keep deleted entries in a backup before permanent removal */ backup_before_delete: boolean; /** Days to keep backups of deleted entries */ backup_retention_days: number; }; /** * Default TTL settings when creating new memories * Note: These are defaults only - individual memories can override */ defaults: { /** Default TTL in days for new memory entries */ ttl_days: number; /** Maximum entries before capacity enforcement */ max_entries: number; }; } export interface CapabilityIndexResourcesConfig { advertise_resources: boolean; variants: { summary: boolean; full: boolean; stats: boolean; }; } export interface EnhancedIndexConfig { enabled: boolean; limits: { maxTriggersPerElement: number; maxTriggerLength: number; maxKeywordsToCheck: number; }; telemetry: { enabled: boolean; sampleRate: number; metricsInterval: number; }; verbPatterns?: { customPrefixes?: string[]; customSuffixes?: string[]; excludedNouns?: string[]; }; backgroundAnalysis?: { enabled: boolean; scanInterval: number; maxConcurrentScans: number; }; resources?: CapabilityIndexResourcesConfig; } export interface ElementsConfig { auto_activate: { personas?: string[]; skills?: string[]; templates?: string[]; agents?: string[]; memories?: string[]; ensembles?: string[]; }; default_element_dir: string; enhanced_index?: EnhancedIndexConfig; } export interface DisplayConfig { persona_indicators: { enabled: boolean; style: 'full' | 'minimal' | 'compact' | 'custom'; include_emoji: boolean; }; verbose_logging: boolean; show_progress: boolean; } export interface WizardConfig { completed: boolean; dismissed: boolean; completedAt?: string; version?: string; lastSeenVersion?: string; skippedSections?: string[]; } export type LicenseTier = 'agpl' | 'free-commercial' | 'paid-commercial'; export interface LicenseConfig { tier: LicenseTier; email?: string; attestedAt?: string; telemetryRequired?: boolean; revenueScale?: string; companyName?: string; useCase?: string; } /** Branded type for validated port numbers (1024–65535). */ export type PortNumber = number & { readonly __brand: 'PortNumber'; }; /** Validate and brand a port number. Returns undefined if invalid. */ export declare function validatePort(value: unknown): PortNumber | undefined; export interface ConsoleConfig { /** * Web console port (1024–65535). Resolution hierarchy: * 1. --port CLI flag (standalone --web mode only) * 2. This config value (~/.dollhouse/config.yml → console.port) * 3. DOLLHOUSE_WEB_CONSOLE_PORT env var * 4. Default: 41715 */ port: number; } export interface SourcePriorityConfigData { order: string[]; stop_on_first: boolean; check_all_for_updates: boolean; fallback_on_error: boolean; } export interface DollhouseConfig { version: string; user: UserConfig; github: GitHubConfig; sync: SyncConfig; collection: CollectionConfig; elements: ElementsConfig; display: DisplayConfig; wizard: WizardConfig; autoLoad: AutoLoadConfig; retentionPolicy: RetentionPolicyConfig; license: LicenseConfig; console: ConsoleConfig; source_priority?: SourcePriorityConfigData; } export interface ConfigUpdateResult { success: boolean; message: string; previousValue?: any; newValue?: any; } export interface ConfigActionResult { success: boolean; message: string; data?: any; } export declare class ConfigManager { private configDir; private configPath; private backupPath; private config; private readonly fileOperations; private os; /** * Extract console.port from raw YAML config content without full * ConfigManager initialization. Uses FAILSAFE_SCHEMA for security * (no code execution). Returns undefined if not found or invalid. */ static readPortFromYaml(yamlContent: string): number | undefined; constructor(fileOperations: IFileOperationsService, osModule: typeof os); /** * Get default configuration */ private getDefaultConfig; /** * Initialize configuration */ initialize(): Promise<void>; /** * Load configuration from file */ private loadConfig; /** * Check if config file exists */ private configExists; /** * Get GitHub OAuth client ID * Environment variable takes precedence over config file */ getGitHubClientId(): string | null; /** * Set GitHub OAuth client ID in config file */ setGitHubClientId(clientId: string): Promise<void>; /** * Get the current configuration */ getConfig(): DollhouseConfig; /** * Get a specific setting using dot notation */ getSetting<T>(path: string, defaultValue?: T): T | undefined; /** * Update a specific setting using dot notation * SECURITY FIX (PR #895): Added prototype pollution protection * Previously: Direct property assignment allowed __proto__ injection * Now: Validates keys against forbidden properties before assignment */ updateSetting(path: string, value: any): Promise<ConfigUpdateResult>; /** * Validate GitHub OAuth client ID format * Client IDs start with "Ov23li" followed by at least 14 alphanumeric characters * * @param clientId - The client ID to validate * @returns true if valid, false otherwise * * @example * ConfigManager.validateClientId("Ov23liABCDEFGHIJKLMN123456") // true * ConfigManager.validateClientId("invalid") // false * ConfigManager.validateClientId("Ov23li") // false (too short) * ConfigManager.validateClientId("Xv23liABCDEFGHIJKLMN") // false (wrong prefix) */ static validateClientId(clientId: any): boolean; /** * Save configuration to file */ private saveConfig; /** * Check if backup exists */ private backupExists; /** * Fix incorrect types in config (e.g., string booleans, string "null") */ private fixConfigTypes; /** * Merge partial config with defaults * * IMPORTANT: This function preserves unknown fields for forward compatibility. * If a future version adds new config fields, older versions won't lose them. */ private mergeWithDefaults; /** * Migrate settings from environment variables */ private migrateFromEnvironment; /** * Reset configuration to defaults * SECURITY FIX (PR #895): Added prototype pollution protection * Previously: Direct property assignment allowed __proto__ injection * Now: Validates keys against forbidden properties before assignment */ resetConfig(section?: string): Promise<ConfigActionResult>; /** * Export configuration to file */ exportConfig(filePath: string): Promise<ConfigActionResult>; /** * Import configuration from file */ importConfig(filePath: string): Promise<ConfigActionResult>; /** * Get formatted config for display */ getFormattedConfig(section?: string): string; } //# sourceMappingURL=ConfigManager.d.ts.map