"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var memory_exports = {};
__export(memory_exports, {
  MemoryDatabase: () => import_database2.MemoryDatabase,
  MemoryManager: () => MemoryManager,
  MemoryVectorManager: () => import_vectors2.MemoryVectorManager,
  compressObservation: () => import_compress2.compressObservation,
  detectSymbols: () => import_symbols2.detectSymbols,
  extractIdentifiers: () => import_compress2.extractIdentifiers
});
module.exports = __toCommonJS(memory_exports);
var import_database = require("./database");
var import_compress = require("./compress");
var import_symbols = require("./symbols");
var import_vectors = require("./vectors");
var import_errors = require("../errors");
var import_database2 = require("./database");
var import_compress2 = require("./compress");
var import_symbols2 = require("./symbols");
var import_vectors2 = require("./vectors");
__reExport(memory_exports, require("./types"), module.exports);
class MemoryManager {
  constructor(config, db) {
    this.config = config;
    this.db = db;
    this.memDb = new import_database.MemoryDatabase(db);
    this.vectorMgr = new import_vectors.MemoryVectorManager(config, this.memDb);
    this.cavemanMode = config.cavemanMode ?? "off";
    this.excludePatterns = config.memoryExcludePatterns ?? [];
  }
  /**
   * Initialize memory tables. Must be called before any operations.
   */
  initialize() {
    this.memDb.initialize();
  }
  /**
   * Check if memory is enabled in config.
   */
  static isEnabled(config) {
    return !!config.enableMemory;
  }
  // ── Store ──────────────────────────────────────────────────────────────────
  /**
   * Store an observation. Handles:
   * 1. Privacy stripping (<private> blocks)
   * 2. Exclude pattern checking
   * 3. Caveman compression (if enabled)
   * 4. Deduplication (content hash)
   * 5. Symbol detection and linking
   * 6. Embedding (if enabled)
   *
   * Returns the observation ID, or null if skipped (duplicate or excluded).
   */
  async store(input, ide = "kiro") {
    let text = input.content;
    text = import_database.MemoryDatabase.stripPrivate(text);
    if (!text.trim()) return null;
    if (this.shouldExclude(text)) return null;
    let contentRaw;
    if (this.cavemanMode !== "off") {
      const result = (0, import_compress.compressObservation)(text, this.cavemanMode);
      contentRaw = text;
      text = result.compressed;
    }
    const cwd = process.cwd();
    const sessionTimeout = this.config.memorySessionTimeout ?? 7200;
    const sessionId = this.memDb.getOrCreateSession(ide, cwd, sessionTimeout);
    const id = this.memDb.insertObservation(text, {
      contentRaw: this.cavemanMode !== "off" ? contentRaw : void 0,
      kind: input.kind ?? "note",
      source: input.source ?? "manual",
      tags: input.tags,
      sessionId
    });
    if (!id) {
      (0, import_errors.logDebug)("Memory: duplicate observation skipped");
      return null;
    }
    const symbols = (0, import_symbols.detectSymbols)(text, this.db);
    if (symbols.length > 0) {
      this.memDb.linkToSymbols(id, symbols.map((s) => s.qualifiedName));
    }
    if (contentRaw) {
      const rawSymbols = (0, import_symbols.detectSymbols)(contentRaw, this.db);
      const extraSymbols = rawSymbols.filter(
        (s) => !symbols.some((existing) => existing.qualifiedName === s.qualifiedName)
      );
      if (extraSymbols.length > 0) {
        this.memDb.linkToSymbols(id, extraSymbols.map((s) => s.qualifiedName));
      }
    }
    const obs = this.memDb.getObservation(id);
    if (obs) {
      await this.vectorMgr.embedObservation(obs);
    }
    return id;
  }
  // ── Search ─────────────────────────────────────────────────────────────────
  /**
   * Hybrid search: combines FTS5 and vector search with configurable alpha.
   */
  async search(query, opts = {}) {
    const limit = opts.limit ?? 10;
    const alpha = opts.alpha ?? this.config.memorySearchAlpha ?? 0.5;
    const ftsResults = this.memDb.searchFTS(query, { ...opts, limit: limit * 2 });
    let vectorResults = [];
    if (this.vectorMgr.isEnabled() && !this.vectorMgr.hasModelMismatch()) {
      vectorResults = await this.vectorMgr.search(query, limit * 2);
    }
    if (vectorResults.length === 0) return ftsResults.slice(0, limit);
    if (ftsResults.length === 0) return vectorResults.slice(0, limit);
    const merged = this.mergeResults(ftsResults, vectorResults, alpha);
    return merged.slice(0, limit);
  }
  /**
   * Get observations linked to specific symbols.
   * Used by kirograph_context and kirograph_impact.
   */
  getLinkedObservations(qualifiedNames, limit = 3, threshold = 0.3) {
    const results = this.memDb.getLinkedObservationsForSymbols(qualifiedNames, limit * 2);
    return results.filter((r) => r.score >= threshold).slice(0, limit);
  }
  // ── Timeline ───────────────────────────────────────────────────────────────
  /**
   * List sessions with their observation counts.
   */
  timeline(opts = {}) {
    const limit = opts.limit ?? 5;
    if (opts.sessionId) {
      const session = this.memDb.getSession(opts.sessionId);
      if (!session) return { sessions: [], observations: /* @__PURE__ */ new Map() };
      const obs = this.memDb.getObservationsBySession(opts.sessionId);
      const map = /* @__PURE__ */ new Map();
      map.set(opts.sessionId, obs);
      return { sessions: [session], observations: map };
    }
    const sessions = this.memDb.listSessions(limit);
    const observations = /* @__PURE__ */ new Map();
    for (const session of sessions) {
      const obs = this.memDb.getObservationsBySession(session.id, 10);
      observations.set(session.id, obs);
    }
    return { sessions, observations };
  }
  // ── Status ─────────────────────────────────────────────────────────────────
  getStats() {
    const modelName = this.config.embeddingModel ?? "nomic-ai/nomic-embed-text-v1.5";
    return this.memDb.getStats(modelName);
  }
  // ── Session management ─────────────────────────────────────────────────────
  endCurrentSession(ide = "kiro") {
    const cwd = process.cwd();
    const sessionTimeout = this.config.memorySessionTimeout ?? 7200;
    const sessionId = this.memDb.getOrCreateSession(ide, cwd, sessionTimeout);
    this.memDb.endSession(sessionId);
  }
  // ── Maintenance ────────────────────────────────────────────────────────────
  prune(olderThanMs) {
    const cutoff = Date.now() - olderThanMs;
    return this.memDb.prune(cutoff);
  }
  async reembed(batchSize = 32) {
    return this.vectorMgr.reembed(batchSize);
  }
  lint() {
    const staleLinks = this.memDb.findStaleLinks().length;
    const modelMismatch = this.vectorMgr.hasModelMismatch();
    const sessionTimeout = (this.config.memorySessionTimeout ?? 7200) * 1e3;
    const staleSessions = this.memDb.closeStaleSessionsOlderThan(sessionTimeout);
    return { staleLinks, modelMismatch, staleSessions };
  }
  removeStaleLinks() {
    return this.memDb.removeStaleLinks();
  }
  // ── Private ────────────────────────────────────────────────────────────────
  shouldExclude(text) {
    if (this.excludePatterns.length === 0) return false;
    for (const pattern of this.excludePatterns) {
      const normalized = pattern.replace(/\*/g, "");
      if (normalized && text.includes(normalized)) return true;
    }
    return false;
  }
  mergeResults(ftsResults, vectorResults, alpha) {
    const maxFts = Math.max(...ftsResults.map((r) => r.score), 1);
    const normalizedFts = /* @__PURE__ */ new Map();
    for (const r of ftsResults) {
      normalizedFts.set(r.observation.id, r.score / maxFts);
    }
    const normalizedVec = /* @__PURE__ */ new Map();
    for (const r of vectorResults) {
      normalizedVec.set(r.observation.id, r.score);
    }
    const allIds = /* @__PURE__ */ new Set([...normalizedFts.keys(), ...normalizedVec.keys()]);
    const merged = [];
    const obsMap = /* @__PURE__ */ new Map();
    for (const r of ftsResults) obsMap.set(r.observation.id, r.observation);
    for (const r of vectorResults) obsMap.set(r.observation.id, r.observation);
    for (const id of allIds) {
      const ftsScore = normalizedFts.get(id) ?? 0;
      const vecScore = normalizedVec.get(id) ?? 0;
      const hybridScore = (1 - alpha) * ftsScore + alpha * vecScore;
      const obs = obsMap.get(id);
      merged.push({ observation: obs, score: hybridScore, scoreSource: "hybrid" });
    }
    merged.sort((a, b) => b.score - a.score);
    return merged;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  MemoryDatabase,
  MemoryManager,
  MemoryVectorManager,
  compressObservation,
  detectSymbols,
  extractIdentifiers,
  ...require("./types")
});
//# sourceMappingURL=index.js.map
