Skip to main content
Glama
portel-dev

NCP - Natural Context Provider

by portel-dev
settings-manager.ts4.92 kB
/** * Settings Manager - Persist and load scheduler configuration * Supports JSON config files and DXT extension configs */ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; import { join } from 'path'; import { getSchedulerDirectory } from '../../utils/ncp-paths.js'; import { SchedulerConfig } from '../../types/scheduler.js'; import { logger } from '../../utils/logger.js'; export class SettingsManager { private configFile: string | null = null; private config: SchedulerConfig | null = null; private initialized: boolean = false; // Default configuration private static readonly DEFAULTS: SchedulerConfig = { maxExecutionsPerJob: 100, maxExecutionAgeDays: 14, cleanupSchedule: '0 0 * * *', // Daily at midnight enableAutoCleanup: true, defaultTimeout: 5 * 60 * 1000 // 5 minutes }; constructor() { // Lazy initialization - don't traverse directories during construction } /** * Initialize paths and configuration on first use */ private ensureInitialized(): void { if (this.initialized) { return; } const schedulerDir = getSchedulerDirectory(); this.configFile = join(schedulerDir, 'config.json'); // Ensure scheduler directory exists if (!existsSync(schedulerDir)) { mkdirSync(schedulerDir, { recursive: true }); logger.info(`[SettingsManager] Created scheduler directory: ${schedulerDir}`); } // Load or create config this.config = this.loadConfig(); this.initialized = true; } /** * Load configuration from file, or create default if missing */ private loadConfig(): SchedulerConfig { try { if (existsSync(this.configFile!)) { const content = readFileSync(this.configFile!, 'utf-8'); const loaded = JSON.parse(content) as Partial<SchedulerConfig>; // Merge with defaults (for new fields added in updates) const merged = { ...SettingsManager.DEFAULTS, ...loaded }; logger.info('[SettingsManager] Loaded configuration from file'); return merged; } else { // Create default config file this.saveConfig(SettingsManager.DEFAULTS); logger.info('[SettingsManager] Created default configuration file'); return { ...SettingsManager.DEFAULTS }; } } catch (error) { logger.error(`[SettingsManager] Failed to load config: ${error instanceof Error ? error.message : String(error)}`); logger.warn('[SettingsManager] Using default configuration'); return { ...SettingsManager.DEFAULTS }; } } /** * Save configuration to file */ private saveConfig(config: SchedulerConfig): void { this.ensureInitialized(); try { writeFileSync(this.configFile!, JSON.stringify(config, null, 2), 'utf-8'); logger.info('[SettingsManager] Saved configuration to file'); } catch (error) { logger.error(`[SettingsManager] Failed to save config: ${error instanceof Error ? error.message : String(error)}`); } } /** * Get current configuration */ getConfig(): SchedulerConfig { this.ensureInitialized(); return { ...this.config! }; } /** * Update configuration (partial update) */ updateConfig(updates: Partial<SchedulerConfig>): void { this.ensureInitialized(); this.config = { ...this.config!, ...updates }; this.saveConfig(this.config); logger.info('[SettingsManager] Updated configuration'); } /** * Reset to default configuration */ resetToDefaults(): void { this.ensureInitialized(); this.config = { ...SettingsManager.DEFAULTS }; this.saveConfig(this.config); logger.info('[SettingsManager] Reset configuration to defaults'); } /** * Load configuration from DXT extension config (for Claude Desktop) * This allows .dxt extensions to specify scheduler retention policies */ static loadFromDXTConfig(dxtConfig: any): Partial<SchedulerConfig> { const schedulerConfig: Partial<SchedulerConfig> = {}; // Check for scheduler settings in DXT config if (dxtConfig?.scheduler) { const dxtScheduler = dxtConfig.scheduler; if (typeof dxtScheduler.maxExecutionsPerJob === 'number') { schedulerConfig.maxExecutionsPerJob = dxtScheduler.maxExecutionsPerJob; } if (typeof dxtScheduler.maxExecutionAgeDays === 'number') { schedulerConfig.maxExecutionAgeDays = dxtScheduler.maxExecutionAgeDays; } if (typeof dxtScheduler.cleanupSchedule === 'string') { schedulerConfig.cleanupSchedule = dxtScheduler.cleanupSchedule; } if (typeof dxtScheduler.enableAutoCleanup === 'boolean') { schedulerConfig.enableAutoCleanup = dxtScheduler.enableAutoCleanup; } if (typeof dxtScheduler.defaultTimeout === 'number') { schedulerConfig.defaultTimeout = dxtScheduler.defaultTimeout; } } return schedulerConfig; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/portel-dev/ncp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server