/** * 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; /** * 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; /** * Get the current configuration */ getConfig(): DollhouseConfig; /** * Get a specific setting using dot notation */ getSetting(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; /** * 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; /** * Export configuration to file */ exportConfig(filePath: string): Promise; /** * Import configuration from file */ importConfig(filePath: string): Promise; /** * Get formatted config for display */ getFormattedConfig(section?: string): string; } //# sourceMappingURL=ConfigManager.d.ts.map