{"version":3,"sources":["../../../src/utils/config-validator.ts","../../../src/utils/config.ts"],"names":["path","load","dump"],"mappings":"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","file":"config.cjs","sourcesContent":["import { ValidationResult } from '../types.js';\nimport { LlmailConfig, ResolvedConfig } from './config.js';\n\n/**\n * Validates llmail configuration.\n * This is a focused utility that only handles config validation.\n * It ensures the config has the required structure and valid values.\n */\nexport class ConfigValidator {\n  /**\n   * Validate raw llmail configuration\n   */\n  validateConfig(config: LlmailConfig): ValidationResult {\n    const errors: string[] = [];\n\n    // Validate required arrays\n    if (!Array.isArray(config.types_list)) {\n      errors.push('types_list must be an array');\n    }\n\n    // Validate array contents if present\n    if (config.types_list?.some(type => typeof type !== 'string' || !type.match(/^[a-z0-9]+$/))) {\n      errors.push('types_list must contain only lowercase alphanumeric strings without hyphens');\n    }\n    if (config.active_states?.some(state => typeof state !== 'string' || !state.match(/^[a-z0-9]+$/))) {\n      errors.push('active_states must contain only lowercase alphanumeric strings without hyphens');\n    }\n    if (config.inactive_reasons?.some(reason => typeof reason !== 'string' || !reason.match(/^[a-z0-9]+$/))) {\n      errors.push('inactive_reasons must contain only lowercase alphanumeric strings without hyphens');\n    }\n\n    // Check for overlapping states if both arrays are present\n    if (config.active_states?.length > 0 && config.inactive_reasons?.length > 0) {\n      const activeStates = new Set(config.active_states);\n      for (const reason of config.inactive_reasons) {\n        if (activeStates.has(reason)) {\n          errors.push('States cannot be both active and inactive');\n          break;\n        }\n      }\n    }\n\n    // Validate required paths\n    if (!config.issues_dir) {\n      errors.push('issues_dir is required');\n    }\n    if (!config.inbox_dir) {\n      errors.push('inbox_dir is required');\n    }\n\n    // Validate plugins if present\n    if (config.plugins !== undefined) {\n      if (typeof config.plugins === 'string') {\n        // Single plugin string format\n        if (!config.plugins.match(/^[a-z0-9-]+$/)) {\n          errors.push('Plugin name must be lowercase alphanumeric with hyphens');\n        }\n      } else if (Array.isArray(config.plugins)) {\n        // Array format\n        for (const plugin of config.plugins) {\n          if (typeof plugin === 'string') {\n            // String array format\n            if (!plugin.match(/^[a-z0-9-]+$/)) {\n              errors.push('Plugin names must be lowercase alphanumeric with hyphens');\n            }\n          } else if (typeof plugin === 'object' && plugin !== null) {\n            // Object format with config\n            if (!plugin.name?.match(/^[a-z0-9-]+$/)) {\n              errors.push('Plugin names must be lowercase alphanumeric with hyphens');\n            }\n            if (plugin.config !== undefined && (typeof plugin.config !== 'object' || plugin.config === null)) {\n              errors.push('Plugin config must be an object');\n            }\n          } else {\n            errors.push('Invalid plugin configuration format');\n          }\n        }\n      } else {\n        errors.push('Invalid plugins configuration format');\n      }\n    }\n\n    return {\n      valid: errors.length === 0,\n      errors,\n      warnings: []\n    };\n  }\n\n  /**\n   * Validate resolved configuration\n   * This is used after the config has been normalized and paths resolved\n   */\n  validateResolvedConfig(config: ResolvedConfig): ValidationResult {\n    const errors: string[] = [];\n\n    // Validate required arrays are present\n    if (!Array.isArray(config.types_list)) {\n      errors.push('Resolved config must have types_list array');\n    }\n    if (!Array.isArray(config.active_states)) {\n      errors.push('Resolved config must have active_states array');\n    }\n    if (!Array.isArray(config.inactive_reasons)) {\n      errors.push('Resolved config must have inactive_reasons array');\n    }\n\n    // Validate required paths are absolute\n    if (!config.issues_dir?.startsWith('/')) {\n      errors.push('Resolved issues_dir must be absolute path');\n    }\n    if (!config.inbox_dir?.startsWith('/')) {\n      errors.push('Resolved inbox_dir must be absolute path');\n    }\n\n    return {\n      valid: errors.length === 0,\n      errors,\n      warnings: []\n    };\n  }\n} ","import fs from 'fs-extra';\nimport path from 'path';\nimport { dump, load } from 'js-yaml';\nimport { FileSystemAdapter } from './file-system-adapter.js';\nimport { ConfigValidator } from './config-validator.js';\n\n/**\n * Core LLMail configuration interface.\n * All paths are relative to the config file location.\n */\nexport interface LlmailConfig {\n  types_list: string[];\n  active_states: string[];\n  inactive_reasons: string[];\n  issues_dir: string;\n  inbox_dir: string;\n  type_dirs?: string[];\n  plugins?: string | string[] | Array<{\n    name: string;\n    config?: Record<string, any>;\n  }>;\n}\n\nexport type ResolvedConfig = LlmailConfig;\n\nconst defaultConfig: LlmailConfig = {\n  types_list: [],\n  active_states: [],\n  inactive_reasons: [],\n  issues_dir: 'issues',\n  inbox_dir: 'inbox'  // Changed to be relative to root\n};\n\n/**\n * Normalize paths in config.\n * All paths in the config should remain relative to the config file location.\n */\nfunction normalizeConfigPaths(config: LlmailConfig): LlmailConfig {\n  // Normalize paths but keep them relative\n  return {\n    ...config,\n    issues_dir: path.normalize(config.issues_dir),\n    inbox_dir: path.normalize(config.inbox_dir)\n  };\n}\n\n/**\n * Load and validate config from a file\n */\nexport async function loadConfigFromFile(fs: FileSystemAdapter, configPath: string, rootDir: string): Promise<LlmailConfig> {\n  const exists = await fs.exists(configPath);\n  \n  if (!exists) {\n    // Return default config with normalized paths\n    return normalizeConfigPaths(defaultConfig);\n  }\n\n  try {\n    const content = await fs.readFile(configPath);\n    let config: any;\n    \n    try {\n      config = load(content) as LlmailConfig;\n    } catch (err) {\n      throw new Error('Failed to load config');\n    }\n\n    // Merge with defaults, ensuring default types are preserved\n    const mergedConfig = {\n      ...defaultConfig,\n      ...config,\n      // Don't merge arrays - use config values if present, otherwise use defaults\n      types_list: config.types_list || defaultConfig.types_list,\n      active_states: config.active_states || defaultConfig.active_states,\n      inactive_reasons: config.inactive_reasons || defaultConfig.inactive_reasons\n    };\n\n    // Validate config\n    const validator = new ConfigValidator();\n    const result = validator.validateConfig(mergedConfig);\n    if (!result.valid) {\n      throw new Error(`Invalid config: ${result.errors[0]}`);\n    }\n\n    // Normalize paths but keep them relative\n    return normalizeConfigPaths(mergedConfig);\n  } catch (err) {\n    if (err instanceof Error) {\n      throw err;\n    }\n    throw new Error('Failed to load config');\n  }\n}\n\n/**\n * Load llmail config from the default location or specified path\n */\nexport async function loadLlmailConfig(fs: FileSystemAdapter, rootDir: string = process.cwd(), configPath?: string): Promise<LlmailConfig> {\n  const resolvedConfigPath = configPath || path.join(rootDir, 'llmail.yaml');\n  try {\n    return await loadConfigFromFile(fs, resolvedConfigPath, rootDir);\n  } catch (err) {\n    // If config file doesn't exist or can't be loaded, return defaults with normalized paths\n    return normalizeConfigPaths(defaultConfig);\n  }\n}\n\n/**\n * Save config to the default location\n */\nexport async function saveLlmailConfig(fs: FileSystemAdapter, config: LlmailConfig, configPath: string): Promise<void> {\n  const yamlContent = dump(normalizeConfigPaths(config));\n  \n  // Ensure the directory exists\n  const configDir = path.dirname(configPath);\n  await fs.ensureDir(configDir);\n  \n  await fs.writeFile(configPath, yamlContent);\n} "]}