// Force strict mode and setup for ESM
"use strict";
import {
  msSinceLastInteraction
} from "./chunk-KW7NOTN6.js";
import {
  FILE_HISTORY_DIR,
  getSubagentsRootDir
} from "./chunk-KN5EBZLT.js";
import "./chunk-T4TZQJ7W.js";
import "./chunk-H6XPXXMH.js";
import "./chunk-5M6IDOMF.js";
import "./chunk-A2HWMJVO.js";
import "./chunk-RCEEXIOO.js";
import "./chunk-KKRTYONM.js";
import "./chunk-TV6K2FB4.js";
import "./chunk-E2UVIFI2.js";
import "./chunk-XU457J4V.js";
import "./chunk-VDDGDZMA.js";
import "./chunk-SPJQO2CE.js";
import "./chunk-SZRN75WQ.js";
import "./chunk-HTO4JFDZ.js";
import "./chunk-CPBF7KYF.js";
import "./chunk-F333XEAU.js";
import "./chunk-6AM5D4ME.js";
import "./chunk-2Z5UX4KI.js";
import "./chunk-ARKANCNX.js";
import "./chunk-L5U3ELZX.js";
import "./chunk-TYLOFD2U.js";
import "./chunk-D5K5YBSN.js";
import "./chunk-4WKAA4KS.js";
import "./chunk-CR3C7WXL.js";
import "./chunk-RTV5TUYB.js";
import "./chunk-VGC4I5JJ.js";
import "./chunk-FBU7WRZI.js";
import "./chunk-Y66VOBRP.js";
import "./chunk-WTNZ6DXB.js";
import "./chunk-JGUT3LWZ.js";
import "./chunk-OKAIGAYW.js";
import "./chunk-ZPAHLFZU.js";
import "./chunk-JESCGQM3.js";
import "./chunk-WIEO4CWB.js";
import "./chunk-XVNQMZ2I.js";
import "./chunk-FEOZBUMT.js";
import "./chunk-VRR65QYW.js";
import "./chunk-A4UCTEB5.js";
import "./chunk-XWRJCPHC.js";
import "./chunk-4LD5APFL.js";
import "./chunk-TYAMGABM.js";
import "./chunk-FCMNKVXT.js";
import "./chunk-DJ2GSRLV.js";
import "./chunk-LQIDP6K5.js";
import {
  Storage,
  createDebugLogger
} from "./chunk-7NFB7LBQ.js";
import "./chunk-75DOP5OR.js";
import "./chunk-DMTGGOSA.js";
import "./chunk-YQ3U5MUC.js";
import "./chunk-TB6UDU4T.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.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 { createHash } from "node:crypto";
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 sweepOldSessionDirs(root, opts) {
  const result = { removed: 0, errors: 0 };
  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);
        }
      })
    );
  }
  if (opts.removeEmptyRoot !== false) {
    await rmdir(root).catch(() => {
    });
  }
  return result;
}
__name(sweepOldSessionDirs, "sweepOldSessionDirs");
async function cleanupOldFileHistoryBackups(opts) {
  return sweepOldSessionDirs(
    join(Storage.getGlobalQwenDir(), FILE_HISTORY_DIR),
    opts
  );
}
__name(cleanupOldFileHistoryBackups, "cleanupOldFileHistoryBackups");
async function cleanupOldSubagentTranscripts(opts) {
  return sweepOldSessionDirs(opts.subagentsRoot, {
    ...opts,
    removeEmptyRoot: false
  });
}
__name(cleanupOldSubagentTranscripts, "cleanupOldSubagentTranscripts");
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 SUBAGENT_MARKER = ".subagent-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");
function getSubagentMarkerPath(qwenDir, projectDir) {
  const projectKey = createHash("sha256").update(projectDir).digest("hex").slice(0, 16);
  return join2(qwenDir, `${SUBAGENT_MARKER}-${projectKey}`);
}
__name(getSubagentMarkerPath, "getSubagentMarkerPath");
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}`
      );
    }
  );
  const projectDir = config.storage?.getProjectDir?.();
  if (projectDir) {
    const markerPath = getSubagentMarkerPath(qwenDir, projectDir);
    await runThrottledOnce(
      {
        name: "subagent-cleanup",
        markerPath,
        lockPath: markerPath + ".lock"
      },
      async () => {
        const r = await cleanupOldSubagentTranscripts({
          cutoffDate: cutoff,
          excludeSessionIds: /* @__PURE__ */ new Set([currentSessionId]),
          subagentsRoot: getSubagentsRootDir(projectDir)
        });
        debugLogger3.debug(`subagents: 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;
var _getSubagentMarkerPathForTesting = getSubagentMarkerPath;
export {
  _FILE_HISTORY_MARKER_FOR_TESTING,
  _getSubagentMarkerPathForTesting,
  _needsCatchUpForTesting,
  _resetForTesting,
  _runHousekeepingForTesting,
  _runPassForTesting,
  startBackgroundHousekeeping
};
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
