// src/temporal-index.ts
import * as fs from "fs";
import * as path from "path";
var INDEX_VERSION = 1;
var TEMPORAL_INDEX_FILE = "index_time.json";
var TAG_INDEX_FILE = "index_tags.json";
var TAG_INDEX_VERSION = 2;
function stateDir(memoryDir) {
  return path.join(memoryDir, "state");
}
function temporalIndexPath(memoryDir) {
  return path.join(stateDir(memoryDir), TEMPORAL_INDEX_FILE);
}
function tagIndexPath(memoryDir) {
  return path.join(stateDir(memoryDir), TAG_INDEX_FILE);
}
function ensureStateDir(memoryDir) {
  const dir = stateDir(memoryDir);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
}
function readJsonSafe(filePath, fallback) {
  try {
    const raw = fs.readFileSync(filePath, "utf8");
    return JSON.parse(raw);
  } catch {
    return fallback;
  }
}
function writeJsonSafe(filePath, data) {
  try {
    fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
  } catch {
  }
}
function writeJsonAtomic(filePath, data) {
  const tmp = `${filePath}.tmp`;
  try {
    fs.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
    fs.renameSync(tmp, filePath);
  } catch {
    writeJsonSafe(filePath, data);
    try {
      fs.unlinkSync(tmp);
    } catch {
    }
  }
}
function isoDateFromTimestamp(isoString) {
  if (typeof isoString !== "string" || isoString.length < 10) {
    console.warn(`[engram] temporal-index: malformed timestamp "${isoString}", falling back to today`);
    return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
  }
  return isoString.slice(0, 10);
}
function addPathToSet(record, key, p) {
  if (!record[key]) {
    record[key] = [];
  }
  if (!record[key].includes(p)) {
    record[key].push(p);
  }
}
function removePathFromSet(record, key, p) {
  if (!record[key]) return;
  record[key] = record[key].filter((x) => x !== p);
  if (record[key].length === 0) {
    delete record[key];
  }
}
function normalizeTagSegment(segment) {
  return segment.trim().toLowerCase().replace(/[_\s]+/g, "-").replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
}
function normalizeCanonicalTag(tag) {
  return tag.trim().toLowerCase().replace(/\s*[>:|.]+\s*/g, "/").replace(/\s*\/\s*/g, "/").split("/").map(normalizeTagSegment).filter(Boolean).join("/");
}
function normalizeAliasKey(tag) {
  return tag.trim().toLowerCase().replace(/[\/_.:-]+/g, " ").replace(/[-]+/g, " ").replace(/[^a-z0-9\s]+/g, " ").replace(/\s+/g, " ").trim();
}
function singularizeAlias(alias) {
  if (!alias.endsWith("s") || alias.length <= 3) return null;
  return alias.slice(0, -1);
}
function deriveParentTags(canonical) {
  const parts = canonical.split("/").filter(Boolean);
  const parents = [];
  for (let i = parts.length - 1; i > 0; i -= 1) {
    parents.push(parts.slice(0, i).join("/"));
  }
  return parents;
}
function deriveTagAliases(rawTag, canonical) {
  const aliases = /* @__PURE__ */ new Set();
  const canonicalAlias = normalizeAliasKey(canonical);
  const rawAlias = normalizeAliasKey(rawTag);
  const leaf = canonical.split("/").at(-1) ?? canonical;
  const leafAlias = normalizeAliasKey(leaf);
  for (const candidate of [canonicalAlias, rawAlias, leafAlias]) {
    if (!candidate) continue;
    aliases.add(candidate);
    const singular = singularizeAlias(candidate);
    if (singular) aliases.add(singular);
  }
  return Array.from(aliases);
}
function normalizeTagIndex(raw) {
  const normalized = {
    version: TAG_INDEX_VERSION,
    tags: {},
    aliases: {}
  };
  if (!raw || typeof raw !== "object") {
    return normalized;
  }
  const sourceTags = raw.tags ?? {};
  for (const [rawCanonical, nodeOrPaths] of Object.entries(sourceTags)) {
    const canonical = normalizeCanonicalTag(rawCanonical);
    if (!canonical) continue;
    const node = Array.isArray(nodeOrPaths) ? { paths: [...new Set(nodeOrPaths)] } : {
      paths: Array.isArray(nodeOrPaths?.paths) ? [...new Set(nodeOrPaths.paths)] : [],
      aliases: Array.isArray(nodeOrPaths?.aliases) ? [...new Set(nodeOrPaths.aliases)] : [],
      parents: Array.isArray(nodeOrPaths?.parents) ? [...new Set(nodeOrPaths.parents)] : []
    };
    const existingNode = normalized.tags[canonical];
    if (existingNode && !Array.isArray(existingNode)) {
      existingNode.paths = [.../* @__PURE__ */ new Set([...existingNode.paths, ...node.paths])];
      existingNode.aliases = [.../* @__PURE__ */ new Set([...existingNode.aliases ?? [], ...node.aliases ?? []])];
      existingNode.parents = [.../* @__PURE__ */ new Set([...existingNode.parents ?? [], ...node.parents ?? []])];
    } else if (Array.isArray(existingNode)) {
      normalized.tags[canonical] = {
        paths: [.../* @__PURE__ */ new Set([...existingNode, ...node.paths])],
        aliases: [...new Set(node.aliases ?? [])],
        parents: [...new Set(node.parents ?? deriveParentTags(canonical))]
      };
    } else {
      normalized.tags[canonical] = node;
    }
    for (const alias of deriveTagAliases(canonical, canonical)) {
      const list = normalized.aliases[alias] ?? [];
      if (!list.includes(canonical)) list.push(canonical);
      normalized.aliases[alias] = list;
    }
    for (const alias of node.aliases ?? []) {
      const aliasKey = normalizeAliasKey(alias);
      if (!aliasKey) continue;
      const list = normalized.aliases[aliasKey] ?? [];
      if (!list.includes(canonical)) list.push(canonical);
      normalized.aliases[aliasKey] = list;
    }
    const mergedNode = normalized.tags[canonical];
    if (mergedNode && !Array.isArray(mergedNode)) {
      mergedNode.parents = [...new Set(mergedNode.parents ?? deriveParentTags(canonical))];
    }
  }
  for (const [alias, canonicals] of Object.entries(raw.aliases ?? {})) {
    const aliasKey = normalizeAliasKey(alias);
    if (!aliasKey) continue;
    const list = normalized.aliases[aliasKey] ?? [];
    for (const canonical of canonicals ?? []) {
      const normalizedCanonical = normalizeCanonicalTag(canonical);
      if (normalizedCanonical && !list.includes(normalizedCanonical)) {
        list.push(normalizedCanonical);
      }
    }
    normalized.aliases[aliasKey] = list;
  }
  return normalized;
}
function ensureTagNode(index, canonical) {
  const existing = index.tags[canonical];
  if (existing && !Array.isArray(existing)) {
    return existing;
  }
  const created = {
    paths: Array.isArray(existing) ? [...new Set(existing)] : [],
    aliases: [],
    parents: deriveParentTags(canonical)
  };
  index.tags[canonical] = created;
  return created;
}
function addTagGraphEntry(index, rawTag, memoryPath) {
  const canonical = normalizeCanonicalTag(rawTag);
  if (!canonical) return;
  const node = ensureTagNode(index, canonical);
  if (!node.paths.includes(memoryPath)) {
    node.paths.push(memoryPath);
  }
  for (const alias of deriveTagAliases(rawTag, canonical)) {
    const aliasKey = normalizeAliasKey(alias);
    if (!aliasKey) continue;
    if (!node.aliases?.includes(aliasKey)) {
      node.aliases = [.../* @__PURE__ */ new Set([...node.aliases ?? [], aliasKey])];
    }
    const list = index.aliases?.[aliasKey] ?? [];
    if (!list.includes(canonical)) {
      index.aliases[aliasKey] = [...list, canonical];
    }
  }
}
function removeTagGraphEntry(index, rawTag, memoryPath) {
  const canonical = normalizeCanonicalTag(rawTag);
  if (!canonical) return;
  const node = index.tags[canonical];
  if (!node || Array.isArray(node)) return;
  node.paths = node.paths.filter((value) => value !== memoryPath);
  if (node.paths.length === 0) {
    delete index.tags[canonical];
  }
}
function expandCanonicalTags(index, rawTags) {
  const canonicals = /* @__PURE__ */ new Set();
  for (const rawTag of rawTags) {
    const canonical = normalizeCanonicalTag(rawTag);
    if (canonical && index.tags[canonical]) {
      canonicals.add(canonical);
    }
    const aliasKey = normalizeAliasKey(rawTag);
    for (const resolved of index.aliases?.[aliasKey] ?? []) {
      canonicals.add(resolved);
    }
  }
  const expanded = /* @__PURE__ */ new Set();
  for (const canonical of canonicals) {
    expanded.add(canonical);
    const node = index.tags[canonical];
    if (node && !Array.isArray(node)) {
      for (const parent of node.parents ?? []) {
        expanded.add(parent);
      }
    }
  }
  return Array.from(expanded);
}
function aliasPhrase(alias) {
  return alias.replace(/\//g, " ").replace(/-/g, " ").replace(/\s+/g, " ").trim();
}
function promptContainsAlias(prompt, alias) {
  const phrase = aliasPhrase(alias);
  if (!phrase) return false;
  const normalizedPrompt = ` ${normalizeAliasKey(prompt)} `;
  return normalizedPrompt.includes(` ${phrase} `);
}
function indexMemory(memoryDir, memoryPath, createdAt, tags) {
  try {
    ensureStateDir(memoryDir);
    const tPath = temporalIndexPath(memoryDir);
    const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
    const dateKey = isoDateFromTimestamp(createdAt);
    addPathToSet(tIndex.dates, dateKey, memoryPath);
    writeJsonAtomic(tPath, tIndex);
    const gPath = tagIndexPath(memoryDir);
    const gIndex = normalizeTagIndex(readJsonSafe(gPath, { version: TAG_INDEX_VERSION, tags: {}, aliases: {} }));
    for (const tag of tags) {
      if (tag && typeof tag === "string") {
        addTagGraphEntry(gIndex, tag, memoryPath);
      }
    }
    writeJsonAtomic(gPath, gIndex);
  } catch {
  }
}
function deindexMemory(memoryDir, memoryPath, createdAt, tags) {
  try {
    ensureStateDir(memoryDir);
    const tPath = temporalIndexPath(memoryDir);
    const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
    const dateKey = isoDateFromTimestamp(createdAt);
    removePathFromSet(tIndex.dates, dateKey, memoryPath);
    writeJsonAtomic(tPath, tIndex);
    const gPath = tagIndexPath(memoryDir);
    const gIndex = normalizeTagIndex(readJsonSafe(gPath, { version: TAG_INDEX_VERSION, tags: {}, aliases: {} }));
    for (const tag of tags) {
      if (tag && typeof tag === "string") {
        removeTagGraphEntry(gIndex, tag, memoryPath);
      }
    }
    writeJsonAtomic(gPath, gIndex);
  } catch {
  }
}
function clearIndexes(memoryDir) {
  try {
    ensureStateDir(memoryDir);
    writeJsonAtomic(temporalIndexPath(memoryDir), { version: INDEX_VERSION, dates: {} });
    writeJsonAtomic(tagIndexPath(memoryDir), { version: TAG_INDEX_VERSION, tags: {}, aliases: {} });
  } catch {
  }
}
function indexesExist(memoryDir) {
  try {
    return fs.existsSync(temporalIndexPath(memoryDir)) && fs.existsSync(tagIndexPath(memoryDir));
  } catch {
    return false;
  }
}
function indexMemoriesBatch(memoryDir, entries) {
  if (entries.length === 0) return;
  try {
    ensureStateDir(memoryDir);
    const tPath = temporalIndexPath(memoryDir);
    const tIndex = readJsonSafe(tPath, { version: INDEX_VERSION, dates: {} });
    const gPath = tagIndexPath(memoryDir);
    const gIndex = normalizeTagIndex(readJsonSafe(gPath, { version: TAG_INDEX_VERSION, tags: {}, aliases: {} }));
    for (const entry of entries) {
      const dateKey = isoDateFromTimestamp(entry.createdAt);
      addPathToSet(tIndex.dates, dateKey, entry.path);
      for (const tag of entry.tags) {
        if (tag && typeof tag === "string") {
          addTagGraphEntry(gIndex, tag, entry.path);
        }
      }
    }
    writeJsonAtomic(tPath, tIndex);
    writeJsonAtomic(gPath, gIndex);
  } catch {
  }
}
async function queryByDateRangeAsync(memoryDir, fromDate, toDate) {
  try {
    const tPath = temporalIndexPath(memoryDir);
    let raw;
    try {
      raw = await fs.promises.readFile(tPath, "utf8");
    } catch {
      return null;
    }
    let tIndex;
    try {
      tIndex = JSON.parse(raw);
    } catch {
      tIndex = { version: INDEX_VERSION, dates: {} };
    }
    const end = toDate ?? new Date(Date.now() + 864e5).toISOString().slice(0, 10);
    const results = /* @__PURE__ */ new Set();
    for (const [date, paths] of Object.entries(tIndex.dates)) {
      if (date >= fromDate && date < end) {
        for (const p of paths) {
          results.add(p);
        }
      }
    }
    return results;
  } catch {
    return null;
  }
}
async function queryByTagsAsync(memoryDir, tags) {
  if (tags.length === 0) return null;
  try {
    const gPath = tagIndexPath(memoryDir);
    let raw;
    try {
      raw = await fs.promises.readFile(gPath, "utf8");
    } catch {
      return null;
    }
    let gIndex;
    try {
      gIndex = normalizeTagIndex(JSON.parse(raw));
    } catch {
      gIndex = { version: TAG_INDEX_VERSION, tags: {}, aliases: {} };
    }
    return queryByTagsFromIndex(gIndex, tags);
  } catch {
    return null;
  }
}
function queryByTagsFromIndex(index, tags) {
  const expandedTags = expandCanonicalTags(index, tags);
  const results = /* @__PURE__ */ new Set();
  for (const canonical of expandedTags) {
    const nodeOrPaths = index.tags[canonical];
    const paths = Array.isArray(nodeOrPaths) ? nodeOrPaths : nodeOrPaths?.paths ?? [];
    for (const pathValue of paths) {
      results.add(pathValue);
    }
  }
  return results.size > 0 ? results : null;
}
function extractTagsFromPrompt(prompt) {
  const found = /* @__PURE__ */ new Set();
  const hashMatches = prompt.matchAll(/#([a-zA-Z][\w-]{1,30})/g);
  for (const m of hashMatches) {
    const canonical = normalizeCanonicalTag(m[1]);
    if (canonical) found.add(canonical);
  }
  return Array.from(found);
}
async function resolvePromptTagPrefilterAsync(memoryDir, prompt) {
  const explicitTags = extractTagsFromPrompt(prompt);
  try {
    const raw = await fs.promises.readFile(tagIndexPath(memoryDir), "utf8");
    const tagIndex = normalizeTagIndex(JSON.parse(raw));
    const matched = new Set(explicitTags);
    for (const canonical of Object.keys(tagIndex.tags)) {
      if (promptContainsAlias(prompt, canonical)) {
        matched.add(canonical);
      }
    }
    for (const [alias, canonicals] of Object.entries(tagIndex.aliases ?? {})) {
      if (!promptContainsAlias(prompt, alias)) continue;
      for (const canonical of canonicals) {
        matched.add(canonical);
      }
    }
    const expandedTags = expandCanonicalTags(tagIndex, Array.from(matched));
    const paths = queryByTagsFromIndex(tagIndex, expandedTags);
    return {
      matchedTags: Array.from(matched),
      expandedTags,
      paths
    };
  } catch {
    return { matchedTags: explicitTags, expandedTags: explicitTags, paths: null };
  }
}
function isTemporalQuery(prompt) {
  return /\b(today|yesterday|this week|last week|this month|last month|recent(?:ly)?|lately|just now|earlier today|this morning|last night|last year|this year|\d+ days? ago|\d+ hours? ago|\d+ weeks? ago|\d+ months? ago|(?:in |on |during |since |before |after )?(?:january|february|march|april|may|june|july|august|september|october|november|december)(?:\s+\d{1,4})?|\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{2,4}|(?:spring|summer|fall|autumn|winter)\s+\d{4}|on the \d{1,2}(?:st|nd|rd|th)?|last (?:monday|tuesday|wednesday|thursday|friday|saturday|sunday))\b/i.test(
    prompt
  );
}
function recencyWindowFromPrompt(prompt, nowMs = Date.now()) {
  const p = prompt.toLowerCase();
  const now = new Date(nowMs);
  let daysBack = 7;
  if (/\btoday\b/.test(p) || /\bthis morning\b/.test(p) || /\bjust now\b/.test(p) || /\bearlier today\b/.test(p)) {
    daysBack = 0;
  } else if (/\byesterday\b/.test(p) || /\blast night\b/.test(p)) {
    daysBack = 1;
  } else if (/\bthis week\b/.test(p)) {
    daysBack = 7;
  } else if (/\blast week\b/.test(p)) {
    daysBack = 14;
  } else if (/\bthis month\b/.test(p)) {
    daysBack = 31;
  } else if (/\blast month\b/.test(p)) {
    daysBack = 62;
  } else if (/\bthis year\b/.test(p)) {
    const jan1 = new Date(now.getFullYear(), 0, 1);
    return jan1.toISOString().slice(0, 10);
  } else if (/\blast year\b/.test(p)) {
    const jan1LastYear = new Date(now.getFullYear() - 1, 0, 1);
    return jan1LastYear.toISOString().slice(0, 10);
  } else {
    const monthNames = [
      "january",
      "february",
      "march",
      "april",
      "may",
      "june",
      "july",
      "august",
      "september",
      "october",
      "november",
      "december"
    ];
    const monthMatch = p.match(/\b(january|february|march|april|may|june|july|august|september|october|november|december)(?:\s+(\d{4}))?\b/);
    if (monthMatch) {
      const monthIdx = monthNames.indexOf(monthMatch[1]);
      const year = monthMatch[2] ? parseInt(monthMatch[2], 10) : now.getFullYear();
      if (/\bbefore\b/.test(p)) {
        if (monthMatch[2]) {
          const monthStart = new Date(year, monthIdx, 1);
          return new Date(monthStart.getTime() - 730 * 864e5).toISOString().slice(0, 10);
        }
        daysBack = 730;
      } else {
        const monthStart = new Date(year, monthIdx, 1);
        return monthStart.toISOString().slice(0, 10);
      }
    }
    const weekMatch = p.match(/(\d{1,5})\s*weeks?\s*ago/);
    if (weekMatch) {
      daysBack = Math.min(365, parseInt(weekMatch[1], 10) * 7);
    } else {
      const monthsAgoMatch = p.match(/(\d{1,5})\s*months?\s*ago/);
      if (monthsAgoMatch) {
        daysBack = Math.min(730, parseInt(monthsAgoMatch[1], 10) * 31);
      } else {
        const numMatch = p.match(/(\d{1,5})\s*days?\s*ago/);
        if (numMatch) {
          daysBack = Math.min(365, parseInt(numMatch[1], 10));
        } else {
          const hrMatch = p.match(/(\d{1,5})\s*hours?\s*ago/);
          if (hrMatch) {
            daysBack = Math.max(1, Math.ceil(parseInt(hrMatch[1], 10) / 24));
          }
        }
      }
    }
    const isoMatch = p.match(/(\d{4})-(\d{2})-(\d{2})/);
    if (isoMatch) {
      return `${isoMatch[1]}-${isoMatch[2]}-${isoMatch[3]}`;
    }
    const usMatch = p.match(/(\d{1,2})\/(\d{1,2})\/(\d{2,4})/);
    if (usMatch) {
      const year = usMatch[3].length === 2 ? 2e3 + parseInt(usMatch[3], 10) : parseInt(usMatch[3], 10);
      return `${year}-${usMatch[1].padStart(2, "0")}-${usMatch[2].padStart(2, "0")}`;
    }
    const dayOfWeekMatch = p.match(/\blast\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/);
    if (dayOfWeekMatch) {
      const dayNames = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
      const targetDay = dayNames.indexOf(dayOfWeekMatch[1]);
      const currentDay = now.getDay();
      daysBack = (currentDay - targetDay + 7) % 7 || 7;
    }
  }
  const from = new Date(nowMs - daysBack * 24 * 60 * 60 * 1e3);
  return from.toISOString().slice(0, 10);
}
function recencyWindowBoundsFromPrompt(prompt, nowMs = Date.now()) {
  const fromDate = recencyWindowFromPrompt(prompt, nowMs);
  const p = prompt.toLowerCase();
  const now = new Date(nowMs);
  const today = now.toISOString().slice(0, 10);
  const tomorrow = new Date(nowMs + 864e5).toISOString().slice(0, 10);
  let toDate;
  if (/\btoday\b|\bthis morning\b|\bjust now\b|\bearlier today\b/.test(p)) {
    toDate = tomorrow;
  } else if (/\byesterday\b|\blast night\b/.test(p)) {
    toDate = today;
  } else if (/\bthis week\b|\bthis month\b|\bthis year\b/.test(p)) {
    toDate = tomorrow;
  } else if (/\blast week\b/.test(p)) {
    toDate = new Date(nowMs - 7 * 864e5).toISOString().slice(0, 10);
  } else if (/\blast month\b/.test(p)) {
    toDate = new Date(nowMs - 31 * 864e5).toISOString().slice(0, 10);
  } else if (/\blast year\b/.test(p)) {
    toDate = `${now.getFullYear()}-01-01`;
  } else {
    const monthNames = [
      "january",
      "february",
      "march",
      "april",
      "may",
      "june",
      "july",
      "august",
      "september",
      "october",
      "november",
      "december"
    ];
    const monthMatch = p.match(/\b(january|february|march|april|may|june|july|august|september|october|november|december)(?:\s+(\d{4}))?\b/);
    if (monthMatch) {
      const monthIdx = monthNames.indexOf(monthMatch[1]);
      const year = monthMatch[2] ? parseInt(monthMatch[2], 10) : now.getFullYear();
      const isSinceOrAfter = /\b(since|after)\b/.test(p);
      const isBefore = /\bbefore\b/.test(p);
      if (isSinceOrAfter) {
        toDate = tomorrow;
      } else if (isBefore) {
        toDate = new Date(year, monthIdx, 1).toISOString().slice(0, 10);
      } else {
        toDate = new Date(year, monthIdx + 1, 1).toISOString().slice(0, 10);
      }
    } else {
      let toDaysBack = -1;
      const weekMatch = p.match(/(\d{1,5})\s*weeks?\s*ago/);
      if (weekMatch) {
        toDaysBack = Math.max(0, Math.min(52, parseInt(weekMatch[1], 10)) - 1) * 7;
      } else {
        const monthsAgoMatch = p.match(/(\d{1,5})\s*months?\s*ago/);
        if (monthsAgoMatch) {
          toDaysBack = Math.max(0, Math.min(24, parseInt(monthsAgoMatch[1], 10)) - 1) * 31;
        } else {
          const numMatch = p.match(/(\d{1,5})\s*days?\s*ago/);
          if (numMatch) {
            toDaysBack = Math.max(0, Math.min(365, parseInt(numMatch[1], 10)) - 1);
          } else {
            const hrMatch = p.match(/(\d{1,5})\s*hours?\s*ago/);
            if (hrMatch) {
              toDaysBack = -1;
            }
          }
        }
      }
      const isoMatch = p.match(/(\d{4})-(\d{2})-(\d{2})/);
      if (isoMatch) {
        const d = /* @__PURE__ */ new Date(`${isoMatch[1]}-${isoMatch[2]}-${isoMatch[3]}T00:00:00Z`);
        toDate = new Date(d.getTime() + 864e5).toISOString().slice(0, 10);
      } else {
        const usMatch = p.match(/(\d{1,2})\/(\d{1,2})\/(\d{2,4})/);
        if (usMatch) {
          const year = usMatch[3].length === 2 ? 2e3 + parseInt(usMatch[3], 10) : parseInt(usMatch[3], 10);
          const d = /* @__PURE__ */ new Date(`${year}-${usMatch[1].padStart(2, "0")}-${usMatch[2].padStart(2, "0")}T00:00:00Z`);
          toDate = new Date(d.getTime() + 864e5).toISOString().slice(0, 10);
        } else {
          const dayOfWeekMatch = p.match(/\blast\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/);
          if (dayOfWeekMatch) {
            const dayNames = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
            const targetDay = dayNames.indexOf(dayOfWeekMatch[1]);
            const currentDay = now.getDay();
            const daysBack = (currentDay - targetDay + 7) % 7 || 7;
            toDate = new Date(nowMs - (daysBack - 1) * 864e5).toISOString().slice(0, 10);
          } else {
            toDate = toDaysBack < 0 ? tomorrow : new Date(nowMs - toDaysBack * 864e5).toISOString().slice(0, 10);
          }
        }
      }
    }
  }
  if (toDate <= fromDate) toDate = tomorrow;
  return { fromDate, toDate };
}

export {
  indexMemory,
  deindexMemory,
  clearIndexes,
  indexesExist,
  indexMemoriesBatch,
  queryByDateRangeAsync,
  queryByTagsAsync,
  extractTagsFromPrompt,
  resolvePromptTagPrefilterAsync,
  isTemporalQuery,
  recencyWindowFromPrompt,
  recencyWindowBoundsFromPrompt
};
//# sourceMappingURL=chunk-V3RXWQIE.js.map