{"version":3,"sources":["../../src/logger.ts","../../src/liquid-extensions.ts","../../src/utils/author-permissions.ts","../../src/memory-store.ts"],"sourcesContent":["/*\n * Centralized logger for Visor CLI and Action modes.\n * - Respects output format (suppresses info in JSON/SARIF unless debug)\n * - Supports levels: silent < error < warn < info < verbose < debug\n * - Routes logs to stderr to keep stdout clean for machine-readable output\n */\n\nexport type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'verbose' | 'debug';\n\nfunction levelToNumber(level: LogLevel): number {\n  switch (level) {\n    case 'silent':\n      return 0;\n    case 'error':\n      return 10;\n    case 'warn':\n      return 20;\n    case 'info':\n      return 30;\n    case 'verbose':\n      return 40;\n    case 'debug':\n      return 50;\n  }\n}\n\nclass Logger {\n  private level: LogLevel = 'info';\n  private isJsonLike: boolean = false;\n  private isTTY: boolean = typeof process !== 'undefined' ? !!process.stderr.isTTY : false;\n\n  configure(\n    opts: {\n      outputFormat?: string;\n      level?: LogLevel;\n      debug?: boolean;\n      verbose?: boolean;\n      quiet?: boolean;\n    } = {}\n  ): void {\n    // Determine base level\n    let lvl: LogLevel = 'info';\n\n    if (opts.debug || process.env.VISOR_DEBUG === 'true') {\n      lvl = 'debug';\n    } else if (opts.verbose || process.env.VISOR_LOG_LEVEL === 'verbose') {\n      lvl = 'verbose';\n    } else if (opts.quiet || process.env.VISOR_LOG_LEVEL === 'quiet') {\n      lvl = 'warn';\n    } else if (opts.level) {\n      lvl = opts.level;\n    } else if (process.env.VISOR_LOG_LEVEL) {\n      const envLvl = process.env.VISOR_LOG_LEVEL as LogLevel;\n      if (['silent', 'error', 'warn', 'info', 'verbose', 'debug'].includes(envLvl)) {\n        lvl = envLvl as LogLevel;\n      }\n    }\n\n    this.level = lvl;\n    const output = opts.outputFormat || process.env.VISOR_OUTPUT_FORMAT || 'table';\n    // In JSON/SARIF we suppress non-error logs unless explicitly verbose/debug\n    this.isJsonLike = output === 'json' || output === 'sarif';\n  }\n\n  private shouldLog(level: LogLevel): boolean {\n    const desired = levelToNumber(level);\n    const current = levelToNumber(this.level);\n    if (desired > current) return false;\n    if (\n      this.isJsonLike &&\n      desired < levelToNumber('error') &&\n      this.level !== 'debug' &&\n      this.level !== 'verbose'\n    ) {\n      // In JSON/SARIF, hide info/warn unless explicitly verbose/debug\n      return false;\n    }\n    return true;\n  }\n\n  private write(msg: string): void {\n    // Always route to stderr to keep stdout clean for results\n    try {\n      process.stderr.write(msg + '\\n');\n    } catch {\n      // Ignore write errors\n    }\n  }\n\n  info(msg: string): void {\n    if (this.shouldLog('info')) this.write(msg);\n  }\n\n  warn(msg: string): void {\n    if (this.shouldLog('warn')) this.write(msg);\n  }\n\n  error(msg: string): void {\n    if (this.shouldLog('error')) this.write(msg);\n  }\n\n  verbose(msg: string): void {\n    if (this.shouldLog('verbose')) this.write(msg);\n  }\n\n  debug(msg: string): void {\n    if (this.shouldLog('debug')) this.write(msg);\n  }\n\n  step(msg: string): void {\n    // High-level phase indicator\n    if (this.shouldLog('info')) this.write(`▶ ${msg}`);\n  }\n\n  success(msg: string): void {\n    if (this.shouldLog('info')) this.write(`✔ ${msg}`);\n  }\n}\n\n// Singleton instance\nexport const logger = new Logger();\n\n// Helper to configure from CLI options in a single place\nexport function configureLoggerFromCli(options: {\n  output?: string;\n  debug?: boolean;\n  verbose?: boolean;\n  quiet?: boolean;\n}): void {\n  logger.configure({\n    outputFormat: options.output,\n    debug: options.debug,\n    verbose: options.verbose,\n    quiet: options.quiet,\n  });\n\n  // Expose output format and debug to process env for modules that need to gate\n  // stdout emissions without plumbing the value through every call site.\n  try {\n    if (options.output) process.env.VISOR_OUTPUT_FORMAT = String(options.output);\n    if (typeof options.debug === 'boolean') {\n      process.env.VISOR_DEBUG = options.debug ? 'true' : 'false';\n    }\n  } catch {\n    // ignore\n  }\n}\n","import { Liquid, TagToken, Context, TopLevelToken, Tag, Value, Emitter } from 'liquidjs';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport {\n  hasMinPermission,\n  isOwner,\n  isMember,\n  isCollaborator,\n  isContributor,\n  isFirstTimer,\n  detectLocalMode,\n} from './utils/author-permissions';\nimport { MemoryStore } from './memory-store';\n\n/**\n * Sanitize label strings to only allow [A-Za-z0-9:/\\- ] characters (including spaces and hyphens)\n * @param value - Label value to sanitize\n * @returns Sanitized label string\n */\nexport function sanitizeLabel(value: unknown): string {\n  if (value == null) return '';\n  const s = String(value);\n  // Keep only alphanumerics, colon, slash, hyphen, and space; collapse repeated slashes and trim\n  return s\n    .replace(/[^A-Za-z0-9:\\/\\- ]/g, '')\n    .replace(/\\/{2,}/g, '/')\n    .trim();\n}\n\n/**\n * Sanitize an array of labels\n * @param labels - Array of label values\n * @returns Array of sanitized, non-empty label strings\n */\nexport function sanitizeLabelList(labels: unknown): string[] {\n  if (!Array.isArray(labels)) return [];\n  return (labels as unknown[]).map(v => sanitizeLabel(v)).filter(s => s.length > 0);\n}\n\n/**\n * Custom ReadFile tag for Liquid templates\n * Usage: {% readfile \"path/to/file.txt\" %}\n * or with variable: {% readfile filename %}\n */\nexport class ReadFileTag extends Tag {\n  private filepath: Value;\n\n  constructor(token: TagToken, remainTokens: TopLevelToken[], liquid: Liquid) {\n    super(token, remainTokens, liquid);\n    this.filepath = new Value(token.args, liquid);\n  }\n\n  *render(ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {\n    const filePath = yield this.filepath.value(ctx, false);\n\n    // Validate the path\n    if (!filePath || typeof filePath !== 'string') {\n      emitter.write('[Error: Invalid file path]');\n      return;\n    }\n\n    // Security: Resolve path relative to project root to prevent directory traversal\n    const projectRoot = process.cwd();\n    const resolvedPath = path.resolve(projectRoot, filePath.toString());\n\n    // Ensure the resolved path is within the project directory\n    if (!resolvedPath.startsWith(projectRoot)) {\n      emitter.write('[Error: File path escapes project directory]');\n      return;\n    }\n\n    // Read the file content\n    try {\n      const content = yield fs.readFile(resolvedPath, 'utf-8');\n      emitter.write(content);\n    } catch (error) {\n      // Handle file read errors gracefully\n      const errorMessage =\n        error instanceof Error\n          ? error.message\n          : (error as NodeJS.ErrnoException)?.code || 'Unknown error';\n      emitter.write(`[Error reading file: ${errorMessage}]`);\n    }\n  }\n}\n\n// Async-local permissions context for filters (per-render)\nconst permissionsALS = new AsyncLocalStorage<{ authorAssociation?: string }>();\n\nexport async function withPermissionsContext<T>(\n  ctx: { authorAssociation?: string },\n  fn: () => Promise<T>\n): Promise<T> {\n  return await permissionsALS.run(ctx, fn as any);\n}\n\n/**\n * Configure a Liquid instance with custom extensions\n */\nexport function configureLiquidWithExtensions(liquid: Liquid): void {\n  // Register the readfile tag\n  liquid.registerTag('readfile', ReadFileTag);\n\n  // Register parse_json filter to parse JSON strings into objects\n  liquid.registerFilter('parse_json', (value: string) => {\n    if (typeof value !== 'string') {\n      return value;\n    }\n    try {\n      return JSON.parse(value);\n    } catch {\n      // Return original value if parsing fails\n      return value;\n    }\n  });\n\n  // Register to_json filter as alias for json (for consistency)\n  liquid.registerFilter('to_json', (value: unknown) => {\n    try {\n      return JSON.stringify(value);\n    } catch {\n      return '[Error: Unable to serialize to JSON]';\n    }\n  });\n\n  // Sanitize a label to allowed characters only: [A-Za-z0-9:/]\n  liquid.registerFilter('safe_label', (value: unknown) => sanitizeLabel(value));\n\n  // Sanitize an array of labels\n  liquid.registerFilter('safe_label_list', (value: unknown) => sanitizeLabelList(value));\n\n  // Convert literal escape sequences (e.g., \"\\n\") into actual newlines\n  liquid.registerFilter('unescape_newlines', (value: unknown) => {\n    if (value == null) return '';\n    const s = String(value);\n    return s.replace(/\\\\n/g, '\\n').replace(/\\\\r/g, '\\r').replace(/\\\\t/g, '\\t');\n  });\n\n  // Register author permission filters (from main)\n  // These filters check the author's permission level; detect local mode for tests\n  const isLocal = detectLocalMode();\n\n  const resolveAssoc = (val: unknown): string | undefined => {\n    if (typeof val === 'string' && val.length > 0) return val;\n    const store = permissionsALS.getStore();\n    return store?.authorAssociation;\n  };\n\n  liquid.registerFilter('has_min_permission', (authorAssociation: unknown, level: string) => {\n    return hasMinPermission(resolveAssoc(authorAssociation), level as any, isLocal);\n  });\n\n  liquid.registerFilter('is_owner', (authorAssociation: unknown) => {\n    return isOwner(resolveAssoc(authorAssociation), isLocal);\n  });\n\n  liquid.registerFilter('is_member', (authorAssociation: unknown) => {\n    return isMember(resolveAssoc(authorAssociation), isLocal);\n  });\n\n  liquid.registerFilter('is_collaborator', (authorAssociation: unknown) => {\n    return isCollaborator(resolveAssoc(authorAssociation), isLocal);\n  });\n\n  liquid.registerFilter('is_contributor', (authorAssociation: unknown) => {\n    return isContributor(resolveAssoc(authorAssociation), isLocal);\n  });\n\n  liquid.registerFilter('is_first_timer', (authorAssociation: unknown) => {\n    return isFirstTimer(resolveAssoc(authorAssociation), isLocal);\n  });\n\n  // Register memory filters for accessing memory store\n  const memoryStore = MemoryStore.getInstance();\n\n  liquid.registerFilter('memory_get', (key: string, namespace?: string) => {\n    if (typeof key !== 'string') {\n      return undefined;\n    }\n    return memoryStore.get(key, namespace);\n  });\n\n  liquid.registerFilter('memory_has', (key: string, namespace?: string) => {\n    if (typeof key !== 'string') {\n      return false;\n    }\n    return memoryStore.has(key, namespace);\n  });\n\n  liquid.registerFilter('memory_list', (namespace?: string) => {\n    return memoryStore.list(namespace);\n  });\n}\n\n/**\n * Create a new Liquid instance with custom extensions\n */\nexport function createExtendedLiquid(options: Record<string, unknown> = {}): Liquid {\n  const liquid = new Liquid({\n    cache: false,\n    strictFilters: false,\n    strictVariables: false,\n    ...options,\n  });\n\n  configureLiquidWithExtensions(liquid);\n  return liquid;\n}\n","/**\n * Author permission utilities for checking GitHub author associations\n *\n * GitHub provides author_association field with these values (in order of privilege):\n * - OWNER: Repository owner\n * - MEMBER: Organization member\n * - COLLABORATOR: Invited collaborator\n * - CONTRIBUTOR: Has contributed before\n * - FIRST_TIME_CONTRIBUTOR: First PR to this repo\n * - FIRST_TIMER: First GitHub contribution ever\n * - NONE: No association\n */\n\nexport type AuthorAssociation =\n  | 'OWNER'\n  | 'MEMBER'\n  | 'COLLABORATOR'\n  | 'CONTRIBUTOR'\n  | 'FIRST_TIME_CONTRIBUTOR'\n  | 'FIRST_TIMER'\n  | 'NONE';\n\n/**\n * Permission hierarchy (from highest to lowest privilege)\n */\nconst PERMISSION_HIERARCHY: AuthorAssociation[] = [\n  'OWNER',\n  'MEMBER',\n  'COLLABORATOR',\n  'CONTRIBUTOR',\n  'FIRST_TIME_CONTRIBUTOR',\n  'FIRST_TIMER',\n  'NONE',\n];\n\n/**\n * Get permission level (0 = highest, higher number = lower privilege)\n */\nfunction getPermissionLevel(association: string | undefined): number {\n  if (!association) return PERMISSION_HIERARCHY.length; // Treat unknown as lowest\n  const index = PERMISSION_HIERARCHY.indexOf(association.toUpperCase() as AuthorAssociation);\n  return index === -1 ? PERMISSION_HIERARCHY.length : index;\n}\n\n/**\n * Check if author has at least the specified permission level (>= logic)\n *\n * @param authorAssociation - The author's association from GitHub API\n * @param minPermission - Minimum required permission level\n * @param isLocalMode - Whether running in local/CLI mode (defaults to true for local runs)\n * @returns true if author has at least the specified permission level\n *\n * @example\n * hasMinPermission('MEMBER', 'MEMBER') // true (exact match)\n * hasMinPermission('OWNER', 'MEMBER') // true (owner >= member)\n * hasMinPermission('COLLABORATOR', 'MEMBER') // false (collaborator < member)\n * hasMinPermission(undefined, 'OWNER', true) // true (local mode)\n */\nexport function hasMinPermission(\n  authorAssociation: string | undefined,\n  minPermission: AuthorAssociation,\n  isLocalMode: boolean = false\n): boolean {\n  // In local mode (not GitHub Actions), treat as owner\n  if (isLocalMode) {\n    return true;\n  }\n\n  const authorLevel = getPermissionLevel(authorAssociation);\n  const minLevel = getPermissionLevel(minPermission);\n\n  // Lower number = higher privilege, so author must have equal or lower number\n  return authorLevel <= minLevel;\n}\n\n/**\n * Check if author is exactly the repository owner\n */\nexport function isOwner(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n): boolean {\n  if (isLocalMode) return true;\n  return authorAssociation?.toUpperCase() === 'OWNER';\n}\n\n/**\n * Check if author is an organization member or owner\n */\nexport function isMember(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n): boolean {\n  if (isLocalMode) return true;\n  return hasMinPermission(authorAssociation, 'MEMBER', isLocalMode);\n}\n\n/**\n * Check if author is a collaborator (or higher)\n */\nexport function isCollaborator(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n): boolean {\n  if (isLocalMode) return true;\n  return hasMinPermission(authorAssociation, 'COLLABORATOR', isLocalMode);\n}\n\n/**\n * Check if author is a contributor (has contributed before)\n */\nexport function isContributor(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n): boolean {\n  if (isLocalMode) return true;\n  return hasMinPermission(authorAssociation, 'CONTRIBUTOR', isLocalMode);\n}\n\n/**\n * Check if author is a first-time contributor (to this repo or GitHub)\n */\nexport function isFirstTimer(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n): boolean {\n  if (isLocalMode) return false; // In local mode, not a first-timer\n  const assoc = authorAssociation?.toUpperCase();\n  return assoc === 'FIRST_TIME_CONTRIBUTOR' || assoc === 'FIRST_TIMER';\n}\n\n/**\n * Create permission helper functions bound to a specific author association\n * This is used to inject functions into JavaScript execution contexts\n *\n * @param authorAssociation - The author's association from PR data\n * @param isLocalMode - Whether running in local/CLI mode\n */\nexport function createPermissionHelpers(\n  authorAssociation: string | undefined,\n  isLocalMode: boolean = false\n) {\n  return {\n    hasMinPermission: (minPermission: AuthorAssociation) =>\n      hasMinPermission(authorAssociation, minPermission, isLocalMode),\n    isOwner: () => isOwner(authorAssociation, isLocalMode),\n    isMember: () => isMember(authorAssociation, isLocalMode),\n    isCollaborator: () => isCollaborator(authorAssociation, isLocalMode),\n    isContributor: () => isContributor(authorAssociation, isLocalMode),\n    isFirstTimer: () => isFirstTimer(authorAssociation, isLocalMode),\n  };\n}\n\n/**\n * Determine if we're running in local mode (not GitHub Actions)\n */\nexport function detectLocalMode(): boolean {\n  return !process.env.GITHUB_ACTIONS;\n}\n\n/**\n * Resolve the most relevant GitHub author association from an event context.\n * Prefers commenter association for issue_comment events, then issue/PR author,\n * and finally falls back to the provided default association.\n */\nexport function resolveAssociationFromEvent(\n  eventContext: any | undefined,\n  fallback?: string\n): string | undefined {\n  try {\n    const ec = eventContext || {};\n    return (\n      ec?.comment?.author_association ||\n      ec?.issue?.author_association ||\n      ec?.pull_request?.author_association ||\n      fallback\n    );\n  } catch {\n    return fallback;\n  }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { MemoryConfig } from './types/config';\nimport { logger } from './logger';\n\n/**\n * Memory store for persistent key-value storage across checks\n * Supports namespaces for isolation and both in-memory and file-based persistence\n */\nexport class MemoryStore {\n  private static instance: MemoryStore;\n  private data: Map<string, Map<string, unknown>>; // namespace -> key -> value\n  private config: MemoryConfig;\n  private initialized = false;\n\n  private constructor(config?: MemoryConfig) {\n    this.data = new Map();\n    this.config = this.normalizeConfig(config);\n  }\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(config?: MemoryConfig): MemoryStore {\n    if (!MemoryStore.instance) {\n      MemoryStore.instance = new MemoryStore(config);\n    } else if (config && !MemoryStore.instance.initialized) {\n      // Update config if not yet initialized\n      MemoryStore.instance.config = MemoryStore.instance.normalizeConfig(config);\n    }\n    return MemoryStore.instance;\n  }\n\n  /**\n   * Reset singleton instance (for testing)\n   */\n  static resetInstance(): void {\n    MemoryStore.instance = undefined!;\n  }\n\n  /**\n   * Initialize memory store (load from file if configured)\n   */\n  async initialize(): Promise<void> {\n    if (this.initialized) {\n      return;\n    }\n\n    // Auto-load if file storage is configured\n    if (this.config.storage === 'file' && this.config.auto_load && this.config.file) {\n      try {\n        await this.load();\n        logger.debug(`Memory store loaded from ${this.config.file}`);\n      } catch (error) {\n        // If file doesn't exist, that's ok - we'll create it on first save\n        if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n          logger.warn(\n            `Failed to load memory store from ${this.config.file}: ${\n              error instanceof Error ? error.message : 'Unknown error'\n            }`\n          );\n        }\n      }\n    }\n\n    this.initialized = true;\n  }\n\n  /**\n   * Normalize and apply defaults to config\n   */\n  private normalizeConfig(config?: MemoryConfig): MemoryConfig {\n    const storage = config?.storage || 'memory';\n    return {\n      storage,\n      format: config?.format || 'json',\n      file: config?.file,\n      namespace: config?.namespace || 'default',\n      auto_load: config?.auto_load !== false,\n      auto_save: config?.auto_save !== false,\n    };\n  }\n\n  /**\n   * Get the default namespace\n   */\n  getDefaultNamespace(): string {\n    return this.config.namespace || 'default';\n  }\n\n  /**\n   * Get a value from memory\n   */\n  get(key: string, namespace?: string): unknown {\n    const ns = namespace || this.getDefaultNamespace();\n    const nsData = this.data.get(ns);\n    return nsData?.get(key);\n  }\n\n  /**\n   * Check if a key exists in memory\n   */\n  has(key: string, namespace?: string): boolean {\n    const ns = namespace || this.getDefaultNamespace();\n    const nsData = this.data.get(ns);\n    return nsData?.has(key) || false;\n  }\n\n  /**\n   * Set a value in memory (override existing)\n   */\n  async set(key: string, value: unknown, namespace?: string): Promise<void> {\n    const ns = namespace || this.getDefaultNamespace();\n\n    // Ensure namespace exists\n    if (!this.data.has(ns)) {\n      this.data.set(ns, new Map());\n    }\n\n    const nsData = this.data.get(ns)!;\n    nsData.set(key, value);\n\n    // Auto-save if configured\n    if (this.config.storage === 'file' && this.config.auto_save) {\n      await this.save();\n    }\n  }\n\n  /**\n   * Append a value to an array in memory\n   * If key doesn't exist, creates a new array\n   * If key exists but is not an array, converts it to an array\n   */\n  async append(key: string, value: unknown, namespace?: string): Promise<void> {\n    const ns = namespace || this.getDefaultNamespace();\n    const existing = this.get(key, ns);\n\n    let newValue: unknown[];\n    if (existing === undefined) {\n      // Create new array\n      newValue = [value];\n    } else if (Array.isArray(existing)) {\n      // Append to existing array\n      newValue = [...existing, value];\n    } else {\n      // Convert single value to array with both values\n      newValue = [existing, value];\n    }\n\n    await this.set(key, newValue, ns);\n  }\n\n  /**\n   * Increment a numeric value in memory\n   * If key doesn't exist, initializes to 0 before incrementing\n   * If key exists but is not a number, throws an error\n   */\n  async increment(key: string, amount = 1, namespace?: string): Promise<number> {\n    const ns = namespace || this.getDefaultNamespace();\n    const existing = this.get(key, ns);\n\n    let newValue: number;\n    if (existing === undefined || existing === null) {\n      // Initialize to 0 and then increment\n      newValue = amount;\n    } else if (typeof existing === 'number') {\n      // Increment existing number\n      newValue = existing + amount;\n    } else {\n      throw new Error(\n        `Cannot increment non-numeric value at key '${key}' (type: ${typeof existing})`\n      );\n    }\n\n    await this.set(key, newValue, ns);\n    return newValue;\n  }\n\n  /**\n   * Delete a key from memory\n   */\n  async delete(key: string, namespace?: string): Promise<boolean> {\n    const ns = namespace || this.getDefaultNamespace();\n    const nsData = this.data.get(ns);\n\n    if (!nsData) {\n      return false;\n    }\n\n    const deleted = nsData.delete(key);\n\n    // Auto-save if configured\n    if (deleted && this.config.storage === 'file' && this.config.auto_save) {\n      await this.save();\n    }\n\n    return deleted;\n  }\n\n  /**\n   * Clear all keys in a namespace (or all namespaces if none specified)\n   */\n  async clear(namespace?: string): Promise<void> {\n    if (namespace) {\n      // Clear specific namespace\n      this.data.delete(namespace);\n    } else {\n      // Clear all namespaces\n      this.data.clear();\n    }\n\n    // Auto-save if configured\n    if (this.config.storage === 'file' && this.config.auto_save) {\n      await this.save();\n    }\n  }\n\n  /**\n   * List all keys in a namespace\n   */\n  list(namespace?: string): string[] {\n    const ns = namespace || this.getDefaultNamespace();\n    const nsData = this.data.get(ns);\n    return nsData ? Array.from(nsData.keys()) : [];\n  }\n\n  /**\n   * List all namespaces\n   */\n  listNamespaces(): string[] {\n    return Array.from(this.data.keys());\n  }\n\n  /**\n   * Get all data in a namespace\n   */\n  getAll(namespace?: string): Record<string, unknown> {\n    const ns = namespace || this.getDefaultNamespace();\n    const nsData = this.data.get(ns);\n    if (!nsData) {\n      return {};\n    }\n\n    const result: Record<string, unknown> = {};\n    for (const [key, value] of nsData.entries()) {\n      result[key] = value;\n    }\n    return result;\n  }\n\n  /**\n   * Load data from file\n   */\n  async load(): Promise<void> {\n    if (!this.config.file) {\n      throw new Error('No file path configured for memory store');\n    }\n\n    const filePath = path.resolve(process.cwd(), this.config.file);\n    const content = await fs.readFile(filePath, 'utf-8');\n\n    if (this.config.format === 'json') {\n      await this.loadFromJson(content);\n    } else if (this.config.format === 'csv') {\n      await this.loadFromCsv(content);\n    } else {\n      throw new Error(`Unsupported format: ${this.config.format}`);\n    }\n  }\n\n  /**\n   * Save data to file\n   */\n  async save(): Promise<void> {\n    if (!this.config.file) {\n      throw new Error('No file path configured for memory store');\n    }\n\n    const filePath = path.resolve(process.cwd(), this.config.file);\n\n    // Ensure directory exists\n    const dir = path.dirname(filePath);\n    await fs.mkdir(dir, { recursive: true });\n\n    let content: string;\n    if (this.config.format === 'json') {\n      content = this.saveToJson();\n    } else if (this.config.format === 'csv') {\n      content = this.saveToCsv();\n    } else {\n      throw new Error(`Unsupported format: ${this.config.format}`);\n    }\n\n    await fs.writeFile(filePath, content, 'utf-8');\n  }\n\n  /**\n   * Load data from JSON format\n   */\n  private async loadFromJson(content: string): Promise<void> {\n    const data = JSON.parse(content);\n\n    // Clear existing data\n    this.data.clear();\n\n    // Load namespaces\n    for (const [namespace, nsData] of Object.entries(data)) {\n      if (typeof nsData === 'object' && nsData !== null && !Array.isArray(nsData)) {\n        const nsMap = new Map<string, unknown>();\n        for (const [key, value] of Object.entries(nsData)) {\n          nsMap.set(key, value);\n        }\n        this.data.set(namespace, nsMap);\n      }\n    }\n  }\n\n  /**\n   * Save data to JSON format\n   */\n  private saveToJson(): string {\n    const result: Record<string, Record<string, unknown>> = {};\n\n    for (const [namespace, nsData] of this.data.entries()) {\n      const nsObj: Record<string, unknown> = {};\n      for (const [key, value] of nsData.entries()) {\n        nsObj[key] = value;\n      }\n      result[namespace] = nsObj;\n    }\n\n    return JSON.stringify(result, null, 2);\n  }\n\n  /**\n   * Load data from CSV format\n   * CSV format: namespace,key,value,type\n   */\n  private async loadFromCsv(content: string): Promise<void> {\n    const lines = content.split('\\n').filter(line => line.trim());\n\n    // Skip header if present\n    let startIndex = 0;\n    if (lines[0]?.startsWith('namespace,')) {\n      startIndex = 1;\n    }\n\n    // Clear existing data\n    this.data.clear();\n\n    // Track arrays (keys that have multiple values)\n    const arrays = new Map<string, Map<string, unknown[]>>(); // namespace -> key -> values[]\n\n    for (let i = startIndex; i < lines.length; i++) {\n      const line = lines[i];\n      const parts = this.parseCsvLine(line);\n\n      if (parts.length < 3) {\n        logger.warn(`Invalid CSV line ${i + 1}: ${line}`);\n        continue;\n      }\n\n      const [namespace, key, valueStr, typeStr] = parts;\n      const value = this.parseCsvValue(valueStr, typeStr);\n\n      // Ensure namespace exists in data\n      if (!this.data.has(namespace)) {\n        this.data.set(namespace, new Map());\n        arrays.set(namespace, new Map());\n      }\n\n      const nsData = this.data.get(namespace)!;\n      const nsArrays = arrays.get(namespace)!;\n\n      // Check if this is a duplicate key (array)\n      if (nsData.has(key)) {\n        // Convert to array if not already\n        if (!nsArrays.has(key)) {\n          const existingValue = nsData.get(key);\n          nsArrays.set(key, [existingValue]);\n        }\n        nsArrays.get(key)!.push(value);\n        nsData.set(key, nsArrays.get(key)!);\n      } else {\n        // First occurrence\n        nsData.set(key, value);\n      }\n    }\n  }\n\n  /**\n   * Save data to CSV format\n   */\n  private saveToCsv(): string {\n    const lines: string[] = ['namespace,key,value,type'];\n\n    for (const [namespace, nsData] of this.data.entries()) {\n      for (const [key, value] of nsData.entries()) {\n        if (Array.isArray(value)) {\n          // Multiple rows for arrays\n          for (const item of value) {\n            lines.push(this.formatCsvLine(namespace, key, item));\n          }\n        } else {\n          // Single row\n          lines.push(this.formatCsvLine(namespace, key, value));\n        }\n      }\n    }\n\n    return lines.join('\\n') + '\\n';\n  }\n\n  /**\n   * Parse a CSV line, handling quoted values with commas\n   */\n  private parseCsvLine(line: string): string[] {\n    const parts: string[] = [];\n    let current = '';\n    let inQuotes = false;\n\n    for (let i = 0; i < line.length; i++) {\n      const char = line[i];\n\n      if (char === '\"') {\n        if (inQuotes && line[i + 1] === '\"') {\n          // Escaped quote\n          current += '\"';\n          i++;\n        } else {\n          // Toggle quotes\n          inQuotes = !inQuotes;\n        }\n      } else if (char === ',' && !inQuotes) {\n        // End of field\n        parts.push(current);\n        current = '';\n      } else {\n        current += char;\n      }\n    }\n\n    // Add last field\n    parts.push(current);\n\n    return parts;\n  }\n\n  /**\n   * Format a CSV line with proper escaping\n   */\n  private formatCsvLine(namespace: string, key: string, value: unknown): string {\n    const type = this.getValueType(value);\n    const valueStr = this.formatCsvValue(value);\n\n    return `${this.escapeCsv(namespace)},${this.escapeCsv(key)},${valueStr},${type}`;\n  }\n\n  /**\n   * Escape a CSV value\n   */\n  private escapeCsv(value: string): string {\n    if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\n      return `\"${value.replace(/\"/g, '\"\"')}\"`;\n    }\n    return value;\n  }\n\n  /**\n   * Format a value for CSV storage\n   */\n  private formatCsvValue(value: unknown): string {\n    if (value === null) {\n      return '\"\"';\n    }\n    if (value === undefined) {\n      return '\"\"';\n    }\n    if (typeof value === 'string') {\n      return this.escapeCsv(value);\n    }\n    if (typeof value === 'number' || typeof value === 'boolean') {\n      return this.escapeCsv(String(value));\n    }\n    // Objects and arrays are serialized as JSON\n    return this.escapeCsv(JSON.stringify(value));\n  }\n\n  /**\n   * Parse a CSV value based on its type\n   */\n  private parseCsvValue(valueStr: string, typeStr?: string): unknown {\n    if (!typeStr || typeStr === 'string') {\n      return valueStr;\n    }\n    if (typeStr === 'number') {\n      return Number(valueStr);\n    }\n    if (typeStr === 'boolean') {\n      return valueStr === 'true';\n    }\n    if (typeStr === 'object' || typeStr === 'array') {\n      try {\n        return JSON.parse(valueStr);\n      } catch {\n        return valueStr;\n      }\n    }\n    return valueStr;\n  }\n\n  /**\n   * Get the type of a value for CSV storage\n   */\n  private getValueType(value: unknown): string {\n    if (value === null || value === undefined) {\n      return 'string';\n    }\n    if (typeof value === 'number') {\n      return 'number';\n    }\n    if (typeof value === 'boolean') {\n      return 'boolean';\n    }\n    if (Array.isArray(value)) {\n      return 'array';\n    }\n    if (typeof value === 'object') {\n      return 'object';\n    }\n    return 'string';\n  }\n\n  /**\n   * Get the current configuration\n   */\n  getConfig(): MemoryConfig {\n    return { ...this.config };\n  }\n}\n"],"mappings":"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","names":["fs","path","path","fs"]}