// Force strict mode and setup for ESM
"use strict";
import {
  getRateLimitErrorDetails,
  getRetryAfterDelayMs,
  getRetryDelayMs,
  isQwenQuotaExceededError,
  isRateLimitError,
  retryContext
} from "./chunk-Q6CQFB7U.js";
import {
  isTlsVerificationDisabled
} from "./chunk-6EFTQYW7.js";
import {
  createDebugLogger,
  getErrorMessage,
  getErrorStatus,
  isAbortError
} from "./chunk-C27BYUX6.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/core/src/utils/retry.ts
init_esbuild_shims();

// packages/core/src/utils/retryErrorClassification.ts
init_esbuild_shims();
function classifyRetryError(error, context = {}) {
  if (isRetryAbortError(error)) {
    return {
      kind: "abort",
      diagnosis: "fail-fast",
      reason: "aborted"
    };
  }
  const details = getRateLimitErrorDetails(error);
  const statusCode = details.statusCode;
  const providerFields = getProviderFields(error);
  const providerCode = details.providerCode ?? providerFields.providerCode;
  const providerMessage = details.providerMessage ?? providerFields.providerMessage;
  const requestId = details.requestId ?? providerFields.requestId;
  const common = {
    ...statusCode !== void 0 ? { statusCode } : {},
    ...providerCode !== void 0 ? { providerCode } : {},
    ...providerMessage !== void 0 ? { providerMessage } : {},
    ...requestId !== void 0 ? { requestId } : {}
  };
  if (context.authType === "qwen-oauth" /* QWEN_OAUTH */ && isQwenQuotaExceededError(error)) {
    return {
      kind: "provider-business",
      diagnosis: "fail-fast",
      reason: "qwen-oauth-free-tier-quota",
      ...common
    };
  }
  if (isAllocatedQuotaExceeded(providerCode)) {
    return {
      kind: "provider-business",
      diagnosis: "fail-fast",
      reason: "allocated-quota-exceeded",
      ...common
    };
  }
  if (isRateLimitError(error, context.extraRetryErrorCodes)) {
    const kind = details.transport === "sse" ? "sse-provider" : statusCode !== void 0 ? "http" : "provider";
    return {
      kind,
      diagnosis: "retryable",
      reason: "rate-limit",
      ...common
    };
  }
  const transportCode = getTransportCode(error);
  if (transportCode !== void 0 && (statusCode === void 0 || statusCode >= 500)) {
    return {
      kind: "transport",
      diagnosis: "retryable",
      reason: "transport-error",
      transportCode,
      ...statusCode !== void 0 ? { statusCode } : {}
    };
  }
  if (statusCode !== void 0) {
    const kind = details.transport === "sse" ? "sse-provider" : "http";
    if (statusCode === 529) {
      return {
        kind,
        diagnosis: "retryable",
        reason: "capacity-overload",
        ...common
      };
    }
    if (statusCode === 401 || statusCode === 403) {
      return {
        kind,
        diagnosis: "fail-fast",
        reason: "auth-error",
        ...common
      };
    }
    if (statusCode >= 400 && statusCode < 500) {
      return {
        kind,
        diagnosis: "fail-fast",
        reason: "client-error",
        ...common
      };
    }
    if (statusCode >= 500 && statusCode < 600) {
      return {
        kind,
        diagnosis: "retryable",
        reason: "server-error",
        ...common
      };
    }
    return {
      kind,
      diagnosis: "unknown",
      reason: "http-status",
      ...common
    };
  }
  return {
    kind: "unknown",
    diagnosis: "unknown",
    reason: "unclassified",
    ...common
  };
}
__name(classifyRetryError, "classifyRetryError");
function isRetryAbortError(error) {
  if (isAbortError(error)) {
    return true;
  }
  return error instanceof Error && error.name === "CanceledError";
}
__name(isRetryAbortError, "isRetryAbortError");
function getTransportCode(error) {
  if (typeof error !== "object" || error === null) {
    return void 0;
  }
  const directCode = error.code;
  if (typeof directCode === "string" && isTransportCode(directCode)) {
    return directCode;
  }
  const cause = error instanceof Error ? error.cause : void 0;
  if (typeof cause === "object" && cause !== null) {
    const causeCode = cause.code;
    if (typeof causeCode === "string" && isTransportCode(causeCode)) {
      return causeCode;
    }
  }
  return void 0;
}
__name(getTransportCode, "getTransportCode");
function isTransportCode(code) {
  return TRANSPORT_ERROR_CODES.has(code);
}
__name(isTransportCode, "isTransportCode");
var TRANSPORT_ERROR_CODES = /* @__PURE__ */ new Set([
  "EAI_AGAIN",
  "ECONNABORTED",
  "ECONNREFUSED",
  "ECONNRESET",
  "EHOSTUNREACH",
  "ENETUNREACH",
  "ENOTFOUND",
  "EPIPE",
  "ETIMEDOUT",
  "UND_ERR_BODY_TIMEOUT",
  "UND_ERR_CONNECT_TIMEOUT",
  "UND_ERR_HEADERS_TIMEOUT",
  "UND_ERR_SOCKET"
]);
function isAllocatedQuotaExceeded(providerCode) {
  return providerCode === "Throttling.AllocationQuota";
}
__name(isAllocatedQuotaExceeded, "isAllocatedQuotaExceeded");
function getProviderFields(error) {
  if (typeof error !== "object" || error === null) {
    return {};
  }
  const source = error;
  const rawCode = typeof source.code === "string" || typeof source.code === "number" ? String(source.code) : void 0;
  const isHttpStatusEcho = typeof source.code === "number" && source.code >= 100 && source.code < 600;
  const providerCode = error instanceof Error && rawCode?.startsWith("ERR_") || isHttpStatusEcho ? void 0 : rawCode;
  const requestId = typeof source.request_id === "string" ? source.request_id : typeof source.requestId === "string" ? source.requestId : void 0;
  const providerMessage = typeof source.message === "string" && (!(error instanceof Error) || providerCode !== void 0 || requestId !== void 0) ? source.message : void 0;
  return {
    ...providerCode !== void 0 ? { providerCode } : {},
    ...providerMessage !== void 0 ? { providerMessage } : {},
    ...requestId !== void 0 ? { requestId } : {}
  };
}
__name(getProviderFields, "getProviderFields");
var FALLBACK_ELIGIBLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 503, 529]);
function isFallbackEligible(classification) {
  return classification.kind !== "transport" && classification.statusCode !== void 0 && FALLBACK_ELIGIBLE_STATUS_CODES.has(classification.statusCode) && classification.diagnosis !== "fail-fast" && classification.diagnosis !== "unknown";
}
__name(isFallbackEligible, "isFallbackEligible");

// packages/core/src/utils/retry.ts
var debugLogger = createDebugLogger("RETRY");
var PERSISTENT_MAX_BACKOFF_MS = 5 * 60 * 1e3;
var PERSISTENT_CAP_MS = 6 * 60 * 60 * 1e3;
var HEARTBEAT_INTERVAL_MS = 3e4;
var DEFAULT_RETRY_OPTIONS = {
  maxAttempts: 7,
  initialDelayMs: 1500,
  maxDelayMs: 3e4,
  // 30 seconds
  shouldRetryOnError: defaultShouldRetry
};
function defaultShouldRetry(error, extraRetryErrorCodes) {
  const status = getErrorStatus(error);
  return isRateLimitError(error, extraRetryErrorCodes) || status !== void 0 && status >= 500 && status < 600;
}
__name(defaultShouldRetry, "defaultShouldRetry");
function hasRetryAfterStatus(status) {
  return status === 429 || status === 503;
}
__name(hasRetryAfterStatus, "hasRetryAfterStatus");
function isTransientCapacityError(error) {
  const status = getErrorStatus(error);
  return status === 429 || status === 529;
}
__name(isTransientCapacityError, "isTransientCapacityError");
function isUnattendedMode() {
  const val = process.env["QWEN_CODE_UNATTENDED_RETRY"];
  return val === "true" || val === "1";
}
__name(isUnattendedMode, "isUnattendedMode");
function delay(ms, signal) {
  return new Promise((resolve, reject) => {
    if (signal?.aborted) {
      return reject(new Error("Retry aborted by signal"));
    }
    const cleanup = /* @__PURE__ */ __name(() => {
      signal?.removeEventListener("abort", onAbort);
    }, "cleanup");
    function onAbort() {
      clearTimeout(timeout);
      cleanup();
      reject(new Error("Retry aborted by signal"));
    }
    __name(onAbort, "onAbort");
    const timeout = setTimeout(() => {
      cleanup();
      resolve();
    }, ms);
    signal?.addEventListener("abort", onAbort, { once: true });
    if (signal?.aborted) {
      clearTimeout(timeout);
      cleanup();
      reject(new Error("Retry aborted by signal"));
    }
  });
}
__name(delay, "delay");
async function sleepWithHeartbeat(totalMs, ctx) {
  let remaining = totalMs;
  while (remaining > 0) {
    if (ctx.signal?.aborted) {
      throw new Error("Retry aborted by signal");
    }
    const chunk = Math.max(1, Math.min(remaining, ctx.heartbeatInterval));
    await delay(chunk, ctx.signal);
    remaining -= chunk;
    if (remaining > 0 && ctx.heartbeatFn) {
      ctx.heartbeatFn({
        attempt: ctx.attempt,
        remainingMs: remaining,
        error: ctx.error
      });
    }
  }
}
__name(sleepWithHeartbeat, "sleepWithHeartbeat");
async function retryWithBackoff(fn, options) {
  if (options?.maxAttempts !== void 0 && options.maxAttempts <= 0) {
    throw new Error("maxAttempts must be a positive number.");
  }
  const cleanOptions = options ? Object.fromEntries(Object.entries(options).filter(([_, v]) => v != null)) : {};
  const {
    maxAttempts,
    initialDelayMs,
    maxDelayMs,
    authType,
    extraRetryErrorCodes,
    shouldRetryOnError,
    shouldRetryOnContent,
    persistentMode,
    persistentMaxBackoffMs,
    persistentCapMs,
    heartbeatIntervalMs,
    heartbeatFn,
    signal,
    onRetry
  } = {
    ...DEFAULT_RETRY_OPTIONS,
    ...cleanOptions
  };
  const hasCustomShouldRetryOnError = typeof options?.shouldRetryOnError === "function";
  const persistent = persistentMode ?? false;
  const maxBackoff = persistentMaxBackoffMs ?? PERSISTENT_MAX_BACKOFF_MS;
  const capMs = persistentCapMs ?? PERSISTENT_CAP_MS;
  const heartbeatInterval = heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS;
  let attempt = 0;
  let persistentAttempt = 0;
  let currentDelay = initialDelayMs;
  const requestEntryTime = Date.now();
  let iterationCount = 0;
  let retryTotalDelayMs = 0;
  let lastContentResult;
  let hadContentRetry = false;
  while (attempt < maxAttempts) {
    attempt++;
    iterationCount++;
    const requestSetupMs = Date.now() - requestEntryTime;
    try {
      const result = await retryContext.run(
        { attempt: iterationCount, retryTotalDelayMs, requestSetupMs },
        () => fn()
      );
      if (shouldRetryOnContent && shouldRetryOnContent(result)) {
        lastContentResult = result;
        hadContentRetry = true;
        const delayMs = getRetryDelayMs({
          // attempt: 1 — currentDelay already tracks exponential growth;
          // getRetryDelayMs is called here only for jitter calculation.
          attempt: 1,
          initialDelayMs: currentDelay,
          maxDelayMs,
          jitterRatio: 0.3
        });
        debugLogger.warn(
          `Attempt ${iterationCount}: response rejected by content check. Retrying with backoff in ${Math.ceil(delayMs / 1e3)}s...`
        );
        await delay(delayMs, signal);
        retryTotalDelayMs += delayMs;
        currentDelay = Math.min(maxDelayMs, currentDelay * 2);
        continue;
      }
      return result;
    } catch (error) {
      const errorStatus = getErrorStatus(error);
      const retryDiagnostics = classifyRetryError(error, {
        authType,
        extraRetryErrorCodes
      });
      if (retryDiagnostics.kind === "abort") {
        throw error;
      }
      if (authType === "qwen-oauth" /* QWEN_OAUTH */ && isQwenQuotaExceededError(error)) {
        debugLogger.error(
          "Qwen OAuth quota exceeded, fast-failing",
          retryDiagnostics,
          error
        );
        throw new Error(
          `Qwen OAuth free tier has been discontinued as of 2026-04-15.

To continue using Qwen Code, try one of these alternatives:
  - OpenRouter:    https://openrouter.ai/docs/quickstart
  - Fireworks AI:  https://docs.fireworks.ai/api-reference/introduction
  - ModelStudio:   https://help.aliyun.com/zh/model-studio/coding-plan

After setting up your API key, run /auth to configure your provider.`
        );
      }
      const isTransient = isTransientCapacityError(error);
      const callerAllowsRetry = hasCustomShouldRetryOnError ? shouldRetryOnError(error) : defaultShouldRetry(error, extraRetryErrorCodes);
      const isFailFast = retryDiagnostics.diagnosis === "fail-fast";
      const shouldPersist = persistent && isTransient && callerAllowsRetry && !isFailFast;
      if (!shouldPersist) {
        if (attempt >= maxAttempts || !callerAllowsRetry) {
          throw error;
        }
      }
      let delayMs;
      if (shouldPersist) {
        persistentAttempt++;
        const retryAfterMs = hasRetryAfterStatus(errorStatus) ? getRetryAfterDelayMs(error) : null;
        if (retryAfterMs !== null && retryAfterMs > 0) {
          delayMs = Math.min(retryAfterMs, capMs);
        } else {
          delayMs = getRetryDelayMs({
            attempt: persistentAttempt,
            initialDelayMs,
            maxDelayMs: Math.min(maxBackoff, capMs),
            jitterRatio: 0.25
          });
        }
        const reportedAttempt = persistentAttempt;
        debugLogger.warn(
          `[Persistent] Attempt ${reportedAttempt} failed with status ${errorStatus ?? "unknown"}. Retrying in ${Math.ceil(delayMs / 1e3)}s...`,
          retryDiagnostics,
          error
        );
        if (!signal?.aborted) {
          try {
            onRetry?.({
              attempt: iterationCount,
              error,
              errorStatus,
              delayMs
            });
          } catch (cbError) {
            debugLogger.warn(
              `onRetry callback threw (swallowed): ${cbError instanceof Error ? cbError.message : String(cbError)}`
            );
          }
        }
        await sleepWithHeartbeat(delayMs, {
          attempt: reportedAttempt,
          error,
          heartbeatInterval,
          heartbeatFn,
          signal
        });
        retryTotalDelayMs += delayMs;
        if (attempt >= maxAttempts) {
          attempt = maxAttempts - 1;
        }
      } else {
        const retryAfterMs = hasRetryAfterStatus(errorStatus) ? getRetryAfterDelayMs(error) : null;
        let actualDelayMs;
        if (retryAfterMs !== null && retryAfterMs > 0) {
          actualDelayMs = retryAfterMs;
          currentDelay = initialDelayMs;
          logRetryAtStatusLevel(
            `Attempt ${attempt} failed with status ${errorStatus ?? "unknown"}. Retrying after explicit delay of ${retryAfterMs}ms...`,
            retryDiagnostics,
            error,
            errorStatus
          );
        } else {
          actualDelayMs = getRetryDelayMs({
            // attempt: 1 — currentDelay already tracks exponential growth;
            // getRetryDelayMs is called here only for jitter calculation.
            attempt: 1,
            initialDelayMs: currentDelay,
            maxDelayMs,
            jitterRatio: 0.3
          });
          currentDelay = Math.min(maxDelayMs, currentDelay * 2);
          logRetryAttempt(
            attempt,
            error,
            retryDiagnostics,
            errorStatus,
            actualDelayMs
          );
        }
        if (!signal?.aborted) {
          try {
            onRetry?.({
              attempt: iterationCount,
              error,
              errorStatus,
              delayMs: actualDelayMs
            });
          } catch (cbError) {
            debugLogger.warn(
              `onRetry callback threw (swallowed): ${cbError instanceof Error ? cbError.message : String(cbError)}`
            );
          }
        }
        await delay(actualDelayMs, signal);
        retryTotalDelayMs += actualDelayMs;
      }
    }
  }
  if (hadContentRetry) {
    return lastContentResult;
  }
  throw new Error("Retry attempts exhausted");
}
__name(retryWithBackoff, "retryWithBackoff");
function logRetryAttempt(attempt, error, retryDiagnostics, errorStatus, delayMs) {
  const backoff = delayMs !== void 0 ? `Retrying with backoff in ${Math.ceil(delayMs / 1e3)}s...` : "Retrying with backoff...";
  const message = errorStatus ? `Attempt ${attempt} failed with status ${errorStatus}. ${backoff}` : `Attempt ${attempt} failed. ${backoff}`;
  logRetryAtStatusLevel(message, retryDiagnostics, error, errorStatus);
}
__name(logRetryAttempt, "logRetryAttempt");
function logRetryAtStatusLevel(message, retryDiagnostics, error, errorStatus) {
  if (errorStatus !== void 0 && errorStatus >= 500 && errorStatus < 600) {
    debugLogger.error(message, retryDiagnostics, error);
  } else {
    debugLogger.warn(message, retryDiagnostics, error);
  }
}
__name(logRetryAtStatusLevel, "logRetryAtStatusLevel");

// packages/core/src/utils/fetch.ts
init_esbuild_shims();
import { URL } from "node:url";
var PRIVATE_IP_RANGES = [
  /^10\./,
  /^127\./,
  /^172\.(1[6-9]|2[0-9]|3[0-1])\./,
  /^192\.168\./,
  // IPv4 link-local (incl. cloud metadata endpoints) and CGNAT 100.64.0.0/10.
  /^169\.254\./,
  /^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\./,
  /^0\.0\.0\.0$/,
  /^::1$/,
  /^::$/,
  // ULA fc00::/7 covers fc00: through fdff: (fd00: is the common prefix in
  // practice); link-local fe80::/10 covers fe80: through febf:.
  /^f[cd][0-9a-f]{2}:/i,
  /^fe[89ab][0-9a-f]:/i
];
var TLS_ERROR_CODES = /* @__PURE__ */ new Set([
  "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
  "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
  "SELF_SIGNED_CERT_IN_CHAIN",
  "DEPTH_ZERO_SELF_SIGNED_CERT",
  "CERT_HAS_EXPIRED",
  "ERR_TLS_CERT_ALTNAME_INVALID"
]);
var FETCH_TROUBLESHOOTING_ERROR_CODES = /* @__PURE__ */ new Set([
  ...TLS_ERROR_CODES,
  "ECONNRESET",
  "ETIMEDOUT",
  "ECONNREFUSED",
  "ENOTFOUND",
  "EAI_AGAIN",
  "EHOSTUNREACH",
  "ENETUNREACH"
]);
var FetchError = class extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
    this.name = "FetchError";
  }
  static {
    __name(this, "FetchError");
  }
};
var CONNECTION_LEVEL_ERROR_CODES = /* @__PURE__ */ new Set([
  ...TLS_ERROR_CODES,
  "ECONNREFUSED",
  "EPROTO",
  "ERR_SSL_WRONG_VERSION_NUMBER",
  // Servers that don't speak TLS on 443 often reset during the handshake
  // rather than refusing the connection. Safe to include: the http fallback
  // only ever fires for URLs the caller requested as http.
  "ECONNRESET",
  "UND_ERR_SOCKET",
  // Filtered port 443 (silent drop): undici's own bounded connect timeout.
  // Deliberately NOT the full-budget ETIMEDOUT — that can fire mid-body on
  // a healthy https server, and a fallback there would double a worst-case
  // 60s wait for an ambiguous gain.
  "UND_ERR_CONNECT_TIMEOUT"
]);
function isConnectionLevelError(error) {
  return error instanceof FetchError && error.code !== void 0 && CONNECTION_LEVEL_ERROR_CODES.has(error.code);
}
__name(isConnectionLevelError, "isConnectionLevelError");
function mappedIpv4(hostname) {
  const match = /^::ffff:(.+)$/i.exec(hostname);
  if (!match) return void 0;
  const tail = match[1];
  if (tail.includes(".")) return tail;
  const groups = tail.split(":");
  if (groups.length !== 2) return void 0;
  const hi = Number.parseInt(groups[0], 16);
  const lo = Number.parseInt(groups[1], 16);
  if (Number.isNaN(hi) || Number.isNaN(lo)) return void 0;
  return `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
}
__name(mappedIpv4, "mappedIpv4");
function isPrivateIp(url) {
  try {
    const hostname = new URL(url).hostname.replace(/^\[|\]$/g, "");
    const target = mappedIpv4(hostname) ?? hostname;
    return PRIVATE_IP_RANGES.some((range) => range.test(target));
  } catch (_e) {
    return false;
  }
}
__name(isPrivateIp, "isPrivateIp");
var INTERNAL_HOST_SUFFIXES = [".local", ".internal", ".lan", ".home.arpa"];
function isPrivateHost(url) {
  try {
    const hostname = new URL(url).hostname.toLowerCase();
    return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "host.docker.internal" || // Single-label hostnames (intranet, ci, printserver) are never public.
    // IPv6 literals are bracketed and dot-free but CAN be public — they
    // are classified by isPrivateIp below, not by this heuristic.
    !hostname.includes(".") && !hostname.startsWith("[") || INTERNAL_HOST_SUFFIXES.some((suffix) => hostname.endsWith(suffix)) || isPrivateIp(url);
  } catch {
    return false;
  }
}
__name(isPrivateHost, "isPrivateHost");
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
function isPermittedRedirect(originalUrl, redirectUrl) {
  try {
    const original = new URL(originalUrl);
    const redirect = new URL(redirectUrl);
    if (redirect.protocol !== original.protocol) return false;
    if (redirect.port !== original.port) return false;
    if (redirect.username || redirect.password) return false;
    const stripWww = /* @__PURE__ */ __name((hostname) => hostname.replace(/^www\./, ""), "stripWww");
    return stripWww(original.hostname) === stripWww(redirect.hostname);
  } catch {
    return false;
  }
}
__name(isPermittedRedirect, "isPermittedRedirect");
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([403, 429]);
var RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
  "ECONNRESET",
  "EAI_AGAIN",
  "UND_ERR_SOCKET"
]);
var RETRY_DELAY_MS = 500;
async function fetchWithPolicy(url, options) {
  const timeoutSignal = AbortSignal.timeout(options.timeoutMs);
  const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
  const abortError = /* @__PURE__ */ __name(() => {
    if (options.signal?.aborted) {
      return options.signal.reason instanceof Error ? options.signal.reason : new FetchError("Request aborted", "ABORT_ERR");
    }
    if (timeoutSignal.aborted) {
      return new FetchError(
        `Request timed out after ${options.timeoutMs}ms`,
        "ETIMEDOUT"
      );
    }
    return void 0;
  }, "abortError");
  let first;
  try {
    first = await fetchPolicyAttempt(url, options, signal, timeoutSignal);
  } catch (error) {
    if (error instanceof FetchError && error.code !== void 0 && RETRYABLE_ERROR_CODES.has(error.code) && !signal.aborted) {
      try {
        await delay(RETRY_DELAY_MS, signal);
      } catch {
        throw abortError() ?? error;
      }
      return fetchPolicyAttempt(url, options, signal, timeoutSignal);
    }
    throw error;
  }
  if (first.kind === "response" && RETRYABLE_STATUSES.has(first.status) && !signal.aborted) {
    try {
      await delay(RETRY_DELAY_MS, signal);
      return await fetchPolicyAttempt(url, options, signal, timeoutSignal);
    } catch {
      const aborted = abortError();
      if (aborted) throw aborted;
      return first;
    }
  }
  return first;
}
__name(fetchWithPolicy, "fetchWithPolicy");
async function fetchPolicyAttempt(url, options, signal, timeoutSignal) {
  const wrapAbort = /* @__PURE__ */ __name((error) => {
    if (options.signal?.aborted) {
      throw options.signal.reason instanceof Error ? options.signal.reason : new FetchError("Request aborted", "ABORT_ERR");
    }
    if (timeoutSignal.aborted) {
      throw new FetchError(
        `Request timed out after ${options.timeoutMs}ms`,
        "ETIMEDOUT"
      );
    }
    if (error instanceof FetchError) throw error;
    const code = getErrorCode(error) ?? (error instanceof Error ? getErrorCode(error.cause) : void 0);
    throw new FetchError(getErrorMessage(error), code);
  }, "wrapAbort");
  let currentUrl = url;
  for (let hop = 0; hop <= options.maxRedirects; hop++) {
    let response;
    try {
      response = await fetch(currentUrl, {
        signal,
        headers: options.headers,
        redirect: "manual"
      });
    } catch (error) {
      return wrapAbort(error);
    }
    if (REDIRECT_STATUSES.has(response.status)) {
      const location = response.headers.get("location");
      await response.body?.cancel().catch(() => {
      });
      if (!location) {
        throw new FetchError("Redirect response missing Location header");
      }
      let redirectUrl;
      try {
        redirectUrl = new URL(location, currentUrl).toString();
      } catch {
        throw new FetchError(
          `Redirect response has a malformed Location header: ${location}`
        );
      }
      if (!isPermittedRedirect(currentUrl, redirectUrl)) {
        return {
          kind: "cross-host-redirect",
          originalUrl: currentUrl,
          redirectUrl,
          status: response.status
        };
      }
      currentUrl = redirectUrl;
      continue;
    }
    if (response.status < 200 || response.status >= 300) {
      await response.body?.cancel().catch(() => {
      });
      return {
        kind: "response",
        status: response.status,
        statusText: response.statusText,
        contentType: response.headers.get("content-type") ?? "",
        contentDisposition: response.headers.get("content-disposition") ?? "",
        body: Buffer.alloc(0),
        finalUrl: currentUrl
      };
    }
    const contentLength = Number(response.headers.get("content-length"));
    if (Number.isFinite(contentLength) && contentLength > options.maxBytes) {
      await response.body?.cancel().catch(() => {
      });
      throw new FetchError(
        `Response too large: ${contentLength} bytes exceeds the ${options.maxBytes}-byte limit`,
        "EMSGSIZE"
      );
    }
    const chunks = [];
    let total = 0;
    if (response.body) {
      const reader = response.body.getReader();
      try {
        for (; ; ) {
          const { done, value } = await reader.read();
          if (done) break;
          total += value.byteLength;
          if (total > options.maxBytes) {
            throw new FetchError(
              `Response too large: exceeded the ${options.maxBytes}-byte limit while streaming`,
              "EMSGSIZE"
            );
          }
          chunks.push(value);
        }
      } catch (error) {
        await reader.cancel().catch(() => {
        });
        if (error instanceof FetchError) throw error;
        return wrapAbort(error);
      } finally {
        reader.releaseLock();
      }
    }
    return {
      kind: "response",
      status: response.status,
      statusText: response.statusText,
      contentType: response.headers.get("content-type") ?? "",
      contentDisposition: response.headers.get("content-disposition") ?? "",
      body: Buffer.concat(chunks, total),
      finalUrl: currentUrl
    };
  }
  throw new FetchError(
    `Too many redirects (exceeded ${options.maxRedirects})`,
    "EMAXREDIRECTS"
  );
}
__name(fetchPolicyAttempt, "fetchPolicyAttempt");
function getErrorCode(error) {
  if (!error || typeof error !== "object") {
    return void 0;
  }
  if ("code" in error && typeof error["code"] === "string") {
    return error["code"];
  }
  return void 0;
}
__name(getErrorCode, "getErrorCode");
function formatUnknownErrorMessage(error) {
  if (typeof error === "string") {
    return error;
  }
  if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") {
    return String(error);
  }
  if (error instanceof Error) {
    return error.message;
  }
  if (!error || typeof error !== "object") {
    return void 0;
  }
  const message = error["message"];
  if (typeof message === "string") {
    return message;
  }
  return void 0;
}
__name(formatUnknownErrorMessage, "formatUnknownErrorMessage");
function formatErrorCause(error) {
  if (!(error instanceof Error)) {
    return void 0;
  }
  const cause = error.cause;
  if (!cause) {
    return void 0;
  }
  const causeCode = getErrorCode(cause);
  const causeMessage = formatUnknownErrorMessage(cause);
  if (!causeCode && !causeMessage) {
    return void 0;
  }
  if (causeCode && causeMessage && !causeMessage.includes(causeCode)) {
    return `${causeCode}: ${causeMessage}`;
  }
  return causeMessage ?? causeCode;
}
__name(formatErrorCause, "formatErrorCause");
function formatFetchErrorForUser(error, options = {}) {
  const errorMessage = getErrorMessage(error);
  const code = error instanceof Error ? getErrorCode(error.cause) ?? getErrorCode(error) : getErrorCode(error);
  const cause = formatErrorCause(error);
  const fullErrorMessage = [
    errorMessage,
    cause ? `(cause: ${cause})` : void 0
  ].filter(Boolean).join(" ");
  const shouldShowFetchHints = errorMessage.toLowerCase().includes("fetch failed") || code != null && FETCH_TROUBLESHOOTING_ERROR_CODES.has(code);
  const shouldShowTlsHint = code != null && TLS_ERROR_CODES.has(code);
  if (!shouldShowFetchHints) {
    return fullErrorMessage;
  }
  const hintLines = [
    "",
    "Troubleshooting:",
    ...options.url ? [`- Confirm you can reach ${options.url} from this machine.`] : [],
    "- If you are behind a proxy, pass `--proxy <url>` (or set `proxy` in settings).",
    ...shouldShowTlsHint ? isTlsVerificationDisabled() ? [
      "- TLS verification is already disabled (`--insecure` / `QWEN_TLS_INSECURE`), so this is likely a network or protocol issue rather than a certificate trust problem."
    ] : [
      "- If your network uses a corporate TLS inspection CA, set `NODE_EXTRA_CA_CERTS` to your CA bundle.",
      "- For a trusted self-signed endpoint, pass `--insecure` (or set `QWEN_TLS_INSECURE=1`) to skip certificate verification."
    ] : []
  ];
  return `${fullErrorMessage}${hintLines.join("\n")}`;
}
__name(formatFetchErrorForUser, "formatFetchErrorForUser");

export {
  classifyRetryError,
  isFallbackEligible,
  isTransientCapacityError,
  isUnattendedMode,
  delay,
  retryWithBackoff,
  isConnectionLevelError,
  isPrivateHost,
  fetchWithPolicy,
  formatFetchErrorForUser
};
/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
