import {
  applyUtilityPromotionRuntimePolicy,
  loadUtilityRuntimeValues
} from "./chunk-FSFEQI74.js";
import {
  TierMigrationExecutor
} from "./chunk-Z5AAYHUC.js";
import {
  decideTierTransition
} from "./chunk-S75M5ZRK.js";
import "./chunk-PYXS46O7.js";
import "./chunk-3QKK7QOS.js";
import "./chunk-TBBDFYXW.js";
import "./chunk-DGXUHMOV.js";
import "./chunk-LPSF4OQH.js";
import "./chunk-PZ5AY32C.js";

// src/maintenance/first-start-migration.ts
import path from "path";
import { access, mkdir, readFile, unlink, writeFile } from "fs/promises";
var FIRST_START_DEMOTION_CAP = 50;
var LIFECYCLE_INIT_DONE_MARKER = ".lifecycle-init-done";
var LIFECYCLE_QMD_REFRESH_PENDING_MARKER = ".lifecycle-qmd-refresh-pending";
function markerPath(memoryDir) {
  return path.join(memoryDir, "state", LIFECYCLE_INIT_DONE_MARKER);
}
function qmdRefreshPendingPath(memoryDir) {
  return path.join(memoryDir, "state", LIFECYCLE_QMD_REFRESH_PENDING_MARKER);
}
async function markerExists(memoryDir) {
  try {
    await access(markerPath(memoryDir));
    return true;
  } catch {
    return false;
  }
}
async function writeMarker(memoryDir, now) {
  const p = markerPath(memoryDir);
  await mkdir(path.dirname(p), { recursive: true });
  await writeFile(p, JSON.stringify({ createdAt: now.toISOString() }), "utf-8");
}
async function readQmdRefreshPending(memoryDir) {
  try {
    const raw = await readFile(qmdRefreshPendingPath(memoryDir), "utf-8");
    const parsed = JSON.parse(raw);
    if (parsed && typeof parsed === "object" && typeof parsed.createdAt === "string" && typeof parsed.collection === "string" && parsed.collection.length > 0) {
      return parsed;
    }
    return null;
  } catch {
    return null;
  }
}
async function pathExists(p) {
  try {
    await access(p);
    return true;
  } catch {
    return false;
  }
}
async function writeQmdRefreshPending(memoryDir, now, collection) {
  const p = qmdRefreshPendingPath(memoryDir);
  await mkdir(path.dirname(p), { recursive: true });
  await writeFile(p, JSON.stringify({ createdAt: now.toISOString(), collection }), "utf-8");
}
async function clearQmdRefreshPending(memoryDir) {
  await unlink(qmdRefreshPendingPath(memoryDir)).catch(() => {
  });
}
async function buildTierRoutingPolicy(config) {
  const basePolicy = {
    enabled: config.qmdTierMigrationEnabled,
    demotionMinAgeDays: config.qmdTierDemotionMinAgeDays,
    demotionValueThreshold: config.qmdTierDemotionValueThreshold,
    promotionValueThreshold: config.qmdTierPromotionValueThreshold
  };
  const runtime = await loadUtilityRuntimeValues({
    memoryDir: config.memoryDir,
    memoryUtilityLearningEnabled: config.memoryUtilityLearningEnabled,
    promotionByOutcomeEnabled: config.promotionByOutcomeEnabled
  });
  return applyUtilityPromotionRuntimePolicy(basePolicy, runtime);
}
async function refreshQmdCollection(qmd, collection, signal) {
  if (typeof qmd.updateCollectionStrict === "function") {
    await qmd.updateCollectionStrict(collection, { signal });
    return;
  }
  await qmd.updateCollection(collection, { signal });
}
async function runFirstStartMigration(options) {
  const {
    storage,
    config,
    demotionCap = FIRST_START_DEMOTION_CAP,
    dryRun = false,
    qmd,
    signal
  } = options;
  const now = (options.now ?? (() => /* @__PURE__ */ new Date()))();
  const abortedResult = (candidateCount2 = 0, demotedCount2 = 0, failureCount2 = 0) => ({
    skipped: candidateCount2 === 0 && demotedCount2 === 0 && failureCount2 === 0,
    skipReason: candidateCount2 === 0 && demotedCount2 === 0 && failureCount2 === 0 ? "aborted" : void 0,
    dryRun,
    candidateCount: candidateCount2,
    demotedCount: demotedCount2,
    failureCount: failureCount2,
    cappedAt: demotionCap
  });
  if (signal?.aborted) {
    return abortedResult();
  }
  if (!config.lifecyclePolicyEnabled) {
    return {
      skipped: true,
      skipReason: "lifecyclePolicyEnabled is false",
      dryRun,
      candidateCount: 0,
      demotedCount: 0,
      failureCount: 0,
      cappedAt: demotionCap
    };
  }
  if (!config.qmdTierMigrationEnabled) {
    return {
      skipped: true,
      skipReason: "qmdTierMigrationEnabled is false",
      dryRun,
      candidateCount: 0,
      demotedCount: 0,
      failureCount: 0,
      cappedAt: demotionCap
    };
  }
  if (await markerExists(config.memoryDir)) {
    return {
      skipped: true,
      skipReason: "lifecycle-init-done marker already present",
      dryRun,
      candidateCount: 0,
      demotedCount: 0,
      failureCount: 0,
      cappedAt: demotionCap
    };
  }
  if (signal?.aborted) {
    return abortedResult();
  }
  const policy = await buildTierRoutingPolicy(config);
  if (signal?.aborted) {
    return abortedResult();
  }
  const hotMemories = await storage.readAllMemories();
  if (signal?.aborted) {
    return abortedResult();
  }
  const demotionCandidates = hotMemories.filter((m) => {
    const decision = decideTierTransition(m, "hot", policy, now);
    return decision.changed && decision.nextTier === "cold";
  });
  const candidateCount = demotionCandidates.length;
  const batch = demotionCandidates.slice(0, demotionCap);
  if (dryRun) {
    return {
      skipped: false,
      dryRun: true,
      candidateCount,
      demotedCount: 0,
      failureCount: 0,
      cappedAt: demotionCap
    };
  }
  let demotedCount = 0;
  let failureCount = 0;
  let qmdRefreshPendingForRun = false;
  const executor = qmd ? new TierMigrationExecutor({
    storage,
    qmd,
    hotCollection: options.hotCollection ?? config.qmdCollection ?? "openclaw-engram",
    coldCollection: options.coldCollection ?? config.qmdColdCollection ?? "openclaw-engram-cold"
  }) : null;
  const coldCollection = options.coldCollection ?? config.qmdColdCollection ?? "openclaw-engram-cold";
  for (const memory of batch) {
    if (signal?.aborted) {
      return abortedResult(candidateCount, demotedCount, failureCount);
    }
    try {
      if (executor) {
        await executor.migrateMemory({
          memory,
          fromTier: "hot",
          toTier: "cold",
          reason: "first-start-lifecycle-migration"
        });
      } else {
        await storage.migrateMemoryToTier(memory, "cold");
      }
      demotedCount += 1;
    } catch {
      const targetPath = storage.buildTierMemoryPath(memory, "cold");
      const [targetExists, sourceExists] = await Promise.all([
        pathExists(targetPath),
        pathExists(memory.path)
      ]);
      const movedToCold = targetExists && !sourceExists;
      if (movedToCold) {
        if (!qmd) {
          demotedCount += 1;
          continue;
        }
        try {
          await refreshQmdCollection(qmd, coldCollection, signal);
          demotedCount += 1;
          continue;
        } catch {
          qmdRefreshPendingForRun = true;
          try {
            await writeQmdRefreshPending(config.memoryDir, now, coldCollection);
          } catch {
          }
          demotedCount += 1;
          continue;
        }
      }
      failureCount += 1;
    }
  }
  if (signal?.aborted) {
    return abortedResult(candidateCount, demotedCount, failureCount);
  }
  const persistedQmdRefreshPending = qmd ? await readQmdRefreshPending(config.memoryDir) : null;
  const hasPersistedQmdRefreshPending = persistedQmdRefreshPending?.collection === coldCollection;
  if (qmd && persistedQmdRefreshPending && persistedQmdRefreshPending.collection !== coldCollection) {
    failureCount += 1;
  }
  if (qmd && (qmdRefreshPendingForRun || hasPersistedQmdRefreshPending)) {
    try {
      await refreshQmdCollection(qmd, coldCollection, signal);
      await clearQmdRefreshPending(config.memoryDir);
    } catch {
      failureCount += 1;
    }
  }
  if (failureCount === 0) {
    await writeMarker(config.memoryDir, now);
  }
  return {
    skipped: false,
    dryRun: false,
    candidateCount,
    demotedCount,
    failureCount,
    cappedAt: demotionCap
  };
}
export {
  FIRST_START_DEMOTION_CAP,
  LIFECYCLE_INIT_DONE_MARKER,
  runFirstStartMigration
};
//# sourceMappingURL=first-start-migration-4MHQEOSD.js.map