// Force strict mode and setup for ESM
"use strict";
import {
  readManyFiles,
  shouldRunVisionBridge
} from "./chunk-Z3SLAUKQ.js";
import {
  emptyMcpResourceText,
  formatMcpResourceContents,
  summarizeMcpResource
} from "./chunk-LQ7TMOCE.js";
import {
  Storage,
  getErrorMessage,
  isNodeError,
  isSubpath,
  unescapePath
} from "./chunk-C4K3FEQ2.js";
import {
  init_esbuild_shims
} from "./chunk-A4BMJM77.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/ui/hooks/atCommandProcessor.ts
init_esbuild_shims();
import * as fs from "node:fs/promises";
import * as path from "node:path";

// packages/cli/src/ui/hooks/mcpResourceRef.ts
init_esbuild_shims();
function matchMcpServerPrefix(input, serverNames) {
  let serverName = null;
  for (const name of serverNames) {
    if (input.startsWith(`${name}:`) && (serverName === null || name.length > serverName.length)) {
      serverName = name;
    }
  }
  if (serverName === null) return null;
  return { serverName, rest: input.slice(serverName.length + 1) };
}
__name(matchMcpServerPrefix, "matchMcpServerPrefix");
function buildMcpResourceRef(serverName, uri) {
  return `${serverName}:${uri}`;
}
__name(buildMcpResourceRef, "buildMcpResourceRef");

// packages/cli/src/ui/hooks/atCommandProcessor.ts
function parseAllAtCommands(query) {
  const parts = [];
  let currentIndex = 0;
  while (currentIndex < query.length) {
    let atIndex = -1;
    let nextSearchIndex = currentIndex;
    while (nextSearchIndex < query.length) {
      if (query[nextSearchIndex] === "@" && (nextSearchIndex === 0 || query[nextSearchIndex - 1] !== "\\")) {
        atIndex = nextSearchIndex;
        break;
      }
      nextSearchIndex++;
    }
    if (atIndex === -1) {
      if (currentIndex < query.length) {
        parts.push({ type: "text", content: query.substring(currentIndex) });
      }
      break;
    }
    if (atIndex > currentIndex) {
      parts.push({
        type: "text",
        content: query.substring(currentIndex, atIndex)
      });
    }
    let pathEndIndex = atIndex + 1;
    let inEscape = false;
    while (pathEndIndex < query.length) {
      const char = query[pathEndIndex];
      if (inEscape) {
        inEscape = false;
      } else if (char === "\\") {
        inEscape = true;
      } else if (/[,\s;!?()[\]{}]/.test(char)) {
        break;
      } else if (char === ".") {
        const nextChar = pathEndIndex + 1 < query.length ? query[pathEndIndex + 1] : "";
        if (nextChar === "" || /\s/.test(nextChar)) {
          break;
        }
      }
      pathEndIndex++;
    }
    const rawAtPath = query.substring(atIndex, pathEndIndex);
    const atPath = unescapePath(rawAtPath);
    parts.push({ type: "atPath", content: atPath });
    currentIndex = pathEndIndex;
  }
  return parts.filter(
    (part) => !(part.type === "text" && part.content.trim() === "")
  );
}
__name(parseAllAtCommands, "parseAllAtCommands");
function parseMcpResourceRef(pathName, mcpServerNames) {
  const match = matchMcpServerPrefix(pathName, mcpServerNames);
  if (!match || !match.rest) return null;
  return { serverName: match.serverName, uri: match.rest };
}
__name(parseMcpResourceRef, "parseMcpResourceRef");
async function resolveAtCommandQuery({
  query,
  config,
  onDebugMessage,
  messageId: userMessageTimestamp,
  signal
}) {
  const commandParts = parseAllAtCommands(query);
  const atPathCommandParts = commandParts.filter(
    (part) => part.type === "atPath"
  );
  if (atPathCommandParts.length === 0) {
    return { processedQuery: [{ text: query }], shouldProceed: true };
  }
  const fileDiscovery = config.getFileService();
  const respectFileIgnore = config.getFileFilteringOptions();
  const pathSpecsToRead = [];
  const atPathToResolvedSpecMap = /* @__PURE__ */ new Map();
  const contentLabelsForDisplay = [];
  const ignoredByReason = {
    git: [],
    qwen: [],
    both: []
  };
  const mcpServerNames = new Set(Object.keys(config.getMcpServers() || {}));
  const mcpResourceRefs = [];
  for (const atPathPart of atPathCommandParts) {
    const originalAtPath = atPathPart.content;
    if (originalAtPath === "@") {
      onDebugMessage(
        "Lone @ detected, will be treated as text in the modified query."
      );
      continue;
    }
    const pathName = originalAtPath.substring(1);
    const resourceRef = parseMcpResourceRef(pathName, mcpServerNames);
    if (resourceRef) {
      mcpResourceRefs.push({ originalAtPath, ...resourceRef });
      atPathToResolvedSpecMap.set(originalAtPath, pathName);
      continue;
    }
    const workspaceContext = config.getWorkspaceContext();
    const projectTempDir = Storage.getGlobalTempDir();
    const absolutePathName = path.isAbsolute(pathName) ? pathName : path.resolve(workspaceContext.getDirectories()[0] || "", pathName);
    if (!isSubpath(projectTempDir, absolutePathName) && !workspaceContext.isPathWithinWorkspace(pathName)) {
      onDebugMessage(
        `Path ${pathName} is not in the workspace and will be skipped.`
      );
      continue;
    }
    const gitIgnored = respectFileIgnore.respectGitIgnore && fileDiscovery.shouldIgnoreFile(pathName, {
      respectGitIgnore: true,
      respectQwenIgnore: false
    });
    const qwenIgnored = respectFileIgnore.respectQwenIgnore && fileDiscovery.shouldIgnoreFile(pathName, {
      respectGitIgnore: false,
      respectQwenIgnore: true
    });
    if (gitIgnored || qwenIgnored) {
      const reason = gitIgnored && qwenIgnored ? "both" : gitIgnored ? "git" : "qwen";
      ignoredByReason[reason].push(pathName);
      const reasonText = reason === "both" ? "ignored by both git and qwen" : reason === "git" ? "git-ignored" : "qwen-ignored";
      onDebugMessage(`Path ${pathName} is ${reasonText} and will be skipped.`);
      continue;
    }
    let resolvedSuccessfully = false;
    let sawNotFound = false;
    for (const dir of config.getWorkspaceContext().getDirectories()) {
      let currentPathSpec = pathName;
      try {
        const absolutePath = path.resolve(dir, pathName);
        const stats = await fs.stat(absolutePath);
        if (stats.isDirectory()) {
          currentPathSpec = pathName;
          onDebugMessage(`Path ${pathName} resolved to directory.`);
        } else {
          onDebugMessage(`Path ${pathName} resolved to file: ${absolutePath}`);
        }
        resolvedSuccessfully = true;
      } catch (error) {
        if (isNodeError(error) && error.code === "ENOENT") {
          sawNotFound = true;
          continue;
        } else {
          onDebugMessage(
            `Error stating path ${pathName}: ${getErrorMessage(error)}. Path ${pathName} will be skipped.`
          );
        }
      }
      if (resolvedSuccessfully) {
        pathSpecsToRead.push(currentPathSpec);
        atPathToResolvedSpecMap.set(originalAtPath, currentPathSpec);
        contentLabelsForDisplay.push(pathName);
        break;
      }
    }
    if (!resolvedSuccessfully && sawNotFound) {
      onDebugMessage(
        `Path ${pathName} not found. Path ${pathName} will be skipped.`
      );
    }
  }
  let initialQueryText = "";
  for (let i = 0; i < commandParts.length; i++) {
    const part = commandParts[i];
    if (part.type === "text") {
      initialQueryText += part.content;
    } else {
      const resolvedSpec = atPathToResolvedSpecMap.get(part.content);
      if (i > 0 && initialQueryText.length > 0 && !initialQueryText.endsWith(" ")) {
        const prevPart = commandParts[i - 1];
        if (prevPart.type === "text" || prevPart.type === "atPath" && atPathToResolvedSpecMap.has(prevPart.content)) {
          initialQueryText += " ";
        }
      }
      if (resolvedSpec) {
        initialQueryText += `@${resolvedSpec}`;
      } else {
        if (i > 0 && initialQueryText.length > 0 && !initialQueryText.endsWith(" ") && !part.content.startsWith(" ")) {
          initialQueryText += " ";
        }
        initialQueryText += part.content;
      }
    }
  }
  initialQueryText = initialQueryText.trim();
  const totalIgnored = ignoredByReason["git"].length + ignoredByReason["qwen"].length + ignoredByReason["both"].length;
  if (totalIgnored > 0) {
    const messages = [];
    if (ignoredByReason["git"].length) {
      messages.push(`Git-ignored: ${ignoredByReason["git"].join(", ")}`);
    }
    if (ignoredByReason["qwen"].length) {
      messages.push(`Qwen-ignored: ${ignoredByReason["qwen"].join(", ")}`);
    }
    if (ignoredByReason["both"].length) {
      messages.push(`Ignored by both: ${ignoredByReason["both"].join(", ")}`);
    }
    const message = `Ignored ${totalIgnored} files:
${messages.join("\n")}`;
    onDebugMessage(message);
  }
  const resourceReads = await Promise.allSettled(
    mcpResourceRefs.map(
      (ref) => config.getToolRegistry().readMcpResource(ref.serverName, ref.uri, { signal })
    )
  );
  const resourceParts = [];
  const resourceDisplays = [];
  const resourceLabels = [];
  for (let i = 0; i < mcpResourceRefs.length; i++) {
    const ref = mcpResourceRefs[i];
    const label = `${ref.serverName}:${ref.uri}`;
    const callId = `client-mcp-resource-${userMessageTimestamp}-${i}`;
    const outcome = resourceReads[i];
    if (outcome.status === "rejected") {
      onDebugMessage(
        `Failed to read MCP resource ${label}: ${getErrorMessage(outcome.reason)}`
      );
      resourceDisplays.push({
        callId,
        name: "Read MCP Resource",
        description: `Read resource ${label}`,
        status: "Error" /* Error */,
        resultDisplay: `Failed to read resource ${label}: ${getErrorMessage(outcome.reason)}`,
        confirmationDetails: void 0
      });
      continue;
    }
    const formatted = formatMcpResourceContents(outcome.value, label);
    if (formatted.parts.length > 0) {
      resourceParts.push(...formatted.parts);
    } else {
      resourceParts.push({ text: emptyMcpResourceText(formatted, label) });
    }
    resourceLabels.push(label);
    resourceDisplays.push({
      callId,
      name: "Read MCP Resource",
      description: `Read resource ${label}`,
      status: "Success" /* Success */,
      resultDisplay: summarizeMcpResource(formatted),
      confirmationDetails: void 0
    });
  }
  if (pathSpecsToRead.length === 0 && mcpResourceRefs.length === 0) {
    onDebugMessage("No valid file paths found in @ commands to read.");
    if (initialQueryText === "@" && query.trim() === "@") {
      return { processedQuery: [{ text: query }], shouldProceed: true };
    } else if (!initialQueryText && query) {
      return { processedQuery: [{ text: query }], shouldProceed: true };
    }
    return {
      processedQuery: [{ text: initialQueryText || query }],
      shouldProceed: true
    };
  }
  const fileParts = [];
  let fileDisplays = [];
  if (pathSpecsToRead.length > 0) {
    try {
      const result = await readManyFiles(config, {
        paths: pathSpecsToRead,
        signal,
        preserveUnsupportedImageForBridge: shouldRunVisionBridge(config)
      });
      const parts = Array.isArray(result.contentParts) ? result.contentParts : [result.contentParts];
      fileDisplays = result.files.map((file, index) => ({
        callId: `client-read-${userMessageTimestamp}-${index}`,
        name: file.isDirectory ? "Read Directory" : "Read File",
        description: file.isDirectory ? `Read directory ${path.basename(file.filePath)}` : `Read file ${path.basename(file.filePath)}`,
        status: file.error ? "Error" /* Error */ : "Success" /* Success */,
        resultDisplay: file.error ? `Failed to read ${path.basename(file.filePath)}: ${file.error}` : void 0,
        confirmationDetails: void 0
      }));
      if (parts.length > 0 && !result.error) {
        for (const part of parts) {
          fileParts.push(typeof part === "string" ? { text: part } : part);
        }
      } else {
        onDebugMessage("readManyFiles returned no content or empty content.");
      }
    } catch (error) {
      const errorToolCallDisplay = {
        callId: `client-read-${userMessageTimestamp}`,
        name: "Read File(s)",
        description: "Error attempting to read files",
        status: "Error" /* Error */,
        resultDisplay: `Error reading files (${contentLabelsForDisplay.join(", ")}): ${getErrorMessage(error)}`,
        confirmationDetails: void 0
      };
      const errorMessage = typeof errorToolCallDisplay.resultDisplay === "string" ? errorToolCallDisplay.resultDisplay : void 0;
      const labelsOnError = [...contentLabelsForDisplay, ...resourceLabels];
      return {
        processedQuery: null,
        shouldProceed: false,
        toolDisplays: [...resourceDisplays, errorToolCallDisplay],
        filesRead: labelsOnError,
        recording: {
          filesRead: labelsOnError,
          status: "error",
          message: errorMessage
        }
      };
    }
  }
  const processedQueryParts = [
    { text: initialQueryText },
    ...fileParts,
    ...resourceParts
  ];
  const allLabels = [...contentLabelsForDisplay, ...resourceLabels];
  return {
    processedQuery: processedQueryParts,
    shouldProceed: true,
    toolDisplays: [...fileDisplays, ...resourceDisplays],
    filesRead: allLabels,
    recording: {
      filesRead: allLabels,
      status: "success"
    }
  };
}
__name(resolveAtCommandQuery, "resolveAtCommandQuery");
async function handleAtCommand(params) {
  const result = await resolveAtCommandQuery(params);
  if (result.recording) {
    const chatRecorder = params.config.getChatRecordingService?.();
    chatRecorder?.recordAtCommand({
      filesRead: result.recording.filesRead,
      status: result.recording.status,
      ...result.recording.message ? { message: result.recording.message } : {},
      userText: params.query
    });
  }
  if (params.addItem && result.toolDisplays && result.toolDisplays.length > 0) {
    const toolGroupItem = {
      type: "tool_group",
      tools: result.toolDisplays
    };
    params.addItem(toolGroupItem, params.messageId);
  }
  return {
    processedQuery: result.processedQuery,
    shouldProceed: result.shouldProceed,
    toolDisplays: result.toolDisplays,
    filesRead: result.filesRead
  };
}
__name(handleAtCommand, "handleAtCommand");

export {
  matchMcpServerPrefix,
  buildMcpResourceRef,
  resolveAtCommandQuery,
  handleAtCommand
};
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
