// Force strict mode and setup for ESM
"use strict";
import {
  escape,
  globStream
} from "./chunk-VDNAD6JC.js";
import "./chunk-GOFAQQZA.js";
import "./chunk-5M6IDOMF.js";
import "./chunk-TWPJO254.js";
import "./chunk-H6XPXXMH.js";
import "./chunk-VA5NLVPT.js";
import "./chunk-I7JDGNG6.js";
import "./chunk-A6SX5TAH.js";
import "./chunk-33FNCQSY.js";
import "./chunk-6PVPNMXU.js";
import "./chunk-QP2X3YUW.js";
import "./chunk-IRH27ZC2.js";
import "./chunk-QHWCP53L.js";
import "./chunk-MOHAWIAW.js";
import "./chunk-X6QNZOTC.js";
import "./chunk-O6GEWCJA.js";
import "./chunk-T26EAKDL.js";
import "./chunk-ZPJWUGCS.js";
import "./chunk-CPBF7KYF.js";
import "./chunk-MISUEWB4.js";
import "./chunk-KRXPRVGL.js";
import "./chunk-A5YZ3FA2.js";
import "./chunk-YAVY33G4.js";
import "./chunk-2UISUFHQ.js";
import "./chunk-HFVW54NL.js";
import "./chunk-TZTBZ25J.js";
import "./chunk-S6LOFUVP.js";
import "./chunk-SRY26X4H.js";
import "./chunk-K623ENWT.js";
import "./chunk-AQ37AY7B.js";
import {
  DEFAULT_FILE_FILTERING_OPTIONS,
  isPathWithinRoot
} from "./chunk-432XCUHF.js";
import "./chunk-XC656O42.js";
import "./chunk-NAVJD2PQ.js";
import "./chunk-QYPT3QUD.js";
import "./chunk-QMBEW7EW.js";
import "./chunk-DGEIYUC3.js";
import "./chunk-MPHPFVKK.js";
import "./chunk-GLNBDYUX.js";
import "./chunk-DJ2GSRLV.js";
import "./chunk-5CPNLKAW.js";
import "./chunk-RPYYTL7E.js";
import "./chunk-2J3OJGTL.js";
import "./chunk-P3QQPMQA.js";
import "./chunk-6O5DVH27.js";
import "./chunk-GLCZKT5V.js";
import "./chunk-2DNKEBXY.js";
import "./chunk-N7ZZBTIU.js";
import "./chunk-VGC4I5JJ.js";
import {
  getMemoryBaseDir
} from "./chunk-E4WHKETF.js";
import "./chunk-UEJESCS7.js";
import {
  BaseDeclarativeTool,
  BaseToolInvocation,
  ToolDisplayNames,
  ToolNames
} from "./chunk-CFDR3GNL.js";
import "./chunk-O4Z6JR7D.js";
import "./chunk-46UV252V.js";
import "./chunk-ZBVS26BY.js";
import "./chunk-BFHXDAR7.js";
import "./chunk-TYERNYH4.js";
import "./chunk-UH7Z7Y45.js";
import "./chunk-O2ZYHG33.js";
import "./chunk-W4RQUHY3.js";
import "./chunk-G7XXKQYS.js";
import {
  createDebugLogger,
  formatDisplayPath,
  getErrorMessage,
  isSubpath,
  resolveAndValidatePath,
  resolvePath,
  unescapePath
} from "./chunk-3RXUYQJI.js";
import "./chunk-VOQXFAY5.js";
import "./chunk-75DOP5OR.js";
import "./chunk-DMTGGOSA.js";
import "./chunk-YQ3U5MUC.js";
import "./chunk-AMDSOFFV.js";
import "./chunk-QUGAUQGJ.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/core/src/tools/glob.ts
init_esbuild_shims();
import fs from "node:fs";
import path from "node:path";
var debugLogger = createDebugLogger("GLOB");
var MAX_FILE_COUNT = 100;
var MAX_GLOB_COLLECTED_ENTRIES = MAX_FILE_COUNT * 10;
var normalizePathForComparison = /* @__PURE__ */ __name((p) => process.platform === "win32" || process.platform === "darwin" ? p.toLowerCase() : p, "normalizePathForComparison");
function sortFileEntries(entries, nowTimestamp, recencyThresholdMs) {
  const sortedEntries = [...entries];
  sortedEntries.sort((a, b) => {
    const mtimeA = a.mtimeMs ?? 0;
    const mtimeB = b.mtimeMs ?? 0;
    const aIsRecent = nowTimestamp - mtimeA < recencyThresholdMs;
    const bIsRecent = nowTimestamp - mtimeB < recencyThresholdMs;
    if (aIsRecent && bIsRecent) {
      return mtimeB - mtimeA;
    } else if (aIsRecent) {
      return -1;
    } else if (bIsRecent) {
      return 1;
    } else {
      return a.fullpath().localeCompare(b.fullpath());
    }
  });
  return sortedEntries;
}
__name(sortFileEntries, "sortFileEntries");
var GlobToolInvocation = class extends BaseToolInvocation {
  constructor(config, params) {
    super(params);
    this.config = config;
    this.fileService = config.getFileService();
  }
  static {
    __name(this, "GlobToolInvocation");
  }
  fileService;
  getDescription() {
    let description = `'${this.params.pattern}'`;
    if (this.params.path) {
      const displayPath = formatDisplayPath(
        this.params.path,
        this.config.getTargetDir()
      );
      description += ` in ${displayPath}`;
    }
    return description;
  }
  /**
   * Returns 'ask' for paths outside the workspace, so that external glob
   * searches require user confirmation.
   */
  async getDefaultPermission() {
    if (!this.params.path) {
      return "allow";
    }
    const workspaceContext = this.config.getWorkspaceContext();
    const resolvedPath = resolvePath(
      this.config.getTargetDir(),
      this.params.path
    );
    if (workspaceContext.isPathWithinWorkspace(resolvedPath) || isSubpath(getMemoryBaseDir(), resolvedPath)) {
      return "allow";
    }
    return "ask";
  }
  /**
   * Runs glob search in a single directory and returns filtered entries.
   */
  async globInDirectory(searchDir, pattern, signal, entryLimit) {
    let effectivePattern = pattern;
    const fullPath = path.join(searchDir, effectivePattern);
    if (fs.existsSync(fullPath)) {
      effectivePattern = escape(effectivePattern);
    }
    const projectRoot = this.config.getTargetDir();
    const fileFilteringOptions = this.getFileFilteringOptions();
    const isTraversalIgnored = /* @__PURE__ */ __name((entry) => {
      try {
        const relativePath = path.relative(projectRoot, entry.fullpath());
        if (!relativePath || !isPathWithinRoot(entry.fullpath(), projectRoot)) {
          return false;
        }
        const ignorePath = entry.isDirectory() ? relativePath + "/" : relativePath;
        return this.fileService.shouldIgnoreFile(
          ignorePath,
          fileFilteringOptions
        );
      } catch (error) {
        debugLogger.debug(
          `traversal ignore check failed for ${entry.fullpath()}: ${getErrorMessage(error)}`
        );
        return false;
      }
    }, "isTraversalIgnored");
    const isAllowedByFileFilters = /* @__PURE__ */ __name((entry) => {
      const relativePath = path.relative(projectRoot, entry.fullpath());
      return this.fileService.filterFiles([relativePath], fileFilteringOptions).length > 0;
    }, "isAllowedByFileFilters");
    const stream = globStream(effectivePattern, {
      cwd: searchDir,
      withFileTypes: true,
      nodir: true,
      stat: true,
      nocase: true,
      dot: true,
      follow: false,
      signal,
      ignore: {
        ignored: isTraversalIgnored,
        childrenIgnored: isTraversalIgnored
      }
    });
    const entries = [];
    let hitLimit = false;
    for await (const entry of stream) {
      if (!isAllowedByFileFilters(entry)) {
        continue;
      }
      if (entries.length >= entryLimit) {
        hitLimit = true;
        break;
      }
      entries.push(entry);
    }
    if (hitLimit) {
      stream.destroy?.();
    }
    return { entries, hitLimit };
  }
  async execute(signal) {
    try {
      const searchDirs = [];
      let searchLocationDescription;
      if (this.params.path) {
        const searchDirAbs = resolveAndValidatePath(
          this.config,
          this.params.path,
          { allowExternalPaths: true }
        );
        searchDirs.push(searchDirAbs);
        searchLocationDescription = `within ${searchDirAbs}`;
      } else {
        const workspaceDirs = this.config.getWorkspaceContext().getDirectories();
        searchDirs.push(...workspaceDirs);
        searchLocationDescription = workspaceDirs.length > 1 ? `across ${workspaceDirs.length} workspace directories` : `in the workspace directory`;
      }
      const pattern = this.params.pattern;
      const allFilteredEntries = [];
      const seenPaths = /* @__PURE__ */ new Set();
      let hitCollectionLimit = false;
      for (const searchDir of searchDirs) {
        const remainingEntries = MAX_GLOB_COLLECTED_ENTRIES - allFilteredEntries.length;
        if (remainingEntries <= 0) {
          hitCollectionLimit = true;
          break;
        }
        const { entries, hitLimit } = await this.globInDirectory(
          searchDir,
          pattern,
          signal,
          remainingEntries
        );
        hitCollectionLimit ||= hitLimit;
        for (const entry of entries) {
          const normalized = normalizePathForComparison(entry.fullpath());
          if (!seenPaths.has(normalized)) {
            seenPaths.add(normalized);
            allFilteredEntries.push(entry);
          }
        }
      }
      const filteredEntries = allFilteredEntries;
      if (!filteredEntries || filteredEntries.length === 0) {
        return {
          llmContent: `No files found matching pattern "${this.params.pattern}" ${searchLocationDescription}`,
          returnDisplay: `No files found`
        };
      }
      const oneDayInMs = 24 * 60 * 60 * 1e3;
      const nowTimestamp = (/* @__PURE__ */ new Date()).getTime();
      const sortedEntries = sortFileEntries(
        filteredEntries,
        nowTimestamp,
        oneDayInMs
      );
      const totalFileCount = sortedEntries.length;
      const fileLimit = Math.min(
        MAX_FILE_COUNT,
        this.config.getTruncateToolOutputLines()
      );
      const truncated = hitCollectionLimit || totalFileCount > fileLimit;
      const entriesToShow = truncated ? sortedEntries.slice(0, fileLimit) : sortedEntries;
      const sortedAbsolutePaths = entriesToShow.map(
        (entry) => entry.fullpath()
      );
      const fileListDescription = sortedAbsolutePaths.join("\n");
      let resultMessage = hitCollectionLimit ? `Found at least ${totalFileCount} file(s) matching "${this.params.pattern}" ${searchLocationDescription}` : `Found ${totalFileCount} file(s) matching "${this.params.pattern}" ${searchLocationDescription}`;
      resultMessage += `, sorted by modification time (newest first):
---
${fileListDescription}`;
      if (hitCollectionLimit) {
        resultMessage += `
---
[Results truncated after scanning ${totalFileCount} matching files. Narrow the pattern or path.]`;
      } else if (truncated) {
        const omittedFiles = totalFileCount - fileLimit;
        const fileTerm = omittedFiles === 1 ? "file" : "files";
        resultMessage += `
---
[${omittedFiles} ${fileTerm} truncated] ...`;
      }
      return {
        llmContent: resultMessage,
        returnDisplay: `${hitCollectionLimit ? "Found at least" : "Found"} ${totalFileCount} matching file(s)${truncated ? " (truncated)" : ""}`,
        resultFilePaths: sortedAbsolutePaths
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      debugLogger.error(`GlobLogic execute Error: ${errorMessage}`, error);
      const rawError = `Error during glob search operation: ${errorMessage}`;
      return {
        llmContent: rawError,
        returnDisplay: `Error: ${errorMessage || "An unexpected error occurred."}`,
        error: {
          message: rawError,
          type: "glob_execution_error" /* GLOB_EXECUTION_ERROR */
        }
      };
    }
  }
  getFileFilteringOptions() {
    const options = this.config.getFileFilteringOptions?.();
    return {
      respectGitIgnore: options?.respectGitIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore,
      respectQwenIgnore: options?.respectQwenIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectQwenIgnore,
      customIgnoreFiles: options?.customIgnoreFiles ?? DEFAULT_FILE_FILTERING_OPTIONS.customIgnoreFiles
    };
  }
};
var GlobTool = class _GlobTool extends BaseDeclarativeTool {
  constructor(config) {
    super(
      _GlobTool.Name,
      ToolDisplayNames.GLOB,
      'Fast file pattern matching tool that works with any codebase size\n- Supports glob patterns like "**/*.js" or "src/**/*.ts"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns\n- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead\n- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.',
      "search" /* Search */,
      {
        properties: {
          pattern: {
            description: "The glob pattern to match files against",
            type: "string"
          },
          path: {
            description: 'The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.',
            type: "string"
          }
        },
        required: ["pattern"],
        type: "object"
      }
    );
    this.config = config;
  }
  static {
    __name(this, "GlobTool");
  }
  static Name = ToolNames.GLOB;
  /**
   * Validates the parameters for the tool.
   */
  validateToolParamValues(params) {
    if (!params.pattern || typeof params.pattern !== "string" || params.pattern.trim() === "") {
      return "The 'pattern' parameter cannot be empty.";
    }
    if (params.path) {
      params.path = unescapePath(params.path.trim());
      try {
        resolveAndValidatePath(this.config, params.path, {
          allowExternalPaths: true
        });
      } catch (error) {
        return getErrorMessage(error);
      }
    }
    return null;
  }
  createInvocation(params) {
    return new GlobToolInvocation(this.config, params);
  }
};
export {
  GlobTool,
  sortFileEntries
};
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
