"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var config_exports = {};
__export(config_exports, {
  addExcludePatterns: () => addExcludePatterns,
  addIncludePatterns: () => addIncludePatterns,
  createDefaultConfig: () => createDefaultConfig,
  isSafeRegex: () => isSafeRegex,
  loadConfig: () => loadConfig,
  saveConfig: () => saveConfig,
  shouldIncludeFile: () => shouldIncludeFile,
  updateConfig: () => updateConfig,
  validateConfig: () => validateConfig
});
module.exports = __toCommonJS(config_exports);
var fs = __toESM(require("fs"));
var path = __toESM(require("path"));
var import_picomatch = __toESM(require("picomatch"));
var import_errors = require("./errors");
const KIROGRAPH_DIR = ".kirograph";
const CONFIG_FILE = "config.json";
const KNOWN_FIELDS = /* @__PURE__ */ new Set([
  "version",
  "languages",
  "include",
  "exclude",
  "maxFileSize",
  "extractDocstrings",
  "trackCallSites",
  "enableEmbeddings",
  "embeddingModel",
  "embeddingDim",
  "useVecIndex",
  "semanticEngine",
  "typesenseDashboard",
  "qdrantDashboard",
  "minLogLevel",
  "frameworkHints",
  "fuzzyResolutionThreshold",
  "enableArchitecture",
  "architectureLayers",
  "cavemanMode",
  "shellCompressionLevel",
  "syncWarningThreshold",
  "enableMemory",
  "memorySearchAlpha",
  "memoryKeepRaw",
  "memoryMaxObservations",
  "memorySessionTimeout",
  "memoryContextLimit",
  "memoryContextThreshold",
  "memoryExcludePatterns",
  "enableDocs",
  "docsInclude",
  "docsExclude",
  "docsLinkCode",
  "docsContextLimit",
  "docsContextThreshold",
  "docsMaxFileSize",
  "docsSummarization",
  // Legacy aliases (still accepted, mapped during validation)
  "enableCompression",
  "compressionLevel"
]);
const LOG_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
function isSafeRegex(pattern) {
  if (pattern.length > 100) return false;
  if (/\([^)]*[+*][^)]*\)[+*?]/.test(pattern)) return false;
  if (/\([^)]*\|[^)]*\)[+*]/.test(pattern)) return false;
  return true;
}
function createDefaultConfig(_projectRoot) {
  return {
    version: 2,
    languages: [],
    include: [],
    exclude: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "*.min.js", "**/.kirograph/**"],
    maxFileSize: 1048576,
    extractDocstrings: true,
    trackCallSites: true,
    enableEmbeddings: false,
    embeddingModel: "nomic-ai/nomic-embed-text-v1.5",
    embeddingDim: 768,
    useVecIndex: false,
    semanticEngine: "cosine",
    typesenseDashboard: false,
    qdrantDashboard: false,
    minLogLevel: "warn",
    frameworkHints: [],
    fuzzyResolutionThreshold: 0.5,
    enableArchitecture: false,
    cavemanMode: "off",
    shellCompressionLevel: "normal",
    syncWarningThreshold: 10,
    enableMemory: false,
    memorySearchAlpha: 0.5,
    memoryKeepRaw: false,
    memoryMaxObservations: 1e4,
    memorySessionTimeout: 7200,
    memoryContextLimit: 3,
    memoryContextThreshold: 0.3,
    memoryExcludePatterns: [],
    enableDocs: false,
    docsInclude: ["**/*.md", "**/*.mdx", "**/*.rst", "**/*.adoc", "**/*.asciidoc", "**/*.rdoc", "**/*.org", "**/*.cheatmd", "docs/**/*.txt", "docs/**/*.html"],
    docsExclude: ["node_modules/**", "**/CHANGELOG*", "**/LICENSE*", "**/CHANGES*", "dist/**", "build/**", "coverage/**", ".git/**", "**/generated/**", "**/auto-generated/**", "**/vendor/**", "_build/**"],
    docsLinkCode: true,
    docsContextLimit: 0,
    docsContextThreshold: 0.3,
    docsMaxFileSize: 1048576,
    docsSummarization: "first-sentence"
  };
}
function validateConfig(config) {
  const defaults = createDefaultConfig();
  if (typeof config !== "object" || config === null) {
    return defaults;
  }
  const raw = config;
  for (const key of Object.keys(raw)) {
    if (!KNOWN_FIELDS.has(key)) {
      (0, import_errors.logWarn)(`Unknown config field: ${key}`);
    }
  }
  const version = typeof raw.version === "number" ? raw.version : defaults.version;
  const languages = Array.isArray(raw.languages) && raw.languages.every((l) => typeof l === "string") ? raw.languages : defaults.languages;
  const maxFileSize = typeof raw.maxFileSize === "number" && raw.maxFileSize > 0 ? raw.maxFileSize : defaults.maxFileSize;
  const extractDocstrings = typeof raw.extractDocstrings === "boolean" ? raw.extractDocstrings : defaults.extractDocstrings;
  const trackCallSites = typeof raw.trackCallSites === "boolean" ? raw.trackCallSites : defaults.trackCallSites;
  const enableEmbeddings = typeof raw.enableEmbeddings === "boolean" ? raw.enableEmbeddings : defaults.enableEmbeddings;
  const embeddingModel = typeof raw.embeddingModel === "string" && raw.embeddingModel.length > 0 ? raw.embeddingModel : defaults.embeddingModel;
  const embeddingDim = typeof raw.embeddingDim === "number" && raw.embeddingDim > 0 ? raw.embeddingDim : defaults.embeddingDim;
  const useVecIndex = typeof raw.useVecIndex === "boolean" ? raw.useVecIndex : defaults.useVecIndex;
  const SEMANTIC_ENGINES = /* @__PURE__ */ new Set(["cosine", "sqlite-vec", "orama", "pglite", "lancedb", "qdrant", "typesense"]);
  const semanticEngine = typeof raw.semanticEngine === "string" && SEMANTIC_ENGINES.has(raw.semanticEngine) ? raw.semanticEngine : useVecIndex ? "sqlite-vec" : defaults.semanticEngine;
  const typesenseDashboard = typeof raw.typesenseDashboard === "boolean" ? raw.typesenseDashboard : defaults.typesenseDashboard;
  const qdrantDashboard = typeof raw.qdrantDashboard === "boolean" ? raw.qdrantDashboard : defaults.qdrantDashboard;
  const minLogLevel = typeof raw.minLogLevel === "string" && LOG_LEVELS.has(raw.minLogLevel) ? raw.minLogLevel : defaults.minLogLevel;
  const frameworkHints = Array.isArray(raw.frameworkHints) && raw.frameworkHints.every((h) => typeof h === "string") ? raw.frameworkHints : defaults.frameworkHints;
  const fuzzyResolutionThreshold = typeof raw.fuzzyResolutionThreshold === "number" && raw.fuzzyResolutionThreshold >= 0 && raw.fuzzyResolutionThreshold <= 1 ? raw.fuzzyResolutionThreshold : defaults.fuzzyResolutionThreshold;
  const enableArchitecture = typeof raw.enableArchitecture === "boolean" ? raw.enableArchitecture : defaults.enableArchitecture;
  const architectureLayers = _validateArchitectureLayers(raw.architectureLayers);
  const CAVEMAN_MODES = /* @__PURE__ */ new Set(["off", "lite", "full", "ultra"]);
  const cavemanMode = typeof raw.cavemanMode === "string" && CAVEMAN_MODES.has(raw.cavemanMode) ? raw.cavemanMode : defaults.cavemanMode;
  const COMPRESSION_LEVELS = /* @__PURE__ */ new Set(["off", "normal", "aggressive", "ultra"]);
  let shellCompressionLevel;
  if (typeof raw.shellCompressionLevel === "string" && COMPRESSION_LEVELS.has(raw.shellCompressionLevel)) {
    shellCompressionLevel = raw.shellCompressionLevel;
  } else if (typeof raw.compressionLevel === "string" && COMPRESSION_LEVELS.has(raw.compressionLevel)) {
    shellCompressionLevel = raw.compressionLevel;
  } else if (typeof raw.enableCompression === "boolean") {
    shellCompressionLevel = raw.enableCompression ? "normal" : "off";
  } else {
    shellCompressionLevel = defaults.shellCompressionLevel;
  }
  const syncWarningThreshold = typeof raw.syncWarningThreshold === "number" && raw.syncWarningThreshold >= 0 ? Math.round(raw.syncWarningThreshold) : defaults.syncWarningThreshold;
  const enableMemory = typeof raw.enableMemory === "boolean" ? raw.enableMemory : defaults.enableMemory;
  const memorySearchAlpha = typeof raw.memorySearchAlpha === "number" && raw.memorySearchAlpha >= 0 && raw.memorySearchAlpha <= 1 ? raw.memorySearchAlpha : defaults.memorySearchAlpha;
  const memoryKeepRaw = typeof raw.memoryKeepRaw === "boolean" ? raw.memoryKeepRaw : defaults.memoryKeepRaw;
  const memoryMaxObservations = typeof raw.memoryMaxObservations === "number" && raw.memoryMaxObservations >= 0 ? Math.round(raw.memoryMaxObservations) : defaults.memoryMaxObservations;
  const memorySessionTimeout = typeof raw.memorySessionTimeout === "number" && raw.memorySessionTimeout > 0 ? Math.round(raw.memorySessionTimeout) : defaults.memorySessionTimeout;
  const memoryContextLimit = typeof raw.memoryContextLimit === "number" && raw.memoryContextLimit >= 0 ? Math.round(raw.memoryContextLimit) : defaults.memoryContextLimit;
  const memoryContextThreshold = typeof raw.memoryContextThreshold === "number" && raw.memoryContextThreshold >= 0 && raw.memoryContextThreshold <= 1 ? raw.memoryContextThreshold : defaults.memoryContextThreshold;
  const memoryExcludePatterns = Array.isArray(raw.memoryExcludePatterns) && raw.memoryExcludePatterns.every((p) => typeof p === "string") ? raw.memoryExcludePatterns : defaults.memoryExcludePatterns;
  const enableDocs = typeof raw.enableDocs === "boolean" ? raw.enableDocs : defaults.enableDocs;
  const docsInclude = Array.isArray(raw.docsInclude) && raw.docsInclude.every((p) => typeof p === "string") ? raw.docsInclude : defaults.docsInclude;
  const docsExclude = Array.isArray(raw.docsExclude) && raw.docsExclude.every((p) => typeof p === "string") ? raw.docsExclude : defaults.docsExclude;
  const docsLinkCode = typeof raw.docsLinkCode === "boolean" ? raw.docsLinkCode : defaults.docsLinkCode;
  const docsContextLimit = typeof raw.docsContextLimit === "number" && raw.docsContextLimit >= 0 ? Math.round(raw.docsContextLimit) : defaults.docsContextLimit;
  const docsContextThreshold = typeof raw.docsContextThreshold === "number" && raw.docsContextThreshold >= 0 && raw.docsContextThreshold <= 1 ? raw.docsContextThreshold : defaults.docsContextThreshold;
  const docsMaxFileSize = typeof raw.docsMaxFileSize === "number" && raw.docsMaxFileSize > 0 ? raw.docsMaxFileSize : defaults.docsMaxFileSize;
  const DOCS_SUMMARIZATION_MODES = /* @__PURE__ */ new Set(["embedding", "first-sentence", "off"]);
  const docsSummarization = typeof raw.docsSummarization === "string" && DOCS_SUMMARIZATION_MODES.has(raw.docsSummarization) ? raw.docsSummarization : defaults.docsSummarization;
  const include = _validatePatterns(raw.include, defaults.include);
  const exclude = _validatePatterns(raw.exclude, defaults.exclude);
  return {
    version,
    languages,
    include,
    exclude,
    maxFileSize,
    extractDocstrings,
    trackCallSites,
    enableEmbeddings,
    embeddingModel,
    embeddingDim,
    useVecIndex,
    semanticEngine,
    typesenseDashboard,
    qdrantDashboard,
    minLogLevel,
    frameworkHints,
    fuzzyResolutionThreshold,
    enableArchitecture,
    cavemanMode,
    shellCompressionLevel,
    syncWarningThreshold,
    enableMemory,
    memorySearchAlpha,
    memoryKeepRaw,
    memoryMaxObservations,
    memorySessionTimeout,
    memoryContextLimit,
    memoryContextThreshold,
    memoryExcludePatterns,
    enableDocs,
    docsInclude,
    docsExclude,
    docsLinkCode,
    docsContextLimit,
    docsContextThreshold,
    docsMaxFileSize,
    docsSummarization,
    ...architectureLayers !== void 0 ? { architectureLayers } : {}
  };
}
function _validateArchitectureLayers(raw) {
  if (raw === void 0 || raw === null) return void 0;
  if (typeof raw !== "object" || Array.isArray(raw)) return void 0;
  const result = {};
  for (const [key, val] of Object.entries(raw)) {
    if (typeof key !== "string") continue;
    if (!Array.isArray(val)) continue;
    const patterns = val.filter((p) => typeof p === "string" && isSafeRegex(p));
    if (patterns.length > 0) result[key] = patterns;
  }
  return Object.keys(result).length > 0 ? result : void 0;
}
function _validatePatterns(raw, fallback) {
  if (!Array.isArray(raw)) return fallback;
  const valid = [];
  for (const p of raw) {
    if (typeof p !== "string") continue;
    if (!isSafeRegex(p)) {
      (0, import_errors.logWarn)(`Unsafe regex pattern skipped: ${p}`);
      continue;
    }
    valid.push(p);
  }
  return valid;
}
const SHALLOW_TO_RECURSIVE = {
  "node_modules/**": "**/node_modules/**",
  "dist/**": "**/dist/**",
  "build/**": "**/build/**",
  ".git/**": "**/.git/**",
  ".kirograph/**": "**/.kirograph/**"
};
function migrateExcludePatterns(patterns) {
  return patterns.map((p) => SHALLOW_TO_RECURSIVE[p] ?? p);
}
async function loadConfig(projectRoot) {
  const dir = path.join(projectRoot, KIROGRAPH_DIR);
  const cfgPath = path.join(dir, CONFIG_FILE);
  if (!fs.existsSync(cfgPath)) {
    const defaults = createDefaultConfig(projectRoot);
    await fs.promises.mkdir(dir, { recursive: true });
    await _writeAtomic(cfgPath, defaults);
    return defaults;
  }
  let raw;
  try {
    const text = await fs.promises.readFile(cfgPath, "utf8");
    raw = JSON.parse(text);
  } catch (err) {
    (0, import_errors.logError)("Config parse error", { path: cfgPath, error: err instanceof Error ? err.message : String(err) });
    return createDefaultConfig(projectRoot);
  }
  const config = validateConfig(raw);
  if (config.version < 2) {
    config.version = 2;
    config.exclude = migrateExcludePatterns(config.exclude);
    await fs.promises.mkdir(dir, { recursive: true });
    await _writeAtomic(cfgPath, config);
  }
  return config;
}
async function saveConfig(projectRoot, config) {
  const dir = path.join(projectRoot, KIROGRAPH_DIR);
  const cfgPath = path.join(dir, CONFIG_FILE);
  await fs.promises.mkdir(dir, { recursive: true });
  await _writeAtomic(cfgPath, config);
}
async function _writeAtomic(cfgPath, config) {
  const tmp = cfgPath + ".tmp";
  await fs.promises.writeFile(tmp, JSON.stringify(config, null, 2), "utf8");
  await fs.promises.rename(tmp, cfgPath);
}
async function updateConfig(projectRoot, patch) {
  const current = await loadConfig(projectRoot);
  const updated = validateConfig({ ...current, ...patch });
  await saveConfig(projectRoot, updated);
  return updated;
}
async function addIncludePatterns(projectRoot, patterns) {
  const config = await loadConfig(projectRoot);
  const existing = new Set(config.include);
  const toAdd = patterns.filter((p) => isSafeRegex(p) && !existing.has(p));
  if (toAdd.length === 0) return;
  await saveConfig(projectRoot, { ...config, include: [...config.include, ...toAdd] });
}
async function addExcludePatterns(projectRoot, patterns) {
  const config = await loadConfig(projectRoot);
  const existing = new Set(config.exclude);
  const toAdd = patterns.filter((p) => isSafeRegex(p) && !existing.has(p));
  if (toAdd.length === 0) return;
  await saveConfig(projectRoot, { ...config, exclude: [...config.exclude, ...toAdd] });
}
function shouldIncludeFile(config, relPath) {
  for (const pattern of config.exclude) {
    if ((0, import_picomatch.default)(pattern)(relPath)) return false;
  }
  if (config.include.length > 0) {
    return config.include.some((pattern) => (0, import_picomatch.default)(pattern)(relPath));
  }
  return true;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  addExcludePatterns,
  addIncludePatterns,
  createDefaultConfig,
  isSafeRegex,
  loadConfig,
  saveConfig,
  shouldIncludeFile,
  updateConfig,
  validateConfig
});
//# sourceMappingURL=config.js.map
