// Force strict mode and setup for ESM
"use strict";
import {
  msSinceLastInteraction
} from "./chunk-MRO43B25.js";
import {
  FILE_HISTORY_DIR
} from "./chunk-BUOJN3MM.js";
import "./chunk-K5PGHDBN.js";
import "./chunk-O4PICXES.js";
import "./chunk-TW522KN6.js";
import "./chunk-MLZQVCF3.js";
import "./chunk-SCHRFI7O.js";
import "./chunk-PLYZAP4W.js";
import "./chunk-UABFCMPA.js";
import "./chunk-77WXWU44.js";
import "./chunk-6VFG3EUJ.js";
import "./chunk-3H7ENG2Q.js";
import "./chunk-3PJXIDKI.js";
import "./chunk-UWCTAVOD.js";
import "./chunk-OFEVLU4C.js";
import "./chunk-AVLOK27J.js";
import "./chunk-JSYEZAYV.js";
import "./chunk-5RNZ2QKF.js";
import "./chunk-G763GDO6.js";
import "./chunk-JMLIPZUU.js";
import "./chunk-GBEPNWYB.js";
import "./chunk-F5ORN4YO.js";
import "./chunk-MVX64PNU.js";
import "./chunk-D46KOV3C.js";
import "./chunk-BNESGOSJ.js";
import "./chunk-SZOEIL6S.js";
import "./chunk-5IFG2VC4.js";
import {
  Storage,
  createDebugLogger
} from "./chunk-R5PDRHEF.js";
import "./chunk-ZERZSAZL.js";
import "./chunk-QN5NZ3UQ.js";
import "./chunk-BR4QREVK.js";
import "./chunk-WFVXF3OM.js";
import {
  init_esbuild_shims
} from "./chunk-A4BMJM77.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/utils/housekeeping/scheduler.ts
init_esbuild_shims();
import { stat as stat3 } from "node:fs/promises";
import { join as join2 } from "node:path";

// packages/cli/src/utils/housekeeping/cleanup.ts
init_esbuild_shims();
import { readdir, stat, rm, rmdir } from "node:fs/promises";
import { join } from "node:path";
var debugLogger = createDebugLogger("HOUSEKEEPING");
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
var MS_PER_HOUR = 60 * 60 * 1e3;
var SWEEP_CONCURRENCY = 20;
function getCutoffDate(cleanupPeriodDays) {
  const periodMs = cleanupPeriodDays > 0 ? cleanupPeriodDays * MS_PER_DAY : MS_PER_HOUR;
  return new Date(Date.now() - periodMs);
}
__name(getCutoffDate, "getCutoffDate");
async function cleanupOldFileHistoryBackups(opts) {
  const result = { removed: 0, errors: 0 };
  const root = join(Storage.getGlobalQwenDir(), FILE_HISTORY_DIR);
  const excludes = opts.excludeSessionIds ?? /* @__PURE__ */ new Set();
  let entries;
  try {
    entries = await readdir(root, { withFileTypes: true });
  } catch (e) {
    if (isENOENT(e)) return result;
    debugLogger.error("readdir failed", e);
    return result;
  }
  const sessionDirs = entries.filter((e) => e.isDirectory() && !excludes.has(e.name)).map((e) => join(root, e.name));
  for (let i = 0; i < sessionDirs.length; i += SWEEP_CONCURRENCY) {
    const batch = sessionDirs.slice(i, i + SWEEP_CONCURRENCY);
    await Promise.all(
      batch.map(async (dir) => {
        try {
          const s = await stat(dir);
          if (s.mtime < opts.cutoffDate) {
            await rm(dir, { recursive: true, force: true });
            result.removed++;
          }
        } catch (err) {
          result.errors++;
          debugLogger.error(`failed to sweep ${dir}`, err);
        }
      })
    );
  }
  await rmdir(root).catch(() => {
  });
  return result;
}
__name(cleanupOldFileHistoryBackups, "cleanupOldFileHistoryBackups");
function isENOENT(e) {
  return e?.code === "ENOENT";
}
__name(isENOENT, "isENOENT");

// packages/cli/src/utils/housekeeping/throttledOnce.ts
init_esbuild_shims();
import { mkdir, open, stat as stat2, unlink, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
var debugLogger2 = createDebugLogger("HOUSEKEEPING");
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
var STALE_LOCK_MS = 60 * 60 * 1e3;
async function runThrottledOnce(opts, task) {
  const minIntervalMs = opts.minIntervalMs ?? ONE_DAY_MS;
  const staleLockMs = opts.staleLockMs ?? STALE_LOCK_MS;
  await mkdir(dirname(opts.lockPath), { recursive: true, mode: 448 }).catch(
    () => {
    }
  );
  if (await markerIsFresh(opts.markerPath, minIntervalMs, opts.name)) {
    return false;
  }
  let acquired = await tryAcquire(opts.lockPath);
  if (!acquired) {
    try {
      const s = await stat2(opts.lockPath);
      if (Date.now() - s.mtimeMs > staleLockMs) {
        await unlink(opts.lockPath).catch(() => {
        });
        acquired = await tryAcquire(opts.lockPath);
      }
    } catch {
      acquired = await tryAcquire(opts.lockPath);
    }
    if (!acquired) {
      debugLogger2.debug(`${opts.name}: skipping, lock held`);
      return false;
    }
  }
  try {
    if (await markerIsFresh(opts.markerPath, minIntervalMs, opts.name)) {
      return false;
    }
    let taskCompleted = false;
    try {
      await task();
      taskCompleted = true;
    } finally {
      if (taskCompleted) {
        try {
          await writeFile(opts.markerPath, (/* @__PURE__ */ new Date()).toISOString());
        } catch (err) {
          debugLogger2.debug(
            `${opts.name}: marker write failed (cleanup succeeded)`,
            err
          );
        }
      }
    }
    return taskCompleted;
  } finally {
    await unlink(opts.lockPath).catch(() => {
      debugLogger2.debug(`${opts.name}: lock unlink failed (harmless)`);
    });
  }
}
__name(runThrottledOnce, "runThrottledOnce");
async function markerIsFresh(markerPath, minIntervalMs, name) {
  try {
    const s = await stat2(markerPath);
    const age = Date.now() - s.mtimeMs;
    if (age < minIntervalMs) {
      debugLogger2.debug(`${name}: skipping, ran ${age}ms ago`);
      return true;
    }
  } catch {
  }
  return false;
}
__name(markerIsFresh, "markerIsFresh");
async function tryAcquire(lockPath) {
  try {
    const fh = await open(lockPath, "wx");
    await fh.close();
    return true;
  } catch (e) {
    if (e?.code === "EEXIST") {
      return false;
    }
    throw e;
  }
}
__name(tryAcquire, "tryAcquire");

// packages/cli/src/utils/housekeeping/scheduler.ts
var debugLogger3 = createDebugLogger("HOUSEKEEPING");
var STARTUP_DELAY_MS = 10 * 60 * 1e3;
var RECURRING_INTERVAL_MS = 24 * 60 * 60 * 1e3;
var RECENT_INTERACTION_MS = 60 * 1e3;
var CATCHUP_THRESHOLD_MS = 7 * 24 * 60 * 60 * 1e3;
var STARTUP_DELAY_CATCHUP_MS = 60 * 1e3;
var FILE_HISTORY_MARKER = ".file-history-cleanup";
var started = false;
function startBackgroundHousekeeping(config, settings) {
  if (started) return;
  started = true;
  void scheduleFirstPass(config, settings).catch((err) => {
    started = false;
    debugLogger3.error(
      "scheduleFirstPass failed; chain will retry on next start",
      err
    );
  });
}
__name(startBackgroundHousekeeping, "startBackgroundHousekeeping");
async function scheduleFirstPass(config, settings) {
  const markerPath = join2(Storage.getGlobalQwenDir(), FILE_HISTORY_MARKER);
  const delay = await needsCatchUp(markerPath) ? STARTUP_DELAY_CATCHUP_MS : STARTUP_DELAY_MS;
  debugLogger3.debug(`first pass in ${delay / 1e3}s`);
  setTimeout(() => scheduleNextPass(config, settings), delay).unref();
}
__name(scheduleFirstPass, "scheduleFirstPass");
async function needsCatchUp(markerPath) {
  try {
    const s = await stat3(markerPath);
    return Date.now() - s.mtimeMs > CATCHUP_THRESHOLD_MS;
  } catch {
    return true;
  }
}
__name(needsCatchUp, "needsCatchUp");
async function runPass(config, settings) {
  if (msSinceLastInteraction() < RECENT_INTERACTION_MS) {
    debugLogger3.debug("user active, deferring 10 min");
    setTimeout(
      () => scheduleNextPass(config, settings),
      STARTUP_DELAY_MS
    ).unref();
    return;
  }
  try {
    await runHousekeeping(config, settings);
  } catch (err) {
    debugLogger3.error("housekeeping pass failed; will retry next cycle", err);
  }
  setTimeout(
    () => scheduleNextPass(config, settings),
    RECURRING_INTERVAL_MS
  ).unref();
}
__name(runPass, "runPass");
function scheduleNextPass(config, settings) {
  void runPass(config, settings).catch((err) => {
    debugLogger3.error("runPass rejected unexpectedly", err);
  });
}
__name(scheduleNextPass, "scheduleNextPass");
async function runHousekeeping(config, settings) {
  const days = settings.merged.general?.cleanupPeriodDays ?? 30;
  const cutoff = getCutoffDate(days);
  const currentSessionId = config.getSessionId();
  const qwenDir = Storage.getGlobalQwenDir();
  await runThrottledOnce(
    {
      name: "file-history-cleanup",
      markerPath: join2(qwenDir, FILE_HISTORY_MARKER),
      lockPath: join2(qwenDir, FILE_HISTORY_MARKER + ".lock")
    },
    async () => {
      const r = await cleanupOldFileHistoryBackups({
        cutoffDate: cutoff,
        excludeSessionIds: /* @__PURE__ */ new Set([currentSessionId])
      });
      debugLogger3.debug(
        `file-history: removed=${r.removed} errors=${r.errors}`
      );
    }
  );
}
__name(runHousekeeping, "runHousekeeping");
function _resetForTesting() {
  started = false;
}
__name(_resetForTesting, "_resetForTesting");
var _needsCatchUpForTesting = needsCatchUp;
var _runHousekeepingForTesting = runHousekeeping;
var _runPassForTesting = runPass;
var _FILE_HISTORY_MARKER_FOR_TESTING = FILE_HISTORY_MARKER;
export {
  _FILE_HISTORY_MARKER_FOR_TESTING,
  _needsCatchUpForTesting,
  _resetForTesting,
  _runHousekeepingForTesting,
  _runPassForTesting,
  startBackgroundHousekeeping
};
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
