UNPKG

@wonderwhy-er/desktop-commander

Version:

MCP server for terminal operations and file editing

145 lines (144 loc) • 5.64 kB
export interface ServerConfig { blockedCommands?: string[]; defaultShell?: string; allowedDirectories?: string[]; telemetryEnabled?: boolean; fileWriteLineLimit?: number; fileReadLineLimit?: number; clientId?: string; currentClient?: ClientInfo; [key: string]: any; } export interface ClientInfo { name: string; version: string; } export declare function normalizeTelemetryEnabledValue(value: unknown): unknown; export declare function isTelemetryDisabledValue(value: unknown): boolean; /** * Parses config.json's text. Editors saving "UTF-8 with BOM" (Notepad, * PowerShell 5's Set-Content -Encoding UTF8) put U+FEFF first, which * JSON.parse rejects although the config is complete. */ export declare function parseConfig(text: string): ServerConfig; /** * Singleton config manager for the server */ declare class ConfigManager { private configPath; private config; private initialized; private _isFirstRun; private writeChain; private saveScheduled; private pendingMutations; private watcher; private reloadTimer; private failedSaves; private saveRetry; private heldRecoveryEvents; constructor(); /** * Initialize configuration - load from disk or create default. * Creation and legacy migration use the same cross-process mutation path as * normal writes so two processes starting together cannot clobber each other. */ init(): Promise<void>; /** * Reads config.json at start. A missing one is created (a first run), a corrupt * one is recovered, and one written before the welcome page existed is marked * as an existing install. If it can't be read, recovered or saved, the session * starts without saving it. */ private loadStartupConfig; /** * Starts the session on `config` and leaves config.json as it is. `warning` * tells the user why; saves are tried again every HELD_SAVE_RETRY_MS. */ private startWithoutSaving; /** * Alias for init() to maintain backward compatibility */ loadConfig(): Promise<void>; /** * Create default configuration */ private getDefaultConfig; private readConfigFromDisk; /** * Recovers a corrupt config.json; the caller holds the config lock. It is backed * up once, then rewritten as buildRecoveredConfig(). Returns the config now on disk. */ private recoverCorruptConfig; /** Sends a recovery event. Telemetry reads the config, so events from before init() is done wait for it. */ private reportRecovery; private emitCorruptConfigTelemetry; private writeConfigAtomically; /** config.json's text, or null when there is none */ private readConfigText; private acquireConfigLock; /** Runs `fn` holding the config lock; `lockLost()` tells whether the lock was lost meanwhile. */ private withConfigLock; /** * Read config.json, apply `mutate`, write it back, all under the cross-process * lock. If the lock was lost, or config.json changed, before the write * committed, nothing was written: it runs again under a new lock, so the * change lands on what the other process saved. */ private performConfigMutation; private mutateLockedConfig; private queueMutation; /** Non-blocking, coalesced persistence for high-frequency state updates. */ scheduleSave(): void; /** Saves the queued changes in `ms`; until then scheduleSave() waits for it */ private retrySaves; private startConfigWatcher; private reloadConfigFromDisk; /** * Get the entire config */ getConfig(): Promise<ServerConfig>; /** * Get a specific configuration value */ getValue(key: string): Promise<any>; /** * Set a specific configuration value and wait until it is saved: the data is * flushed to disk before the rename; the folder flush after it is best effort. * With holdIfNotSaved, a value whose save fails is still in effect, and is * queued to be saved with later writes (the call still rejects). */ setValue(key: string, value: any, options?: { holdIfNotSaved?: boolean; }): Promise<void>; /** * Update one value under the cross-process lock and return it once saved: the * data is flushed to disk before the rename; the folder flush after it is best effort. */ updateValue(key: string, updater: (current: any) => any): Promise<any>; /** * Set a value without waiting on disk. The queued operation is applied to the * latest on-disk config while holding the cross-process lock. */ setValueNonBlocking(key: string, value: any): Promise<void>; /** * Atomically update one value without blocking the caller on persistence. * The updater is replayed against the latest disk value under the lock, which * makes counter-style updates safe across multiple Desktop Commander processes. */ updateValueNonBlocking(key: string, updater: (current: any) => any): Promise<any>; /** Update multiple configuration values at once. */ updateConfig(updates: Partial<ServerConfig>): Promise<ServerConfig>; /** Reset configuration to defaults. This intentionally replaces all keys. */ resetConfig(): Promise<ServerConfig>; /** * Check if this is the first run (config file was just created) */ isFirstRun(): boolean; /** * Get or create a persistent client ID for analytics and A/B tests */ getOrCreateClientId(): Promise<string>; } export declare const configManager: ConfigManager; export {};