"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 index_exports = {};
__export(index_exports, {
  default: () => KiroGraph,
  findNearestKiroGraphRoot: () => findNearestKiroGraphRoot
});
module.exports = __toCommonJS(index_exports);
var path = __toESM(require("path"));
var fs = __toESM(require("fs"));
var import_database = require("./db/database");
var import_utils = require("./utils");
var import_config = require("./config");
var import_queries = require("./graph/queries");
var import_resolution = require("./resolution/index");
var import_vectors = require("./vectors/index");
var import_context = require("./context/index");
var import_architecture = require("./architecture/index");
var import_lock_manager = require("./core/lock-manager");
var import_pipeline = require("./core/pipeline");
var import_file_tree = require("./core/file-tree");
var import_snapshot = require("./core/snapshot");
var import_searcher = require("./search/searcher");
const KIROGRAPH_DIR = ".kirograph";
class KiroGraph {
  constructor(projectRoot, db, config) {
    this.projectRoot = projectRoot;
    this.db = db;
    this.config = config;
    this.queryManager = new import_queries.GraphQueryManager(db);
    this.resolver = new import_resolution.ReferenceResolver(db, config);
    this.vectors = new import_vectors.VectorManager(db, config, projectRoot);
    this.contextBuilder = new import_context.ContextBuilder(db, this.resolver, this.vectors, projectRoot);
    this.arch = new import_architecture.ArchitectureAnalyzer(db, config, projectRoot);
    this.lock = new import_lock_manager.LockManager(projectRoot);
    this.pipeline = new import_pipeline.IndexPipeline(db, this.vectors, this.resolver, this.arch, this.lock, config, projectRoot);
    this.searcher = new import_searcher.Searcher(db);
  }
  // ── Factory ────────────────────────────────────────────────────────────────
  static async init(projectRoot, config, onModelProgress) {
    const resolved = path.resolve(projectRoot);
    (0, import_utils.validateProjectPath)(resolved);
    fs.mkdirSync(path.join(resolved, KIROGRAPH_DIR), { recursive: true });
    const cfg = { ...(0, import_config.createDefaultConfig)(resolved), ...config };
    await (0, import_config.saveConfig)(resolved, cfg);
    const db = new import_database.GraphDatabase(resolved);
    const kg = new KiroGraph(resolved, db, cfg);
    await kg.vectors.initialize(onModelProgress);
    return kg;
  }
  static async open(projectRoot, onModelProgress) {
    const resolved = path.resolve(projectRoot);
    (0, import_utils.validateProjectPath)(resolved);
    if (!fs.existsSync(path.join(resolved, KIROGRAPH_DIR))) {
      throw new Error(`KiroGraph not initialized at ${resolved}. Run: kirograph init`);
    }
    const cfg = await (0, import_config.loadConfig)(resolved);
    const db = new import_database.GraphDatabase(resolved);
    const kg = new KiroGraph(resolved, db, cfg);
    await kg.vectors.initialize(onModelProgress);
    return kg;
  }
  static isInitialized(projectRoot) {
    return fs.existsSync(path.join(path.resolve(projectRoot), KIROGRAPH_DIR));
  }
  // ── Lock / dirty marker ────────────────────────────────────────────────────
  unlockForce() {
    this.lock.forceRelease();
  }
  markDirty() {
    this.lock.markDirty();
  }
  clearDirty() {
    this.lock.clearDirty();
  }
  isDirty() {
    return this.lock.isDirty();
  }
  isIndexLocked() {
    return this.lock.isLocked();
  }
  async syncIfDirty() {
    if (!this.isDirty()) return null;
    return this.sync();
  }
  /**
   * Returns the number of files that have changed on disk but are not yet
   * reflected in the index. Used by the MCP status tool to warn the agent
   * when the index may be stale.
   */
  async getPendingSyncCount() {
    try {
      const { getChangedFiles, scanDirectory } = await Promise.resolve().then(() => require("./sync/index.js"));
      const gitChanged = await getChangedFiles(this.projectRoot, this.config);
      const hasGitChanges = gitChanged.added.length > 0 || gitChanged.modified.length > 0 || gitChanged.removed.length > 0;
      if (hasGitChanges) {
        return gitChanged.added.length + gitChanged.modified.length + gitChanged.removed.length;
      }
      const indexed = new Set(this.db.getAllFiles().map((f) => f.path));
      const current = new Set(
        (await scanDirectory(this.projectRoot, this.config)).map((f) => require("path").relative(this.projectRoot, f).replace(/\\/g, "/"))
      );
      let pending = 0;
      for (const p of indexed) {
        if (!current.has(p)) pending++;
      }
      for (const p of current) {
        if (!indexed.has(p)) pending++;
      }
      return pending;
    } catch {
      return 0;
    }
  }
  // ── Indexing ───────────────────────────────────────────────────────────────
  async indexAll(opts) {
    return this.pipeline.indexAll(opts);
  }
  async sync(changedFilesOrOpts) {
    if (Array.isArray(changedFilesOrOpts)) {
      return this.pipeline.sync({ changedFiles: changedFilesOrOpts });
    }
    return this.pipeline.sync({
      changedFiles: changedFilesOrOpts?.files,
      onProgress: changedFilesOrOpts?.onProgress
    });
  }
  // ── Symbol search ──────────────────────────────────────────────────────────
  searchNodes(query, kindOrOpts, limit = 20) {
    return this.searcher.search(query, kindOrOpts, limit);
  }
  // ── Graph queries ──────────────────────────────────────────────────────────
  async getCallers(nodeId, limit = 30) {
    return this.queryManager.getCallers(nodeId, limit);
  }
  async getCallees(nodeId, limit = 30) {
    return this.queryManager.getCallees(nodeId, limit);
  }
  async getImpactRadius(nodeId, depth = 2) {
    return this.queryManager.getImpactRadius(nodeId, depth);
  }
  getAllNodes() {
    return this.db.getAllNodes();
  }
  getAllEdges() {
    return this.db.getAllEdges();
  }
  findDeadCode(limit = 50) {
    return this.db.findDeadCode(limit);
  }
  findCircularDependencies() {
    return this.db.findCircularDependencies();
  }
  async findPath(fromId, toId, maxDepth = 10) {
    return this.queryManager.findPath(fromId, toId, maxDepth);
  }
  getTypeHierarchy(nodeId, direction = "both") {
    return this.db.getTypeHierarchy(nodeId, direction);
  }
  getNode(id) {
    return this.db.getNode(id);
  }
  getNodeContext(nodeId) {
    return this.db.getNodeContext(nodeId);
  }
  getNodeMetrics(nodeId) {
    return this.db.getNodeMetrics(nodeId);
  }
  getNodeSource(node) {
    const absPath = (0, import_utils.validatePathWithinRoot)(path.join(this.projectRoot, node.filePath), this.projectRoot);
    if (!absPath) return null;
    try {
      return fs.readFileSync(absPath, "utf8").split("\n").slice(node.startLine - 1, node.endLine).join("\n");
    } catch {
      return null;
    }
  }
  // ── Context building ───────────────────────────────────────────────────────
  async buildContext(task, opts) {
    return this.contextBuilder.buildTaskContext(task, opts);
  }
  // ── File browsing ──────────────────────────────────────────────────────────
  getFiles(opts) {
    const picomatch = opts?.pattern ? require("picomatch")(opts.pattern) : null;
    const filtered = this.db.getAllFiles().filter((f) => {
      if (opts?.filterPath && !f.path.startsWith(opts.filterPath)) return false;
      if (picomatch && !picomatch(f.path)) return false;
      return true;
    });
    return (0, import_file_tree.buildFileTree)(filtered, opts?.maxDepth);
  }
  getAffectedTests(changedFiles, opts) {
    return this.queryManager.getAffectedTests(changedFiles, opts);
  }
  // ── Graph insights ─────────────────────────────────────────────────────────
  findHotspots(limit = 20) {
    return this.db.findHotspots(limit);
  }
  findSurprisingConnections(limit = 20) {
    return this.db.findSurprisingConnections(limit);
  }
  // ── Snapshots ──────────────────────────────────────────────────────────────
  createSnapshotManager() {
    return new import_snapshot.SnapshotManager(this.db, this.projectRoot);
  }
  // ── Stats ──────────────────────────────────────────────────────────────────
  async getStats() {
    const stats = this.db.getStats();
    const vecIndexCount = await this.vectors.vecIndexCount();
    const embeddingCount = vecIndexCount > 0 ? vecIndexCount : stats.embeddingCount;
    const EMBEDDABLE = ["function", "method", "class", "interface", "type_alias", "component", "module"];
    const embeddableNodeCount = EMBEDDABLE.reduce((sum, k) => sum + (stats.nodesByKind[k] ?? 0), 0);
    const pendingFiles = await this.getPendingSyncCount();
    const syncRunning = this.isIndexLocked();
    return {
      ...stats,
      embeddingCount,
      embeddableNodeCount,
      embeddingsEnabled: this.config.enableEmbeddings ?? false,
      embeddingModel: this.config.embeddingModel,
      useVecIndex: this.config.useVecIndex ?? false,
      semanticEngine: this.config.semanticEngine ?? "cosine",
      vecIndexCount,
      engineFallback: this.vectors.getEngineFallback(),
      frameworks: this.config.frameworkHints ?? [],
      architectureEnabled: this.config.enableArchitecture ?? false,
      ...this.config.enableArchitecture ? { architectureStats: this.db.getArchStats() } : {},
      pendingFiles,
      syncRunning,
      syncWarningThreshold: this.config.syncWarningThreshold ?? 10
    };
  }
  getEngineFallback() {
    return this.vectors.getEngineFallback();
  }
  // ── Architecture API ───────────────────────────────────────────────────────
  getArchitecture() {
    const base = this.db.getArchitectureResult();
    const filePackages = {};
    for (const { filePath, packageId } of this.db.getArchFilePackages()) {
      if (!filePackages[filePath]) filePackages[filePath] = [];
      filePackages[filePath].push(packageId);
    }
    const fileLayers = {};
    for (const row of this.db.getArchFileLayers()) {
      if (!fileLayers[row.filePath]) fileLayers[row.filePath] = [];
      fileLayers[row.filePath].push({ layerId: row.layerId, confidence: row.confidence, matchedPattern: row.matchedPattern });
    }
    return { ...base, filePackages, fileLayers };
  }
  isArchitectureEnabled() {
    return this.config.enableArchitecture ?? false;
  }
  // ── Misc ───────────────────────────────────────────────────────────────────
  getProjectRoot() {
    return this.projectRoot;
  }
  getDatabase() {
    return this.db;
  }
  close() {
    this.vectors.close();
    this.lock.release();
    this.db.close();
  }
}
function findNearestKiroGraphRoot(startPath) {
  let current = path.resolve(startPath);
  while (true) {
    if (fs.existsSync(path.join(current, KIROGRAPH_DIR))) return current;
    const parent = path.dirname(current);
    if (parent === current) return null;
    current = parent;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  findNearestKiroGraphRoot
});
//# sourceMappingURL=index.js.map
