"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var utils_exports = {};
__export(utils_exports, {
  FileLock: () => FileLock,
  MemoryMonitor: () => MemoryMonitor,
  Mutex: () => Mutex,
  clamp: () => clamp,
  debounce: () => debounce,
  isPathWithinRoot: () => isPathWithinRoot,
  isPathWithinRootReal: () => isPathWithinRootReal,
  normalizePath: () => normalizePath,
  processInBatches: () => processInBatches,
  safeJsonParse: () => safeJsonParse,
  throttle: () => throttle,
  validatePathWithinRoot: () => validatePathWithinRoot,
  validateProjectPath: () => validateProjectPath
});
module.exports = __toCommonJS(utils_exports);
var path = __toESM(require("path"));
var fs = __toESM(require("fs"));
var import_errors = require("./errors");
class Mutex {
  constructor() {
    this.queue = [];
    this._locked = false;
  }
  async acquire() {
    return new Promise((resolve) => {
      const tryAcquire = () => {
        if (!this._locked) {
          this._locked = true;
          resolve(() => this._release());
        } else {
          this.queue.push(tryAcquire);
        }
      };
      tryAcquire();
    });
  }
  async withLock(fn) {
    const release = await this.acquire();
    try {
      return await fn();
    } finally {
      release();
    }
  }
  isLocked() {
    return this._locked;
  }
  _release() {
    this._locked = false;
    const next = this.queue.shift();
    if (next) next();
  }
}
class FileLock {
  // 2 minutes
  constructor(lockPath) {
    this.lockPath = lockPath;
  }
  static {
    this.STALE_TIMEOUT_MS = 12e4;
  }
  async acquire() {
    const deadline = Date.now() + FileLock.STALE_TIMEOUT_MS;
    while (Date.now() < deadline) {
      try {
        const fd = fs.openSync(this.lockPath, "wx");
        fs.writeSync(fd, String(process.pid));
        fs.closeSync(fd);
        return () => this._release();
      } catch {
        try {
          const stat = fs.statSync(this.lockPath);
          if (Date.now() - stat.mtimeMs > FileLock.STALE_TIMEOUT_MS) {
            fs.unlinkSync(this.lockPath);
            continue;
          }
        } catch {
          continue;
        }
        await new Promise((r) => setTimeout(r, 50));
      }
    }
    throw new Error(`FileLock: timed out waiting for lock at ${this.lockPath}`);
  }
  withLock(fn) {
    const fd = fs.openSync(this.lockPath, "wx");
    fs.writeSync(fd, String(process.pid));
    fs.closeSync(fd);
    try {
      return fn();
    } finally {
      this._release();
    }
  }
  async withLockAsync(fn) {
    const release = await this.acquire();
    try {
      return await fn();
    } finally {
      release();
    }
  }
  _release() {
    try {
      fs.unlinkSync(this.lockPath);
    } catch {
    }
  }
}
async function processInBatches(items, batchSize, fn) {
  const results = [];
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    const batchResults = await fn(batch);
    results.push(...batchResults);
  }
  return results;
}
function debounce(fn, delayMs) {
  let timer = null;
  return function(...args) {
    if (timer !== null) clearTimeout(timer);
    timer = setTimeout(() => {
      timer = null;
      fn.apply(this, args);
    }, delayMs);
  };
}
function throttle(fn, intervalMs) {
  let lastCall = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastCall >= intervalMs) {
      lastCall = now;
      return fn.apply(this, args);
    }
  };
}
class MemoryMonitor {
  constructor(opts) {
    this.timer = null;
    this.peakBytes = 0;
    this.thresholdBytes = opts.thresholdMb * 1024 * 1024;
    this.intervalMs = opts.intervalMs;
  }
  start() {
    if (this.timer !== null) return;
    this.timer = setInterval(() => {
      const used = process.memoryUsage().heapUsed;
      if (used > this.peakBytes) this.peakBytes = used;
      if (used > this.thresholdBytes) {
        (0, import_errors.logWarn)(`MemoryMonitor: heap usage ${(used / 1024 / 1024).toFixed(1)} MB exceeds threshold ${(this.thresholdBytes / 1024 / 1024).toFixed(1)} MB`);
      }
    }, this.intervalMs);
    if (this.timer.unref) this.timer.unref();
  }
  stop() {
    if (this.timer !== null) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }
  /** Returns peak heap usage in bytes. */
  getPeakUsage() {
    return this.peakBytes;
  }
}
function validatePathWithinRoot(filePath, root) {
  const resolved = path.resolve(filePath);
  const resolvedRoot = path.resolve(root);
  if (!resolved.startsWith(resolvedRoot + path.sep) && resolved !== resolvedRoot) return null;
  return resolved;
}
function validateProjectPath(projectRoot) {
  const SENSITIVE_DIRS = /* @__PURE__ */ new Set(["/", "/etc", "/usr", "/var", "/bin", "/sbin", "/lib", "/lib64", "/proc", "/sys", "/dev", "/boot"]);
  const resolved = path.resolve(projectRoot);
  if (SENSITIVE_DIRS.has(resolved)) {
    throw new Error(`Refusing to initialize KiroGraph in sensitive directory: ${resolved}`);
  }
}
function isPathWithinRoot(filePath, root) {
  const resolved = path.resolve(filePath);
  const resolvedRoot = path.resolve(root);
  return resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path.sep);
}
function isPathWithinRootReal(filePath, root) {
  try {
    const real = fs.realpathSync(filePath);
    const realRoot = fs.realpathSync(root);
    return real === realRoot || real.startsWith(realRoot + path.sep);
  } catch {
    return false;
  }
}
function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}
function normalizePath(p) {
  return p.split(path.sep).join("/");
}
function safeJsonParse(json, fallback) {
  try {
    return JSON.parse(json);
  } catch {
    return fallback;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  FileLock,
  MemoryMonitor,
  Mutex,
  clamp,
  debounce,
  isPathWithinRoot,
  isPathWithinRootReal,
  normalizePath,
  processInBatches,
  safeJsonParse,
  throttle,
  validatePathWithinRoot,
  validateProjectPath
});
//# sourceMappingURL=utils.js.map
