"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);

// tools/warp_grep/harness.ts
var harness_exports = {};
__export(harness_exports, {
  AGENT_CONFIG: () => AGENT_CONFIG,
  DEFAULT_EXCLUDES: () => DEFAULT_EXCLUDES,
  LocalRipgrepProvider: () => LocalRipgrepProvider,
  buildInitialState: () => buildInitialState,
  calculateContextBudget: () => calculateContextBudget,
  extractPathFromCommand: () => extractPathFromCommand,
  formatListDirectoryTree: () => formatListDirectoryTree,
  formatToolResult: () => formatAgentToolOutput,
  formatTurnMessage: () => formatTurnMessage,
  normalizeFinishFiles: () => normalizeFinishFiles,
  parseFinishFiles: () => parseFinishFiles,
  parseReadLines: () => parseReadLines,
  readFinishFiles: () => readFinishFiles,
  resolveFinishFiles: () => resolveFinishFiles,
  toolGlob: () => toolGlob,
  toolGrep: () => toolGrep,
  toolListDirectory: () => toolListDirectory,
  toolRead: () => toolRead
});
module.exports = __toCommonJS(harness_exports);

// tools/warp_grep/agent/parser.ts
function parseReadLines(linesStr) {
  const ranges = [];
  for (const rangeStr of linesStr.split(",")) {
    const trimmed = rangeStr.trim();
    if (!trimmed) continue;
    const parts = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
    if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
      ranges.push([parts[0], parts[1]]);
    } else if (Number.isFinite(parts[0])) {
      ranges.push([parts[0], parts[0]]);
    }
  }
  if (ranges.length === 1) return { start: ranges[0][0], end: ranges[0][1] };
  if (ranges.length > 1) return { lines: ranges };
  return {};
}
function parseFinishFiles(filesStr) {
  const files = [];
  for (const line of filesStr.trim().split(/\s+/)) {
    const trimmed = line.trim();
    if (!trimmed) continue;
    const searchFrom = /^[A-Za-z]:/.test(trimmed) ? 2 : 0;
    const colonIdx = trimmed.indexOf(":", searchFrom);
    if (colonIdx === -1) {
      files.push({ path: trimmed, lines: "*" });
      continue;
    }
    const filePath = trimmed.slice(0, colonIdx);
    const rangesPart = trimmed.slice(colonIdx + 1);
    if (!rangesPart.trim() || rangesPart.trim() === "*") {
      files.push({ path: filePath, lines: "*" });
      continue;
    }
    const ranges = [];
    for (const rangeStr of rangesPart.split(",")) {
      const rt = rangeStr.trim();
      if (!rt) continue;
      const parts = rt.split("-").map((v) => parseInt(v.trim(), 10));
      if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
        ranges.push([parts[0], parts[1]]);
      } else if (Number.isFinite(parts[0])) {
        ranges.push([parts[0], parts[0]]);
      }
    }
    files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
  }
  return files;
}
function extractPathFromCommand(command) {
  const tokens = command.trim().split(/\s+/);
  const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
  return pathTokens[0] || ".";
}

// tools/warp_grep/agent/formatter.ts
var ToolOutputFormatter = class {
  format(toolName, _args, output, options = {}) {
    const name = (toolName ?? "").trim();
    if (!name) {
      return "";
    }
    const payload = output?.toString?.()?.trim?.() ?? "";
    const isError = Boolean(options.isError);
    if (!payload && !isError) {
      return "";
    }
    return `<tool_response>
${payload}
</tool_response>`;
  }
};
var sharedFormatter = new ToolOutputFormatter();
function formatAgentToolOutput(toolName, args, output, options = {}) {
  return sharedFormatter.format(toolName, args, output, options);
}

// tools/warp_grep/agent/helpers.ts
var import_path = __toESM(require("path"), 1);

// tools/warp_grep/agent/config.ts
var parseEnvTimeout = (envValue, defaultMs) => {
  if (!envValue) return defaultMs;
  const parsed = parseInt(envValue, 10);
  return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
};
var AGENT_CONFIG = {
  MAX_TURNS: 6,
  /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
  TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
  MAX_CONTEXT_CHARS: 321600,
  MAX_OUTPUT_LINES: 200,
  MAX_LIST_RESULTS: 500,
  MAX_READ_LINES: 800,
  MAX_LIST_DEPTH: 3,
  LIST_TIMEOUT_MS: 2e3
};
var BUILTIN_EXCLUDES = [
  // Version control
  ".git",
  ".svn",
  ".hg",
  ".bzr",
  // Dependencies
  "node_modules",
  "bower_components",
  ".pnpm",
  ".yarn",
  "vendor",
  "packages",
  "Pods",
  ".bundle",
  // Python
  "__pycache__",
  ".pytest_cache",
  ".mypy_cache",
  ".ruff_cache",
  ".venv",
  "venv",
  ".tox",
  ".nox",
  ".eggs",
  "*.egg-info",
  // Build outputs
  "dist",
  "build",
  "out",
  "output",
  "target",
  "_build",
  ".next",
  ".nuxt",
  ".output",
  ".vercel",
  ".netlify",
  // Cache directories
  ".cache",
  ".parcel-cache",
  ".turbo",
  ".nx",
  ".gradle",
  // IDE/Editor
  ".idea",
  ".vscode",
  ".vs",
  // Coverage
  "coverage",
  ".coverage",
  "htmlcov",
  ".nyc_output",
  // Temporary
  "tmp",
  "temp",
  ".tmp",
  ".temp",
  // Lock files
  "package-lock.json",
  "yarn.lock",
  "pnpm-lock.yaml",
  "bun.lockb",
  "Cargo.lock",
  "Gemfile.lock",
  "poetry.lock",
  // Binary/minified
  "*.min.js",
  "*.min.css",
  "*.bundle.js",
  "*.wasm",
  "*.so",
  "*.dll",
  "*.pyc",
  "*.map",
  "*.js.map",
  // Hidden directories catch-all
  ".*"
];
var DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);

// tools/warp_grep/agent/helpers.ts
function getMessageSize(m) {
  if (m.role === "tool") return m.content.length;
  if (m.role === "assistant") {
    let size = typeof m.content === "string" ? m.content.length : 0;
    if (m.tool_calls) {
      size += m.tool_calls.reduce((s, tc) => s + tc.function.name.length + tc.function.arguments.length, 0);
    }
    return size;
  }
  return m.content.length;
}
function formatTurnMessage(turnsUsed, maxTurns) {
  const turnsRemaining = maxTurns - turnsUsed;
  if (turnsRemaining === 1) {
    return `
You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run out of turns to explore the code base and MUST call the finish tool now`;
  }
  return `
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
}
function calculateContextBudget(messages) {
  const totalChars = messages.reduce((sum, m) => sum + getMessageSize(m), 0);
  const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
  const percent = Math.floor(totalChars / maxChars * 100);
  const usedK = Math.floor(totalChars / 1e3);
  const maxK = Math.floor(maxChars / 1e3);
  return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
}
async function buildInitialState(repoRoot, searchTerm, provider, options) {
  const budget = calculateContextBudget([]);
  const turnTag = `You have used 0 turns and have ${AGENT_CONFIG.MAX_TURNS} remaining`;
  const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
  const absRoot = repoRoot;
  try {
    const entries = await provider.listDirectory({
      path: ".",
      maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
      maxDepth: treeDepth
    });
    const lines = [absRoot];
    for (const e of entries) {
      lines.push(import_path.default.join(absRoot, e.path));
    }
    return `<repo_structure>
${lines.join("\n")}
</repo_structure>

<search_string>
${searchTerm}
</search_string>
${budget}
${turnTag}`;
  } catch {
    return `<repo_structure>
${absRoot}
</repo_structure>

<search_string>
${searchTerm}
</search_string>
${budget}
${turnTag}`;
  }
}
function formatListDirectoryTree(entries) {
  if (!entries.length) return "empty";
  return entries.map((e) => {
    const indent = "  ".repeat(e.depth);
    const name = e.type === "dir" ? `${e.name}/` : e.name;
    return `${indent}${name}`;
  }).join("\n");
}

// tools/warp_grep/agent/tools/grep.ts
async function toolGrep(provider, args) {
  const res = await provider.grep(args);
  if (res.error) {
    return { output: res.error };
  }
  if (!res.lines.length) {
    return { output: "no matches" };
  }
  return { output: res.lines.join("\n") };
}

// tools/warp_grep/agent/tools/read.ts
function isValidRange(start, end) {
  return typeof start === "number" && typeof end === "number" && Number.isFinite(start) && Number.isFinite(end) && start > 0 && end >= start;
}
async function toolRead(provider, args) {
  if (args.lines && Array.isArray(args.lines) && args.lines.length > 0) {
    const validRanges = [];
    for (const range of args.lines) {
      if (Array.isArray(range) && range.length >= 2 && isValidRange(range[0], range[1])) {
        validRanges.push([range[0], range[1]]);
      }
    }
    if (validRanges.length === 0) {
      const res2 = await provider.read({ path: args.path });
      if (res2.error) return res2.error;
      if (!res2.lines.length) return "(empty file)";
      return res2.lines.join("\n");
    }
    const chunks = [];
    for (const [start, end] of validRanges) {
      const res2 = await provider.read({ path: args.path, start, end });
      if (res2.error) return res2.error;
      chunks.push(res2.lines.join("\n"));
    }
    if (chunks.every((c) => c === "")) return "(empty file)";
    return chunks.join("\n...\n");
  }
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
  if (res.error) {
    return res.error;
  }
  if (!res.lines.length) return "(empty file)";
  return res.lines.join("\n");
}

// tools/warp_grep/agent/tools/list_directory.ts
var import_path2 = __toESM(require("path"), 1);
async function toolListDirectory(provider, args, repoRoot) {
  const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_LIST_RESULTS;
  const maxDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
  const entries = await provider.listDirectory({
    path: args.path,
    pattern: args.pattern ?? null,
    maxResults,
    maxDepth
  });
  if (!entries.length) return "empty";
  if (repoRoot) {
    const absRoot = repoRoot;
    const lines = entries.map((e) => import_path2.default.join(absRoot, e.path));
    return lines.join("\n");
  }
  return entries.map((e) => e.path).join("\n");
}

// tools/warp_grep/agent/tools/glob.ts
async function toolGlob(provider, args) {
  const res = await provider.glob(args);
  if (res.error) {
    return res.error;
  }
  if (!res.files.length) {
    return "no matches";
  }
  const header = `Found ${res.totalFound} file(s) matching "${args.pattern}" within ${res.searchDir}, sorted by modification time (newest first):`;
  const body = res.files.join("\n");
  const truncated = res.totalFound > res.files.length ? `
[${res.totalFound - res.files.length} files truncated]` : "";
  return `${header}
---
${body}
---${truncated}`;
}

// tools/warp_grep/agent/tools/finish.ts
function isValidRange2(range) {
  return Array.isArray(range) && range.length >= 2 && typeof range[0] === "number" && typeof range[1] === "number" && Number.isFinite(range[0]) && Number.isFinite(range[1]) && range[0] > 0 && range[1] >= range[0];
}
function extractValidRanges(lines) {
  if (!Array.isArray(lines)) return null;
  const valid = [];
  for (const range of lines) {
    if (isValidRange2(range)) {
      valid.push([range[0], range[1]]);
    }
  }
  return valid.length > 0 ? valid : null;
}
function normalizeFinishFiles(files) {
  return files.map((f) => {
    if (f.lines === "*") return { path: f.path, lines: "*" };
    const validRanges = extractValidRanges(f.lines);
    if (!validRanges) return { path: f.path, lines: "*" };
    return { path: f.path, lines: mergeRanges(validRanges) };
  });
}
async function readFinishFiles(repoRoot, files, reader) {
  const out = [];
  for (const f of files) {
    const validRanges = f.lines === "*" ? null : extractValidRanges(f.lines);
    if (f.lines === "*" || !validRanges) {
      const lines = await reader(f.path);
      out.push({ path: f.path, ranges: "*", content: lines.join("\n") });
    } else {
      const ranges = mergeRanges(validRanges);
      const chunks = [];
      for (let i = 0; i < ranges.length; i++) {
        const [s, e] = ranges[i];
        if (i === 0 && s > 1) {
          chunks.push(`// ... existing code, block starting at line ${s} ...`);
        } else if (i > 0) {
          chunks.push(`// ... existing code, block starting at line ${s} ...`);
        }
        const lines = await reader(f.path, s, e);
        chunks.push(lines.join("\n"));
      }
      out.push({ path: f.path, ranges, content: chunks.join("\n") });
    }
  }
  return out;
}
function mergeRanges(ranges) {
  if (!ranges.length) return [];
  const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
  const merged = [];
  let [cs, ce] = sorted[0];
  for (let i = 1; i < sorted.length; i++) {
    const [s, e] = sorted[i];
    if (s <= ce + 1) {
      ce = Math.max(ce, e);
    } else {
      merged.push([cs, ce]);
      cs = s;
      ce = e;
    }
  }
  merged.push([cs, ce]);
  return merged;
}

// tools/warp_grep/providers/local.ts
var import_promises2 = __toESM(require("fs/promises"), 1);
var import_path4 = __toESM(require("path"), 1);

// tools/warp_grep/utils/ripgrep.ts
var import_child_process = require("child_process");
var import_ripgrep = require("@vscode/ripgrep");
var resolvedRgPath = null;
var rgPathChecked = false;
function spawnRg(rgBinary, args, opts) {
  return new Promise((resolve) => {
    const child = (0, import_child_process.spawn)(rgBinary, args, {
      cwd: opts?.cwd,
      env: { ...process.env, ...opts?.env || {} },
      stdio: ["ignore", "pipe", "pipe"]
    });
    let stdout = "";
    let stderr = "";
    child.stdout.on("data", (d) => stdout += d.toString());
    child.stderr.on("data", (d) => stderr += d.toString());
    child.on("close", (code) => {
      resolve({ stdout, stderr, exitCode: typeof code === "number" ? code : -1 });
    });
    child.on("error", () => {
      resolve({ stdout: "", stderr: "Failed to spawn ripgrep.", exitCode: -1 });
    });
  });
}
function isBinaryFailure(result) {
  if (result.exitCode === -1) return true;
  if (result.stderr.includes("jemalloc") || result.stderr.includes("Unsupported system page size")) return true;
  if (result.exitCode === 134) return true;
  return false;
}
async function runRipgrep(args, opts) {
  if (rgPathChecked && resolvedRgPath) {
    return spawnRg(resolvedRgPath, args, opts);
  }
  if (!rgPathChecked) {
    const result = await spawnRg(import_ripgrep.rgPath, args, opts);
    if (!isBinaryFailure(result)) {
      resolvedRgPath = import_ripgrep.rgPath;
      rgPathChecked = true;
      return result;
    }
    const fallbackResult = await spawnRg("rg", args, opts);
    if (!isBinaryFailure(fallbackResult)) {
      resolvedRgPath = "rg";
      rgPathChecked = true;
      return fallbackResult;
    }
    rgPathChecked = true;
    return {
      stdout: "",
      stderr: "Failed to spawn ripgrep. Neither bundled nor system rg is available.",
      exitCode: -1
    };
  }
  return {
    stdout: "",
    stderr: "Failed to spawn ripgrep. Neither bundled nor system rg is available.",
    exitCode: -1
  };
}

// tools/warp_grep/utils/paths.ts
var import_fs = __toESM(require("fs"), 1);
var import_path3 = __toESM(require("path"), 1);
function resolveUnderRepo(repoRoot, targetPath) {
  const absRoot = import_path3.default.resolve(repoRoot);
  const resolved = import_path3.default.resolve(absRoot, targetPath);
  ensureWithinRepo(absRoot, resolved);
  return resolved;
}
function ensureWithinRepo(repoRoot, absTarget) {
  const rel = import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absTarget));
  if (rel.startsWith("..") || import_path3.default.isAbsolute(rel)) {
    throw new Error(`Path outside repository root: ${absTarget}`);
  }
}
function toRepoRelative(repoRoot, absPath) {
  return import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absPath));
}
function isSymlink(p) {
  try {
    const st = import_fs.default.lstatSync(p);
    return st.isSymbolicLink();
  } catch {
    return false;
  }
}
function fixPathRepetition(fullPath) {
  const segments = fullPath.split(import_path3.default.sep).filter(Boolean);
  if (segments.length < 2) return null;
  for (let len = Math.floor(segments.length / 2); len >= 1; len--) {
    for (let i = 0; i <= segments.length - 2 * len; i++) {
      const first = segments.slice(i, i + len);
      const second = segments.slice(i + len, i + 2 * len);
      if (first.every((seg, idx) => seg === second[idx])) {
        const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];
        return import_path3.default.sep + fixed.join(import_path3.default.sep);
      }
    }
  }
  return null;
}
function isTextualFile(filePath, maxBytes = 2e6) {
  try {
    const st = import_fs.default.statSync(filePath);
    if (!st.isFile()) return false;
    if (st.size > maxBytes) return false;
    const fd = import_fs.default.openSync(filePath, "r");
    const buf = Buffer.alloc(512);
    const read = import_fs.default.readSync(fd, buf, 0, buf.length, 0);
    import_fs.default.closeSync(fd);
    for (let i = 0; i < read; i++) {
      const c = buf[i];
      if (c === 0) return false;
    }
    return true;
  } catch {
    return false;
  }
}

// tools/warp_grep/utils/files.ts
var import_promises = __toESM(require("fs/promises"), 1);
async function readAllLines(filePath) {
  const content = await import_promises.default.readFile(filePath, "utf8");
  return content.split(/\r?\n/);
}

// tools/warp_grep/providers/local.ts
var SKIP_NAMES = /* @__PURE__ */ new Set([
  // Version control
  ".git",
  ".svn",
  ".hg",
  ".bzr",
  // Dependencies
  "node_modules",
  "bower_components",
  ".pnpm",
  ".yarn",
  "vendor",
  "Pods",
  ".bundle",
  // Python
  "__pycache__",
  ".pytest_cache",
  ".mypy_cache",
  ".ruff_cache",
  ".venv",
  "venv",
  ".tox",
  ".nox",
  ".eggs",
  // Build outputs
  "dist",
  "build",
  "out",
  "output",
  "target",
  "_build",
  ".next",
  ".nuxt",
  ".output",
  ".vercel",
  ".netlify",
  // Cache
  ".cache",
  ".parcel-cache",
  ".turbo",
  ".nx",
  ".gradle",
  // IDE
  ".idea",
  ".vscode",
  ".vs",
  // Coverage
  "coverage",
  ".coverage",
  "htmlcov",
  ".nyc_output",
  // Temp
  "tmp",
  "temp",
  ".tmp",
  ".temp",
  // Lock files
  "package-lock.json",
  "yarn.lock",
  "pnpm-lock.yaml",
  "bun.lockb",
  "Cargo.lock",
  "Gemfile.lock",
  "poetry.lock"
]);
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
  ".min.js",
  ".min.css",
  ".bundle.js",
  ".wasm",
  ".so",
  ".dll",
  ".pyc",
  ".map",
  ".js.map"
]);
function shouldSkip(name, allowNames) {
  if (allowNames?.has(name)) return false;
  if (SKIP_NAMES.has(name)) return true;
  if (name.startsWith(".")) return true;
  for (const ext of SKIP_EXTENSIONS) {
    if (name.endsWith(ext)) return true;
  }
  return false;
}
var LocalRipgrepProvider = class {
  constructor(repoRoot, excludes = DEFAULT_EXCLUDES, options) {
    this.repoRoot = repoRoot;
    this.excludes = excludes;
    if (options?.allowNames?.length) {
      this.allowNames = new Set(options.allowNames);
    }
  }
  allowNames;
  async grep(params) {
    let abs;
    try {
      abs = resolveUnderRepo(this.repoRoot, params.path);
    } catch (err) {
      return {
        lines: [],
        error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
      };
    }
    const stat = await import_promises2.default.stat(abs).catch(() => null);
    if (!stat) return { lines: [] };
    const targetArg = abs === import_path4.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
    const contextLines = params.context_lines !== void 0 ? String(params.context_lines) : "1";
    const args = [
      "--no-config",
      "--no-heading",
      "--with-filename",
      "--line-number",
      "--color=never",
      "--trim",
      "--max-columns=400",
      "-C",
      contextLines,
      ...params.case_sensitive === false ? ["--ignore-case"] : [],
      ...params.glob ? ["--glob", params.glob] : [],
      ...this.excludes.filter((e) => !this.allowNames?.has(e)).flatMap((e) => ["-g", `!${e}`]),
      params.pattern,
      targetArg || "."
    ];
    const res = await runRipgrep(args, { cwd: this.repoRoot });
    if (res.exitCode === -1) {
      return {
        lines: [],
        error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:
  \u2022 macOS: brew install ripgrep
  \u2022 Ubuntu/Debian: apt install ripgrep
  \u2022 Windows: choco install ripgrep
  \u2022 Or visit: https://github.com/BurntSushi/ripgrep#installation
Exit code: ${res.exitCode}${res.stderr ? `
Details: ${res.stderr}` : ""}`
      };
    }
    if (res.exitCode !== 0 && res.exitCode !== 1) {
      return {
        lines: [],
        error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}`
      };
    }
    const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
    if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
      const truncated = lines.slice(0, AGENT_CONFIG.MAX_OUTPUT_LINES);
      truncated.push(`... (output truncated at ${AGENT_CONFIG.MAX_OUTPUT_LINES} of ${lines.length} lines)`);
      return { lines: truncated };
    }
    return { lines };
  }
  async read(params) {
    let abs;
    try {
      abs = resolveUnderRepo(this.repoRoot, params.path);
    } catch (err) {
      return {
        lines: [],
        error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
      };
    }
    let stat = await import_promises2.default.stat(abs).catch(() => null);
    if (!stat || !stat.isFile()) {
      const fixedPath = fixPathRepetition(abs);
      if (fixedPath) {
        const fixedStat = await import_promises2.default.stat(fixedPath).catch(() => null);
        if (fixedStat?.isFile()) {
          abs = fixedPath;
          stat = fixedStat;
        }
      }
    }
    if (!stat || !stat.isFile()) {
      return {
        lines: [],
        error: `[FILE NOT FOUND] You tried to read "${params.path}" but there is no file at this path. Double-check the path exists and is spelled correctly.`
      };
    }
    if (isSymlink(abs)) {
      return {
        lines: [],
        error: `[SYMLINK] You tried to read "${params.path}" but this is a symlink. Try reading the actual file it points to instead.`
      };
    }
    if (!isTextualFile(abs)) {
      return {
        lines: [],
        error: `[UNREADABLE FILE] You tried to read "${params.path}" but this file is either too large or not a text file, so it cannot be read. Try a different file.`
      };
    }
    let lines;
    try {
      lines = await readAllLines(abs);
    } catch (err) {
      return {
        lines: [],
        error: `[READ ERROR] Failed to read "${params.path}": ${err instanceof Error ? err.message : String(err)}`
      };
    }
    const total = lines.length;
    const rawStart = params.start;
    const rawEnd = params.end;
    let s = 1;
    let e = total;
    const startValid = rawStart === void 0 || Number.isFinite(rawStart) && rawStart > 0;
    const endValid = rawEnd === void 0 || Number.isFinite(rawEnd) && rawEnd > 0;
    if (startValid && endValid) {
      s = rawStart ?? 1;
      e = Math.min(rawEnd ?? total, total);
      if (s > total && total > 0 || s > e) {
        s = 1;
        e = total;
      }
    }
    const out = [];
    for (let i = s; i <= e; i += 1) {
      const content = lines[i - 1] ?? "";
      out.push(`${i}|${content}`);
    }
    if (out.length > AGENT_CONFIG.MAX_READ_LINES) {
      const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);
      truncated.push(`... (output truncated at ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines)`);
      return { lines: truncated };
    }
    return { lines: out };
  }
  async listDirectory(params) {
    let abs;
    try {
      abs = resolveUnderRepo(this.repoRoot, params.path);
    } catch {
      return [];
    }
    const stat = await import_promises2.default.stat(abs).catch(() => null);
    if (!stat || !stat.isDirectory()) {
      return [];
    }
    const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
    const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
    const regex = params.pattern ? new RegExp(params.pattern) : null;
    const repoRoot = this.repoRoot;
    const allowNames = this.allowNames;
    const results = [];
    let timedOut = false;
    const startTime = Date.now();
    async function walk(dir, depth) {
      if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {
        timedOut = true;
        return;
      }
      if (depth > maxDepth || results.length >= maxResults) return;
      let entries;
      try {
        entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
      } catch {
        return;
      }
      for (const entry of entries) {
        if (timedOut || results.length >= maxResults) break;
        if (shouldSkip(entry.name, allowNames)) continue;
        if (regex && !regex.test(entry.name)) continue;
        const full = import_path4.default.join(dir, entry.name);
        const isDir = entry.isDirectory();
        results.push({
          name: entry.name,
          path: toRepoRelative(repoRoot, full),
          type: isDir ? "dir" : "file",
          depth
        });
        if (isDir) {
          await walk(full, depth + 1);
        }
      }
    }
    await walk(abs, 0);
    return results;
  }
  async glob(params) {
    let abs;
    try {
      abs = params.path ? resolveUnderRepo(this.repoRoot, params.path) : this.repoRoot;
    } catch (err) {
      return { files: [], searchDir: this.repoRoot, totalFound: 0, error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}` };
    }
    const stat = await import_promises2.default.stat(abs).catch(() => null);
    if (!stat || !stat.isDirectory()) {
      return { files: [], searchDir: abs, totalFound: 0, error: `[PATH ERROR] Directory not found: ${params.path || "."}` };
    }
    const targetArg = abs === import_path4.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
    const args = [
      "--no-config",
      "--files",
      "--color=never",
      "-g",
      params.pattern,
      ...this.excludes.filter((e) => !this.allowNames?.has(e)).flatMap((e) => ["-g", `!${e}`]),
      targetArg || "."
    ];
    const res = await runRipgrep(args, { cwd: this.repoRoot });
    if (res.exitCode === -1) {
      return { files: [], searchDir: abs, totalFound: 0, error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required for glob search.` };
    }
    if (res.exitCode !== 0 && res.exitCode !== 1) {
      return { files: [], searchDir: abs, totalFound: 0, error: `[GLOB ERROR] glob failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}` };
    }
    const absRoot = import_path4.default.resolve(this.repoRoot);
    const relFiles = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
    const absFiles = relFiles.map((f) => import_path4.default.resolve(absRoot, f));
    const withMtime = [];
    for (const f of absFiles) {
      const s = await import_promises2.default.stat(f).catch(() => null);
      withMtime.push({ file: f, mtime: s?.mtimeMs ?? 0 });
    }
    withMtime.sort((a, b) => b.mtime - a.mtime);
    const totalFound = withMtime.length;
    return { files: withMtime.slice(0, 100).map((f) => f.file), searchDir: abs, totalFound };
  }
};

// tools/warp_grep/harness.ts
async function resolveFinishFiles(provider, files) {
  return readFinishFiles("", files, async (p, s, e) => {
    const r = await provider.read({ path: p, start: s, end: e });
    return r.lines.map((l) => {
      const idx = l.indexOf("|");
      return idx >= 0 ? l.slice(idx + 1) : l;
    });
  });
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  AGENT_CONFIG,
  DEFAULT_EXCLUDES,
  LocalRipgrepProvider,
  buildInitialState,
  calculateContextBudget,
  extractPathFromCommand,
  formatListDirectoryTree,
  formatToolResult,
  formatTurnMessage,
  normalizeFinishFiles,
  parseFinishFiles,
  parseReadLines,
  readFinishFiles,
  resolveFinishFiles,
  toolGlob,
  toolGrep,
  toolListDirectory,
  toolRead
});
//# sourceMappingURL=harness.cjs.map