FileScopeMCP
by admica
Verified
- FileScopeMCP
- src
import * as fs from 'fs/promises';
import * as path from 'path';
import { z } from 'zod';
import { Config, FileWatchingConfig } from './types.js';
// Define the FileWatchingConfig schema
const FileWatchingSchema = z.object({
enabled: z.boolean().default(false),
debounceMs: z.number().int().positive().default(300),
ignoreDotFiles: z.boolean().default(true),
autoRebuildTree: z.boolean().default(true),
maxWatchedDirectories: z.number().int().positive().default(1000),
watchForNewFiles: z.boolean().default(true),
watchForDeleted: z.boolean().default(true),
watchForChanged: z.boolean().default(true)
}).optional();
// Define the config schema
const ConfigSchema = z.object({
baseDirectory: z.string(),
excludePatterns: z.array(z.string()),
fileWatching: FileWatchingSchema,
version: z.string()
});
// Verify the schema matches our Config type
type ValidateConfig = z.infer<typeof ConfigSchema> extends Config ? true : false;
const DEFAULT_CONFIG: Config = {
baseDirectory: "",
excludePatterns: [],
fileWatching: {
enabled: false,
debounceMs: 300,
ignoreDotFiles: true,
autoRebuildTree: true,
maxWatchedDirectories: 1000,
watchForNewFiles: true,
watchForDeleted: true,
watchForChanged: true
},
version: "1.0.0"
};
export async function loadConfig(configPath: string = 'config.json'): Promise<Config> {
console.error(`\n🔧 LOADING CONFIG from ${configPath}`);
console.error(` - Current working directory: ${process.cwd()}`);
try {
const fullPath = path.resolve(configPath);
console.error(` - Resolved full path: ${fullPath}`);
const exists = await fs.access(fullPath).then(() => true).catch(() => false);
console.error(` - Config file exists: ${exists ? '✅ YES' : '❌ NO'}`);
if (!exists) {
console.error(` - ⚠️ Using default config instead`);
console.error(` - Default config:`, JSON.stringify(DEFAULT_CONFIG, null, 2));
return DEFAULT_CONFIG;
}
const configContent = await fs.readFile(configPath, 'utf-8');
console.error(` - Read ${configContent.length} bytes from config file`);
try {
const parsedConfig = JSON.parse(configContent);
console.error(` - Parsed config successfully`);
// Check for exclude patterns
if (parsedConfig.excludePatterns && Array.isArray(parsedConfig.excludePatterns)) {
console.error(` - Found ${parsedConfig.excludePatterns.length} exclude patterns`);
if (parsedConfig.excludePatterns.length > 0) {
console.error(` - First 5 patterns:`, parsedConfig.excludePatterns.slice(0, 5));
}
} else {
console.error(` - ⚠️ No exclude patterns found in config!`);
}
// Validate config
const validatedConfig = ConfigSchema.parse(parsedConfig);
console.error(` - Config validation successful`);
console.error(` - Base directory: ${validatedConfig.baseDirectory}`);
console.error(` - Version: ${validatedConfig.version}`);
console.error(`🔧 CONFIG LOADED SUCCESSFULLY\n`);
return validatedConfig;
} catch (parseError) {
console.error(` - ❌ ERROR parsing config JSON:`, parseError);
console.error(` - Raw config content:`, configContent);
console.error(` - ⚠️ Using default config instead`);
return DEFAULT_CONFIG;
}
} catch (error) {
console.error(` - ❌ ERROR loading config:`, error);
console.error(` - ⚠️ Using default config instead`);
console.error(` - Default config:`, JSON.stringify(DEFAULT_CONFIG, null, 2));
return DEFAULT_CONFIG;
}
}
export async function saveConfig(config: Config, configPath: string = 'config.json'): Promise<void> {
try {
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
} catch (error) {
console.error('Error saving config:', error);
throw error;
}
}