"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/browser/index.ts
var browser_exports = {};
__export(browser_exports, {
  BROWSER_SYSTEM_PROMPT: () => BROWSER_SYSTEM_PROMPT,
  BROWSER_TOOL_DESCRIPTION: () => BROWSER_TOOL_DESCRIPTION,
  BrowserClient: () => BrowserClient,
  LIVE_PRESETS: () => LIVE_PRESETS,
  MorphAPIError: () => MorphAPIError,
  MorphAuthenticationError: () => MorphAuthenticationError,
  MorphError: () => MorphError,
  MorphNotFoundError: () => MorphNotFoundError,
  MorphProfileLimitError: () => MorphProfileLimitError,
  MorphRateLimitError: () => MorphRateLimitError,
  MorphValidationError: () => MorphValidationError,
  ProfilesClient: () => ProfilesClient,
  anthropic: () => anthropic_exports,
  buildEmbedCode: () => buildEmbedCode,
  buildLiveIframe: () => buildLiveIframe,
  buildLiveUrl: () => buildLiveUrl,
  checkHealth: () => checkHealth,
  executeBrowserTask: () => executeBrowserTask,
  executeWithRecording: () => executeWithRecording,
  gemini: () => gemini_exports,
  getErrors: () => getErrors,
  getRecording: () => getRecording,
  getWebp: () => getWebp,
  openai: () => openai_exports,
  parseAPIError: () => parseAPIError,
  vercel: () => vercel_exports,
  waitForRecording: () => waitForRecording
});
module.exports = __toCommonJS(browser_exports);

// package.json
var package_default = {
  name: "@morphllm/morphsdk",
  version: "0.2.168",
  description: "TypeScript SDK and CLI for Morph Fast Apply integration",
  type: "module",
  main: "./dist/index.cjs",
  module: "./dist/index.js",
  types: "./dist/index.d.ts",
  exports: {
    ".": {
      types: "./dist/index.d.ts",
      import: "./dist/index.js",
      require: "./dist/index.cjs"
    },
    "./logger": {
      types: "./dist/logger.d.ts",
      import: "./dist/logger.js",
      require: "./dist/logger.cjs"
    },
    "./edge": {
      types: "./dist/edge.d.ts",
      import: "./dist/edge.js",
      require: "./dist/edge.cjs"
    },
    "./tools/warp-grep": {
      types: "./dist/tools/warp_grep/index.d.ts",
      import: "./dist/tools/warp_grep/index.js",
      require: "./dist/tools/warp_grep/index.cjs"
    },
    "./tools/warp-grep/openai": {
      types: "./dist/tools/warp_grep/openai.d.ts",
      import: "./dist/tools/warp_grep/openai.js",
      require: "./dist/tools/warp_grep/openai.cjs"
    },
    "./tools/warp-grep/anthropic": {
      types: "./dist/tools/warp_grep/anthropic.d.ts",
      import: "./dist/tools/warp_grep/anthropic.js",
      require: "./dist/tools/warp_grep/anthropic.cjs"
    },
    "./tools/warp-grep/vercel": {
      types: "./dist/tools/warp_grep/vercel.d.ts",
      import: "./dist/tools/warp_grep/vercel.js",
      require: "./dist/tools/warp_grep/vercel.cjs"
    },
    "./tools/warp-grep/client": {
      types: "./dist/tools/warp_grep/client.d.ts",
      import: "./dist/tools/warp_grep/client.js",
      require: "./dist/tools/warp_grep/client.cjs"
    },
    "./tools/warp-grep/gemini": {
      types: "./dist/tools/warp_grep/gemini.d.ts",
      import: "./dist/tools/warp_grep/gemini.js",
      require: "./dist/tools/warp_grep/gemini.cjs"
    },
    "./tools/warp-grep/harness": {
      types: "./dist/tools/warp_grep/harness.d.ts",
      import: "./dist/tools/warp_grep/harness.js",
      require: "./dist/tools/warp_grep/harness.cjs"
    },
    "./tools/fastapply": {
      types: "./dist/tools/fastapply/index.d.ts",
      import: "./dist/tools/fastapply/index.js",
      require: "./dist/tools/fastapply/index.cjs"
    },
    "./tools/fastapply/anthropic": {
      types: "./dist/tools/fastapply/anthropic.d.ts",
      import: "./dist/tools/fastapply/anthropic.js",
      require: "./dist/tools/fastapply/anthropic.cjs"
    },
    "./tools/fastapply/openai": {
      types: "./dist/tools/fastapply/openai.d.ts",
      import: "./dist/tools/fastapply/openai.js",
      require: "./dist/tools/fastapply/openai.cjs"
    },
    "./tools/fastapply/vercel": {
      types: "./dist/tools/fastapply/vercel.d.ts",
      import: "./dist/tools/fastapply/vercel.js",
      require: "./dist/tools/fastapply/vercel.cjs"
    },
    "./tools/codebase-search": {
      types: "./dist/tools/codebase_search/index.d.ts",
      import: "./dist/tools/codebase_search/index.js",
      require: "./dist/tools/codebase_search/index.cjs"
    },
    "./tools/codebase-search/anthropic": {
      types: "./dist/tools/codebase_search/anthropic.d.ts",
      import: "./dist/tools/codebase_search/anthropic.js",
      require: "./dist/tools/codebase_search/anthropic.cjs"
    },
    "./tools/codebase-search/openai": {
      types: "./dist/tools/codebase_search/openai.d.ts",
      import: "./dist/tools/codebase_search/openai.js",
      require: "./dist/tools/codebase_search/openai.cjs"
    },
    "./tools/codebase-search/vercel": {
      types: "./dist/tools/codebase_search/vercel.d.ts",
      import: "./dist/tools/codebase_search/vercel.js",
      require: "./dist/tools/codebase_search/vercel.cjs"
    },
    "./tools/git": {
      types: "./dist/git/index.d.ts",
      import: "./dist/git/index.js",
      require: "./dist/git/index.cjs"
    },
    "./tools/browser": {
      types: "./dist/tools/browser/index.d.ts",
      import: "./dist/tools/browser/index.js",
      require: "./dist/tools/browser/index.cjs"
    },
    "./tools/browser/anthropic": {
      types: "./dist/tools/browser/anthropic.d.ts",
      import: "./dist/tools/browser/anthropic.js",
      require: "./dist/tools/browser/anthropic.cjs"
    },
    "./tools/browser/openai": {
      types: "./dist/tools/browser/openai.d.ts",
      import: "./dist/tools/browser/openai.js",
      require: "./dist/tools/browser/openai.cjs"
    },
    "./tools/browser/vercel": {
      types: "./dist/tools/browser/vercel.d.ts",
      import: "./dist/tools/browser/vercel.js",
      require: "./dist/tools/browser/vercel.cjs"
    },
    "./tools/browser/profiles": {
      types: "./dist/tools/browser/profiles/index.d.ts",
      import: "./dist/tools/browser/profiles/index.js",
      require: "./dist/tools/browser/profiles/index.cjs"
    },
    "./modelrouter": {
      types: "./dist/modelrouter/index.d.ts",
      import: "./dist/modelrouter/index.js",
      require: "./dist/modelrouter/index.cjs"
    },
    "./tools/compact": {
      types: "./dist/tools/compact/index.d.ts",
      import: "./dist/tools/compact/index.js",
      require: "./dist/tools/compact/index.cjs"
    },
    "./subagents": {
      types: "./dist/subagents/index.d.ts",
      import: "./dist/subagents/index.js",
      require: "./dist/subagents/index.cjs"
    },
    "./subagents/vercel": {
      types: "./dist/subagents/vercel.d.ts",
      import: "./dist/subagents/vercel.js",
      require: "./dist/subagents/vercel.cjs"
    },
    "./subagents/anthropic": {
      types: "./dist/subagents/anthropic.d.ts",
      import: "./dist/subagents/anthropic.js",
      require: "./dist/subagents/anthropic.cjs"
    }
  },
  files: [
    "dist/**/*.js",
    "dist/**/*.cjs",
    "dist/**/*.d.ts",
    "dist/**/*.map",
    "!dist/**/__tests__/**",
    "!dist/**/*.test.*"
  ],
  scripts: {
    build: "tsup version.ts index.ts edge.ts client.ts tools/index.ts tools/fastapply/index.ts tools/fastapply/core.ts tools/fastapply/apply.ts tools/fastapply/types.ts tools/fastapply/prompts.ts tools/fastapply/anthropic.ts tools/fastapply/openai.ts tools/fastapply/vercel.ts tools/codebase_search/index.ts tools/codebase_search/core.ts tools/codebase_search/types.ts tools/codebase_search/prompts.ts tools/codebase_search/anthropic.ts tools/codebase_search/openai.ts tools/codebase_search/vercel.ts tools/warp_grep/index.ts tools/warp_grep/client.ts tools/warp_grep/openai.ts tools/warp_grep/anthropic.ts tools/warp_grep/vercel.ts tools/warp_grep/gemini.ts tools/warp_grep/harness.ts tools/warp_grep/agent/config.ts tools/warp_grep/agent/parser.ts tools/warp_grep/agent/runner.ts tools/warp_grep/agent/types.ts tools/warp_grep/agent/formatter.ts tools/warp_grep/providers/types.ts tools/warp_grep/providers/local.ts tools/warp_grep/providers/remote.ts tools/warp_grep/providers/code_storage_http.ts tools/warp_grep/tools/grep.ts tools/warp_grep/tools/analyse.ts tools/warp_grep/tools/read.ts tools/warp_grep/tools/finish.ts tools/warp_grep/utils/paths.ts tools/warp_grep/utils/github.ts tools/warp_grep/utils/ripgrep.ts tools/warp_grep/utils/format.ts tools/warp_grep/utils/files.ts git/index.ts git/client.ts git/config.ts git/types.ts tools/browser/index.ts tools/browser/core.ts tools/browser/types.ts tools/browser/prompts.ts tools/browser/anthropic.ts tools/browser/openai.ts tools/browser/vercel.ts tools/browser/live.ts tools/browser/errors.ts tools/browser/profiles/index.ts tools/browser/profiles/core.ts tools/browser/profiles/types.ts modelrouter/index.ts modelrouter/core.ts modelrouter/types.ts tools/compact/index.ts tools/compact/core.ts tools/compact/types.ts tools/utils/resilience.ts subagents/index.ts subagents/types.ts subagents/prompts.ts subagents/vercel.ts subagents/anthropic.ts --format esm,cjs --sourcemap --clean --dts --dts-resolve",
    prepare: "npm run build",
    typecheck: "tsc --noEmit",
    lint: "eslint .",
    test: "vitest run",
    "test:watch": "vitest watch",
    "test:anthropic": "vitest run anthropic",
    "test:openai": "vitest run openai",
    "test:vercel": "vitest run vercel",
    "test:git": "vitest run git",
    "test:browser": "vitest run browser",
    "test:agent": "npx tsx tests/fullAgentTest.ts",
    "test:integration": "npx tsx tests/fullIntegrationTest.ts",
    "test:e2e": "vitest run --config vitest.e2e.config.ts",
    "release:patch": "npm version patch && npm publish",
    "release:minor": "npm version minor && npm publish",
    "release:major": "npm version major && npm publish"
  },
  keywords: [
    "morph",
    "fast-apply",
    "cli",
    "sdk",
    "edit-file"
  ],
  engines: {
    node: ">=18"
  },
  license: "MIT",
  dependencies: {
    "@vscode/ripgrep": "^1.17.0",
    ai: ">=5.0.0",
    diff: "^7.0.0",
    "isomorphic-git": "^1.25.10",
    openai: "^4.52.7",
    zod: ">=3.23.0"
  },
  devDependencies: {
    "@ai-sdk/anthropic": "^2.0.70",
    "@ai-sdk/openai": "^2.0.35",
    "@anthropic-ai/sdk": "^0.30.1",
    "@google/generative-ai": "^0.24.1",
    "@types/diff": "^7.0.2",
    "@types/node": "^20.14.10",
    "@typescript-eslint/eslint-plugin": "^7.18.0",
    "@typescript-eslint/parser": "^7.18.0",
    dotenv: "^16.4.5",
    eslint: "^8.57.0",
    shx: "^0.3.4",
    tsup: "^8.5.0",
    tsx: "^4.16.2",
    typescript: "^5.5.4",
    vitest: "^2.1.6"
  },
  peerDependencies: {
    "@anthropic-ai/sdk": ">=0.25.0",
    "@google/generative-ai": ">=0.21.0",
    ai: ">=5.0.0",
    zod: ">=3.23.0"
  },
  peerDependenciesMeta: {
    "@anthropic-ai/sdk": {
      optional: true
    },
    "@google/generative-ai": {
      optional: true
    },
    ai: {
      optional: true
    },
    zod: {
      optional: true
    }
  },
  publishConfig: {
    access: "public"
  }
};

// version.ts
var SDK_VERSION = package_default.version;

// tools/utils/resilience.ts
var DEFAULT_RETRY_CONFIG = {
  maxRetries: 3,
  initialDelay: 1e3,
  maxDelay: 3e4,
  backoffMultiplier: 2,
  retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
};
async function fetchWithRetry(url, options, retryConfig = {}) {
  const {
    maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
    initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
    maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
    backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
    retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
    onRetry
  } = retryConfig;
  let lastError = null;
  let delay = initialDelay;
  options = { ...options, headers: { "X-Morph-SDK-Version": SDK_VERSION, ...options.headers } };
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      if (response.status === 429 || response.status === 503) {
        if (attempt < maxRetries) {
          const retryAfter = response.headers.get("Retry-After");
          const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
          const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
          if (onRetry) {
            onRetry(attempt + 1, error);
          }
          await sleep(waitTime);
          delay *= backoffMultiplier;
          continue;
        }
      }
      return response;
    } catch (error) {
      lastError = error;
      const isRetryable = retryableErrors.some(
        (errType) => lastError?.message?.includes(errType)
      );
      if (!isRetryable || attempt === maxRetries) {
        throw lastError;
      }
      const waitTime = Math.min(delay, maxDelay);
      if (onRetry) {
        onRetry(attempt + 1, lastError);
      }
      await sleep(waitTime);
      delay *= backoffMultiplier;
    }
  }
  throw lastError || new Error("Max retries exceeded");
}
async function withTimeout(promise, timeoutMs, errorMessage) {
  let timeoutId;
  const timeoutPromise = new Promise((_, reject) => {
    timeoutId = setTimeout(() => {
      reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
    }, timeoutMs);
  });
  try {
    const result = await Promise.race([promise, timeoutPromise]);
    clearTimeout(timeoutId);
    return result;
  } catch (error) {
    clearTimeout(timeoutId);
    throw error;
  }
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// logger.ts
var MorphLogger = class {
  enabled;
  fileStream;
  /** Resolves once the file stream is initialized (or immediately if no file logging). */
  ready;
  constructor() {
    this.enabled = typeof process !== "undefined" && (process.env.MORPH_DEBUG === "1" || !!process.env.MORPH_LOG_FILE);
    this.fileStream = null;
    const f = typeof process !== "undefined" ? process.env.MORPH_LOG_FILE : void 0;
    if (f) {
      this.ready = import("fs").then((fs) => {
        this.fileStream = fs.createWriteStream(f, { flags: "a" });
      }).catch(() => {
      });
    } else {
      this.ready = Promise.resolve();
    }
  }
  debug(component, msg, data) {
    this._log("debug", component, msg, data);
  }
  info(component, msg, data) {
    this._log("info", component, msg, data);
  }
  warn(component, msg, data) {
    this._log("warn", component, msg, data);
  }
  error(component, msg, data) {
    this._log("error", component, msg, data);
  }
  enable() {
    this.enabled = true;
  }
  get isEnabled() {
    return this.enabled;
  }
  _log(level, component, msg, data) {
    if (level !== "error" && !this.enabled) return;
    const ts = (/* @__PURE__ */ new Date()).toISOString();
    const prefix = `[${ts}] [${level.toUpperCase()}] [${component}]`;
    console.error(data ? `${prefix} ${msg} ${JSON.stringify(data)}` : `${prefix} ${msg}`);
    this.fileStream?.write(JSON.stringify({ ts, level, component, msg, ...data && { data } }) + "\n");
  }
};
var logger = new MorphLogger();

// tools/browser/live.ts
var LIVE_PRESETS = {
  /** Read-only monitoring (no interaction) */
  readonly: { interactive: false },
  /** Interactive control (human-in-the-loop) */
  interactive: { interactive: true },
  /** Watch-only without controls */
  monitoring: { interactive: false, showControls: false }
};
function buildLiveUrl(debugUrl, options = {}) {
  if (!debugUrl) {
    throw new Error(
      "debugUrl is required. Ensure your backend returns debugUrl in the task response. Contact support@morphllm.com if you need help."
    );
  }
  const normalized = normalizeLiveUrl(debugUrl);
  const url = new URL(normalized);
  if (options.interactive !== void 0) {
    url.searchParams.set("interactive", String(options.interactive));
  }
  if (options.theme) {
    url.searchParams.set("theme", options.theme);
  }
  if (options.showControls !== void 0) {
    url.searchParams.set("showControls", String(options.showControls));
  }
  if (options.pageId) {
    url.searchParams.set("pageId", options.pageId);
  }
  if (options.pageIndex) {
    url.searchParams.set("pageIndex", options.pageIndex);
  }
  return url.toString();
}
function cdpToHttps(wsUrl) {
  return wsUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://");
}
function normalizeLiveUrl(debugUrl) {
  const trimmed = debugUrl.trim();
  if (!trimmed) return trimmed;
  if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
    return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;
  }
  let url;
  try {
    url = new URL(trimmed);
  } catch {
    return trimmed;
  }
  const wssParam = url.searchParams.get("wss");
  if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
    url.searchParams.set("wss", cdpToHttps(wssParam));
  }
  return url.toString();
}
function buildLiveIframe(debugUrl, options = {}) {
  const {
    width = "100%",
    height = "600px",
    style = "",
    className = "",
    ...sessionOptions
  } = options;
  const src = buildLiveUrl(debugUrl, sessionOptions);
  const widthStr = typeof width === "number" ? `${width}px` : width;
  const heightStr = typeof height === "number" ? `${height}px` : height;
  const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;
  const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;
  const attributes = [
    `src="${src}"`,
    `style="${fullStyle}"`
  ];
  if (className) {
    attributes.push(`class="${className}"`);
  }
  return `<iframe ${attributes.join(" ")}></iframe>`;
}
function buildEmbedCode(debugUrl, options = {}) {
  const iframe = buildLiveIframe(debugUrl, options);
  return `<!-- Embed Morph Live Session -->
${iframe}`;
}
function resolvePreset(optionsOrPreset) {
  if (!optionsOrPreset) {
    return {};
  }
  if (typeof optionsOrPreset === "string") {
    const preset = LIVE_PRESETS[optionsOrPreset];
    if (!preset) {
      throw new Error(
        `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(", ")}`
      );
    }
    return preset;
  }
  return optionsOrPreset;
}

// tools/browser/errors.ts
var MorphError = class extends Error {
  /** Error code for programmatic handling */
  code;
  /** Original cause of the error, if any */
  cause;
  constructor(message, code, cause) {
    super(message);
    this.name = "MorphError";
    this.code = code;
    this.cause = cause;
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor);
    }
  }
  /**
   * Returns a JSON representation of the error for logging.
   */
  toJSON() {
    return {
      name: this.name,
      message: this.message,
      code: this.code,
      cause: this.cause?.message
    };
  }
};
var MorphValidationError = class extends MorphError {
  /** The field that failed validation */
  field;
  constructor(message, field) {
    super(message, "validation_error");
    this.name = "MorphValidationError";
    this.field = field;
  }
  toJSON() {
    return {
      ...super.toJSON(),
      field: this.field
    };
  }
};
var MorphAPIError = class extends MorphError {
  /** HTTP status code */
  statusCode;
  /** Request ID for debugging (if available) */
  requestId;
  /** Raw response body */
  rawResponse;
  constructor(message, code, statusCode, options) {
    super(message, code, options?.cause);
    this.name = "MorphAPIError";
    this.statusCode = statusCode;
    this.requestId = options?.requestId;
    this.rawResponse = options?.rawResponse;
  }
  toJSON() {
    return {
      ...super.toJSON(),
      statusCode: this.statusCode,
      requestId: this.requestId
    };
  }
};
var MorphAuthenticationError = class extends MorphAPIError {
  constructor(message = "Authentication required. Please provide a valid API key.") {
    super(message, "authentication_required", 401);
    this.name = "MorphAuthenticationError";
  }
};
var MorphRateLimitError = class extends MorphAPIError {
  /** When the rate limit resets (Unix timestamp) */
  resetAt;
  /** Number of seconds until reset */
  retryAfter;
  constructor(message = "Rate limit exceeded. Please retry later.", options) {
    super(message, "rate_limit_exceeded", 429, { requestId: options?.requestId });
    this.name = "MorphRateLimitError";
    this.resetAt = options?.resetAt;
    this.retryAfter = options?.retryAfter;
  }
  toJSON() {
    return {
      ...super.toJSON(),
      resetAt: this.resetAt,
      retryAfter: this.retryAfter
    };
  }
};
var MorphNotFoundError = class extends MorphAPIError {
  /** The type of resource that was not found */
  resourceType;
  /** The ID of the resource that was not found */
  resourceId;
  constructor(resourceType, resourceId) {
    const message = resourceId ? `${resourceType} '${resourceId}' not found` : `${resourceType} not found`;
    super(message, "resource_not_found", 404);
    this.name = "MorphNotFoundError";
    this.resourceType = resourceType;
    this.resourceId = resourceId;
  }
  toJSON() {
    return {
      ...super.toJSON(),
      resourceType: this.resourceType,
      resourceId: this.resourceId
    };
  }
};
var MorphProfileLimitError = class extends MorphAPIError {
  /** Current number of profiles */
  currentCount;
  /** Maximum allowed profiles for the plan */
  maxAllowed;
  constructor(message = "Profile limit exceeded for your plan.", options) {
    super(message, "profile_limit_exceeded", 403, { requestId: options?.requestId });
    this.name = "MorphProfileLimitError";
    this.currentCount = options?.currentCount;
    this.maxAllowed = options?.maxAllowed;
  }
  toJSON() {
    return {
      ...super.toJSON(),
      currentCount: this.currentCount,
      maxAllowed: this.maxAllowed
    };
  }
};
function parseAPIError(statusCode, responseText, requestId) {
  let errorData = {};
  try {
    errorData = JSON.parse(responseText);
  } catch {
  }
  const message = errorData.detail || errorData.message || responseText || "Unknown error";
  const code = errorData.code;
  switch (statusCode) {
    case 401:
      return new MorphAuthenticationError(message);
    case 403:
      if (code === "profile_limit_exceeded" || message.toLowerCase().includes("limit")) {
        return new MorphProfileLimitError(message, { requestId });
      }
      return new MorphAPIError(message, "insufficient_permissions", statusCode, { requestId, rawResponse: responseText });
    case 404:
      if (message.toLowerCase().includes("profile")) {
        return new MorphNotFoundError("Profile", void 0);
      }
      if (message.toLowerCase().includes("session")) {
        return new MorphNotFoundError("Session", void 0);
      }
      return new MorphAPIError(message, "resource_not_found", statusCode, { requestId, rawResponse: responseText });
    case 429:
      return new MorphRateLimitError(message, { requestId });
    case 422:
      return new MorphAPIError(message, "validation_error", statusCode, { requestId, rawResponse: responseText });
    case 500:
    case 502:
    case 503:
    case 504:
      return new MorphAPIError(message, "service_unavailable", statusCode, { requestId, rawResponse: responseText });
    default:
      return new MorphAPIError(message, "network_error", statusCode, { requestId, rawResponse: responseText });
  }
}

// tools/browser/profiles/types.ts
function transformProfile(api) {
  return {
    id: api.id,
    name: api.name,
    repoId: api.repo_id,
    cookieDomains: api.cookie_domains,
    lastUsedAt: api.last_used_at,
    createdAt: api.created_at,
    updatedAt: api.updated_at
  };
}
function transformCreateInput(input) {
  return {
    name: input.name,
    repo_id: input.repoId
  };
}
function transformSession(api) {
  return {
    sessionId: api.session_id,
    debugUrl: api.debug_url || ""
  };
}
function transformSaveInput(input) {
  return {
    session_id: input.sessionId,
    profile_id: input.profileId
  };
}
function transformStateResponse(api) {
  return {
    profileId: api.profile_id,
    stateUrl: api.state_url,
    expiresIn: api.expires_in
  };
}

// tools/browser/profiles/core.ts
var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
var ProfilesClient = class {
  config;
  constructor(config) {
    this.config = config;
  }
  /**
    * Create a new browser profile and immediately start a live session.
    *
    * @param input - Profile creation parameters
    * @returns Profile setup handle with live URL + save()
    * @throws {MorphValidationError} If input validation fails
    * @throws {MorphProfileLimitError} If profile limit is exceeded
    * @throws {MorphAuthenticationError} If API key is missing or invalid
    *
    * @example
    * ```typescript
  * const setup = await morph.browser.profiles.createProfile({
  *   name: 'LinkedIn Production',
  *   repoId: 'owner/repo'
  * });
  * console.log(setup.session.debugUrl);
  * await setup.save();
    * ```
    */
  async createProfile(input) {
    return createProfile(input, this.config);
  }
  /**
   * List all profiles for the authenticated user.
   *
   * @param repoId - Optional repository ID to filter by
   * @returns Array of profiles
   *
   * @example
   * ```typescript
   * // List all profiles
   * const allProfiles = await morph.browser.profiles.listProfiles();
   *
   * // List profiles for a specific repo
   * const repoProfiles = await morph.browser.profiles.listProfiles('owner/repo');
   * ```
   */
  async listProfiles(repoId) {
    return listProfiles(this.config, repoId);
  }
  /**
   * Get a profile by ID with convenience methods.
   *
   * @param id - Profile ID
   * @returns Profile with attached methods
   * @throws {MorphNotFoundError} If profile is not found
   *
   * @example
   * ```typescript
   * const profile = await morph.browser.profiles.getProfile('profile-id');
   * const state = await profile.getState();
   * await profile.delete();
   * ```
   */
  async getProfile(id) {
    return getProfile(id, this.config);
  }
  /**
   * Update a profile by opening a live session (no rename).
   *
   * @param id - Profile ID
   * @returns Profile setup handle with live URL + save()
   */
  async updateProfile(id) {
    return updateProfile(id, this.config);
  }
  /**
   * Delete a profile.
   *
   * @param id - Profile ID
   * @throws {MorphNotFoundError} If profile is not found
   */
  async deleteProfile(id) {
    return deleteProfile(id, this.config);
  }
  /**
   * Start a browser session for profile setup.
   *
   * Returns a live URL where the user can sign into accounts.
   * After signing in, call `saveSession` to persist the state.
   *
   * @param input - Optional session parameters
   * @returns Session with debug URL
   *
   * @example
   * ```typescript
   * const session = await morph.browser.profiles.startSession();
   * console.log('Sign in at:', session.debugUrl);
   * // Open debugUrl in browser, user signs in...
   * await morph.browser.profiles.saveSession(session.sessionId, profile.id);
   * ```
   */
  async startSession(input) {
    return startProfileSession(this.config, input);
  }
  /**
   * Save browser state from a session to a profile.
   *
   * Call this after the user is done signing into accounts.
   * Extracts cookies, localStorage, and sessionStorage.
   *
   * @param sessionId - Browser session ID from startSession
   * @param profileId - Profile ID to save state to
   * @returns Updated profile with cookie domains
   */
  async saveSession(sessionId, profileId) {
    return saveProfileSession({ sessionId, profileId }, this.config);
  }
  /**
   * List available repo IDs (discovery).
   *
   * @returns Repo summaries with profile counts
   */
  async listRepos() {
    return listRepos(this.config);
  }
  /**
   * Get the presigned URL for a profile's state.
   *
   * Use this to download the raw state JSON for debugging
   * or to restore state manually.
   *
   * @param profileId - Profile ID
   * @returns State URL with expiry information
   */
  async getProfileState(profileId) {
    return getProfileState(profileId, this.config);
  }
};
function validateCreateInput(input) {
  if (!input.name || typeof input.name !== "string") {
    throw new MorphValidationError("name is required", "name");
  }
  const trimmedName = input.name.trim();
  if (trimmedName.length === 0) {
    throw new MorphValidationError("name cannot be empty", "name");
  }
  if (trimmedName.length > 100) {
    throw new MorphValidationError("name must be 100 characters or less", "name");
  }
  if (!input.repoId || typeof input.repoId !== "string") {
    throw new MorphValidationError("repoId is required", "repoId");
  }
  if (input.repoId.trim().length === 0) {
    throw new MorphValidationError("repoId cannot be empty", "repoId");
  }
}
function validateId(id, fieldName) {
  if (!id || typeof id !== "string") {
    throw new MorphValidationError(`${fieldName} is required`, fieldName);
  }
  if (id.trim().length === 0) {
    throw new MorphValidationError(`${fieldName} cannot be empty`, fieldName);
  }
}
async function createProfile(input, config = {}) {
  validateCreateInput(input);
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(transformCreateInput(input))
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  const profile = transformProfile(apiProfile);
  const session = await startProfileSession(config, { profileId: profile.id });
  return buildProfileSetup(profile, session, config);
}
async function listProfiles(config = {}, repoId) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const url = repoId ? `${apiUrl}/profiles?repo_id=${encodeURIComponent(repoId)}` : `${apiUrl}/profiles`;
  const response = await fetchWithRetry(
    url,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const data = await response.json();
  return data.profiles.map(transformProfile);
}
async function getProfile(id, config = {}) {
  validateId(id, "id");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  const profile = transformProfile(apiProfile);
  return {
    ...profile,
    getState: () => getProfileState(id, config),
    delete: () => deleteProfile(id, config)
  };
}
async function updateProfile(id, config = {}) {
  validateId(id, "id");
  const profile = await fetchProfile(id, config);
  const session = await startProfileSession(config, { profileId: profile.id });
  return buildProfileSetup(profile, session, config);
}
async function deleteProfile(id, config = {}) {
  validateId(id, "id");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "DELETE", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
}
async function startProfileSession(config = {}, input) {
  if (!config.apiKey) {
    throw new MorphAuthenticationError();
  }
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const body = input?.profileId ? { profile_id: input.profileId } : {};
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/session/start`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(body)
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiSession = await response.json();
  return transformSession(apiSession);
}
async function saveProfileSession(input, config = {}) {
  validateId(input.sessionId, "sessionId");
  validateId(input.profileId, "profileId");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/session/save`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(transformSaveInput(input))
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  return transformProfile(apiProfile);
}
async function listRepos(config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/repos`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const data = await response.json();
  const repos = Array.isArray(data?.repos) ? data.repos : [];
  return repos.map((repo) => ({
    repoId: repo.repo_id,
    repoFullName: repo.repo_full_name,
    profileCount: repo.profile_count ?? 0
  }));
}
async function getProfileState(profileId, config = {}) {
  validateId(profileId, "profileId");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(profileId)}/state`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiState = await response.json();
  return transformStateResponse(apiState);
}
function buildHeaders(config) {
  const headers = { "Content-Type": "application/json" };
  if (config.apiKey) {
    headers["Authorization"] = `Bearer ${config.apiKey}`;
  }
  return headers;
}
async function fetchProfile(id, config) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  return transformProfile(apiProfile);
}
function buildProfileSetup(profile, session, config) {
  return {
    profile,
    session,
    save: () => saveProfileSession({ sessionId: session.sessionId, profileId: profile.id }, config)
  };
}

// tools/browser/core.ts
var DEFAULT_CONFIG = {
  apiUrl: process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com",
  timeout: 1e6,
  // 10 minutes for complex tasks
  debug: false
};
var BrowserClient = class {
  config;
  /**
   * Profile management - create and manage browser profiles for storing login state.
   */
  profiles;
  constructor(config = {}) {
    this.config = {
      ...DEFAULT_CONFIG,
      ...config
    };
    this.profiles = new ProfilesClient(this.config);
  }
  /**
   * Execute a browser automation task
   */
  async execute(input) {
    return executeBrowserTask(input, this.config);
  }
  async createTask(input) {
    const apiUrl = this.config.apiUrl || DEFAULT_CONFIG.apiUrl;
    const debug = this.config.debug || false;
    const hasTask = typeof input.task === "string" && input.task.trim().length > 0;
    const hasDiff = typeof input.diff === "string" && input.diff.trim().length > 0;
    if (!hasTask && !hasDiff) {
      throw new Error('Browser task requires either "task" (natural language) or "diff" (PR-review planning)');
    }
    logger.debug("Browser", "create_task", { task: (input.task ?? "").slice(0, 100), url: input.url, endpoint: `${apiUrl}/browser-task/async` });
    const headers = { "Content-Type": "application/json" };
    if (this.config.apiKey) headers["Authorization"] = `Bearer ${this.config.apiKey}`;
    const response = await fetch(`${apiUrl}/browser-task/async`, {
      method: "POST",
      headers,
      body: JSON.stringify({
        task: input.task,
        diff: input.diff,
        url: input.url,
        max_steps: input.maxSteps ?? 10,
        model: input.model ?? "morph-computer-use-v0",
        viewport_width: input.viewportWidth ?? 1280,
        viewport_height: input.viewportHeight ?? 720,
        external_id: input.externalId,
        repo_id: input.repoId,
        repo_full_name: input.repoFullName,
        commit_id: input.commitId,
        record_video: input.recordVideo ?? false,
        video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
        video_height: input.videoHeight ?? input.viewportHeight ?? 720,
        allow_resizing: input.allowResizing ?? false,
        structured_output: "schema" in input ? stringifyStructuredOutput(input.schema) : void 0,
        auth: input.auth,
        profile_id: input.profileId,
        force_query_params: input.forceQueryParams
      })
    });
    if (!response.ok) {
      const errorText = await response.text().catch(() => response.statusText);
      logger.error("Browser", "create_task_error", { status: response.status, error: errorText });
      throw new Error(`HTTP ${response.status}: ${errorText}`);
    }
    const result = mapTaskResult(await response.json());
    logger.debug("Browser", "task_created", { recording_id: result.recordingId, task_id: result.taskId, debug_url: !!result.debugUrl });
    if ("schema" in input) {
      return wrapTaskResponseWithSchema(result, this.config, input.schema);
    } else {
      return wrapTaskResponse(result, this.config);
    }
  }
  /**
   * Execute task with recording and wait for video to be ready
   */
  async executeWithRecording(input) {
    return executeWithRecording(input, this.config);
  }
  /**
   * Get recording status and URLs
   */
  async getRecording(recordingId) {
    return getRecording(recordingId, this.config);
  }
  /**
   * Wait for recording to complete with automatic polling
   */
  async waitForRecording(recordingId, options) {
    return waitForRecording(recordingId, this.config, options);
  }
  /**
   * Get errors from recording with screenshots
   */
  async getErrors(recordingId) {
    return getErrors(recordingId, this.config);
  }
  /**
   * Get animated WebP preview of recording
   */
  async getWebp(recordingId, options) {
    return getWebp(recordingId, this.config, options);
  }
  /**
   * Check if browser worker service is healthy
   */
  async checkHealth() {
    return checkHealth(this.config);
  }
};
async function executeBrowserTask(input, config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const timeout = config.timeout || DEFAULT_CONFIG.timeout;
  const debug = config.debug || false;
  if (!input.task || input.task.trim().length === 0) {
    return {
      success: false,
      error: 'Task description is required. Example: "Go to example.com and click the login button"'
    };
  }
  if (input.maxSteps !== void 0 && (input.maxSteps < 1 || input.maxSteps > 50)) {
    return {
      success: false,
      error: "maxSteps must be between 1 and 50. Use more steps for complex multi-page flows."
    };
  }
  logger.debug("Browser", "execute_start", { task: input.task.slice(0, 100), url: input.url, max_steps: input.maxSteps ?? 10, record_video: input.recordVideo ?? false });
  const startTime = Date.now();
  try {
    const headers = { "Content-Type": "application/json" };
    if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
    const fetchPromise = fetchWithRetry(
      `${apiUrl}/browser-task`,
      {
        method: "POST",
        headers,
        body: JSON.stringify({
          task: input.task,
          url: input.url,
          max_steps: input.maxSteps ?? 10,
          model: input.model ?? "morph-computer-use-v0",
          viewport_width: input.viewportWidth ?? 1280,
          viewport_height: input.viewportHeight ?? 720,
          external_id: input.externalId,
          repo_id: input.repoId,
          commit_id: input.commitId,
          record_video: input.recordVideo ?? false,
          video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
          video_height: input.videoHeight ?? input.viewportHeight ?? 720,
          allow_resizing: input.allowResizing ?? false,
          structured_output: input.structuredOutput,
          auth: input.auth,
          profile_id: input.profileId,
          force_query_params: input.forceQueryParams
        })
      },
      config.retryConfig
    );
    const response = await withTimeout(
      fetchPromise,
      timeout,
      `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing maxSteps.`
    );
    if (!response.ok) {
      const errorText = await response.text().catch(() => response.statusText);
      logger.error("Browser", "execute_error", { status: response.status, error: errorText });
      throw new Error(`HTTP ${response.status}: ${errorText}`);
    }
    const result = mapTaskResult(await response.json());
    const elapsed = Date.now() - startTime;
    logger.debug("Browser", "execute_complete", { success: result.success, latency_ms: elapsed, steps: result.stepsTaken ?? 0, recording_id: result.recordingId });
    return result;
  } catch (error) {
    if (error instanceof Error) {
      if (error.message.includes("ECONNREFUSED") || error.message.includes("fetch failed")) {
        return {
          success: false,
          error: `Cannot connect to browser worker at ${apiUrl}. Ensure the service is running and accessible. For local dev, set MORPH_ENVIRONMENT=DEV.`
        };
      }
      return {
        success: false,
        error: error.message
      };
    }
    return {
      success: false,
      error: String(error)
    };
  }
}
async function getRecording(recordingId, config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const debug = config.debug || false;
  if (!config.apiKey) {
    throw new Error("API key required for getRecording");
  }
  if (debug) console.log(`[Browser] getRecording: ${recordingId}`);
  const response = await fetch(`${apiUrl}/recordings/${recordingId}`, {
    method: "GET",
    headers: { "Authorization": `Bearer ${config.apiKey}` }
  });
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }
  const data = mapRecordingStatus(await response.json());
  if (debug) console.log(`[Browser] Recording status: ${data.status}`);
  return {
    ...data,
    getWebp: (options) => getWebp(recordingId, config, options),
    getErrors: () => getErrors(recordingId, config)
  };
}
async function waitForRecording(recordingId, config = {}, options = {}) {
  const timeout = options.timeout ?? 6e4;
  const pollInterval = options.pollInterval ?? 2e3;
  const startTime = Date.now();
  while (Date.now() - startTime < timeout) {
    const status = await getRecording(recordingId, config);
    if (status.status === "COMPLETED" || status.status === "ERROR") {
      return status;
    }
    await new Promise((resolve) => setTimeout(resolve, pollInterval));
  }
  throw new Error(`Recording timeout after ${timeout}ms - status still pending`);
}
async function executeWithRecording(input, config = {}) {
  const taskResult = await executeBrowserTask(input, config);
  if (taskResult.recordingId) {
    try {
      const recording = await waitForRecording(
        taskResult.recordingId,
        config,
        { timeout: 6e4, pollInterval: 2e3 }
      );
      return {
        ...taskResult,
        recording
      };
    } catch (error) {
      const errorRecording = {
        id: taskResult.recordingId,
        status: "ERROR",
        error: error instanceof Error ? error.message : String(error),
        createdAt: (/* @__PURE__ */ new Date()).toISOString(),
        getWebp: (options) => getWebp(taskResult.recordingId, config, options),
        getErrors: () => getErrors(taskResult.recordingId, config)
      };
      return {
        ...taskResult,
        recording: errorRecording
      };
    }
  }
  return taskResult;
}
async function getErrors(recordingId, config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const debug = config.debug || false;
  if (!config.apiKey) {
    throw new Error("API key required for getErrors");
  }
  if (debug) console.log(`[Browser] getErrors: ${recordingId}`);
  const response = await fetch(`${apiUrl}/recordings/${recordingId}/errors`, {
    method: "GET",
    headers: { "Authorization": `Bearer ${config.apiKey}` }
  });
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }
  const errors = mapErrorsResponse(await response.json());
  if (debug) console.log(`[Browser] Found ${errors.totalErrors} errors`);
  return errors;
}
function stringifyStructuredOutput(schema) {
  try {
    return JSON.stringify({
      type: "object",
      description: "Zod schema definition (Zod v3)",
      zodDef: schema._def
    });
  } catch (error) {
    console.warn("[Browser] Failed to serialize Zod schema:", error);
    return JSON.stringify({
      type: "object",
      description: "Schema serialization failed"
    });
  }
}
function parseStructuredTaskOutput(result, schema) {
  if (!result.output) {
    return { ...result, parsed: null };
  }
  try {
    const parsed = JSON.parse(result.output);
    const validated = schema.parse(parsed);
    return { ...result, parsed: validated };
  } catch (error) {
    if (error instanceof SyntaxError) {
      return { ...result, parsed: null };
    }
    throw error;
  }
}
function mapTaskResult(api) {
  if (!api || typeof api !== "object") {
    return api;
  }
  return {
    success: api.success,
    result: api.result,
    error: api.error,
    stepsTaken: api.steps_taken,
    executionTimeMs: api.execution_time_ms,
    urls: api.urls,
    actionNames: api.action_names,
    errors: api.errors,
    modelActions: api.model_actions,
    isDone: api.is_done,
    actionHistory: api.action_history,
    actionResults: api.action_results,
    hasErrors: api.has_errors,
    numberOfSteps: api.number_of_steps,
    judgement: api.judgement,
    isValidated: api.is_validated,
    replayId: api.replay_id,
    replayUrl: api.replay_url,
    recordingId: api.recording_id,
    recordingStatus: api.recording_status,
    taskId: api.task_id,
    status: api.status,
    output: api.output,
    debugUrl: api.debug_url
  };
}
function mapRecordingStatus(api) {
  return {
    id: api.id,
    status: api.status,
    replayUrl: api.replay_url,
    networkUrl: api.network_url,
    consoleUrl: api.console_url,
    videoUrl: api.video_url,
    result: api.result,
    totalEvents: api.total_events,
    fileSize: api.file_size,
    duration: api.duration,
    error: api.error,
    createdAt: api.created_at
  };
}
function mapBrowserError(api) {
  return {
    type: api.type,
    message: api.message,
    url: api.url,
    timestamp: api.timestamp,
    screenshotUrl: api.screenshot_url,
    capturedAt: api.captured_at,
    status: api.status
  };
}
function mapErrorsResponse(api) {
  return {
    recordingId: api.recording_id,
    totalErrors: api.total_errors,
    errors: Array.isArray(api.errors) ? api.errors.map(mapBrowserError) : []
  };
}
function mapWebpResponse(api) {
  return {
    webpUrl: api.webp_url,
    cached: api.cached,
    width: api.width,
    fps: api.fps,
    maxDuration: api.max_duration,
    fileSize: api.file_size,
    maxSizeMb: api.max_size_mb,
    budgetMet: api.budget_met,
    qualityUsed: api.quality_used,
    attempts: api.attempts
  };
}
async function getTaskStatus(taskId, config) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const debug = config.debug || false;
  if (debug) console.log(`[Browser] getTaskStatus: ${taskId}`);
  const headers = {};
  if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
  const response = await fetch(`${apiUrl}/tasks/${taskId}`, {
    method: "GET",
    headers
  });
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }
  const result = mapTaskResult(await response.json());
  if (debug) console.log(`[Browser] Task status: ${result.status}`);
  return result;
}
function generateLiveUrl(taskId, config) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const baseUrl = apiUrl.replace("/api", "");
  return `${baseUrl}/tasks/${taskId}/live`;
}
async function pollTaskUntilComplete(taskId, config, pollConfig = {}) {
  const interval = pollConfig.interval ?? 2e3;
  const timeout = pollConfig.timeout ?? 3e5;
  const startTime = Date.now();
  while (Date.now() - startTime < timeout) {
    const status = await getTaskStatus(taskId, config);
    if (status.status === "completed" || status.status === "failed") {
      return status;
    }
    await new Promise((resolve) => setTimeout(resolve, interval));
  }
  throw new Error(`Task polling timeout after ${timeout}ms`);
}
function wrapTaskResponse(result, config) {
  const debugUrl = result.debugUrl ?? "";
  const wrapped = {
    ...result,
    debugUrl,
    taskId: result.taskId || "",
    liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
    complete: async (pollConfig) => {
      if (result.taskId) {
        return pollTaskUntilComplete(result.taskId, config, pollConfig);
      }
      if (result.recordingId) {
        const recording = await waitForRecording(
          result.recordingId,
          config,
          pollConfig
        );
        return {
          ...result,
          recordingStatus: recording.status
        };
      }
      throw new Error("Cannot poll completion: no taskId or recordingId available");
    },
    // Add Steel live session helpers - either functional or error-throwing
    getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
      );
    },
    getLiveIframe: debugUrl ? (optionsOrPreset) => {
      const options = resolvePreset(optionsOrPreset);
      return buildLiveIframe(debugUrl, options);
    } : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
      );
    },
    getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
      );
    }
  };
  return wrapped;
}
function wrapTaskResponseWithSchema(result, config, schema) {
  const debugUrl = result.debugUrl ?? "";
  const parsed = result.output ? parseStructuredTaskOutput(result, schema) : { ...result, parsed: null };
  const wrapped = {
    ...parsed,
    debugUrl,
    taskId: result.taskId || "",
    liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
    complete: async (pollConfig) => {
      if (result.taskId) {
        const finalResult = await pollTaskUntilComplete(result.taskId, config, pollConfig);
        return parseStructuredTaskOutput(finalResult, schema);
      }
      if (result.recordingId) {
        const recording = await waitForRecording(
          result.recordingId,
          config,
          pollConfig
        );
        return {
          ...parsed,
          recordingStatus: recording.status
        };
      }
      throw new Error("Cannot poll completion: no taskId or recordingId available");
    },
    // Add Steel live session helpers - either functional or error-throwing
    getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions. "
      );
    },
    getLiveIframe: debugUrl ? (optionsOrPreset) => {
      const options = resolvePreset(optionsOrPreset);
      return buildLiveIframe(debugUrl, options);
    } : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
      );
    },
    getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
      throw new Error(
        "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
      );
    }
  };
  return wrapped;
}
async function getWebp(recordingId, config = {}, options = {}) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  const debug = config.debug || false;
  if (!config.apiKey) {
    throw new Error("API key required for getWebp");
  }
  const params = new URLSearchParams();
  if (options.maxDuration !== void 0) params.set("max_duration", String(options.maxDuration));
  if (options.fps !== void 0) params.set("fps", String(options.fps));
  if (options.width !== void 0) params.set("width", String(options.width));
  if (options.quality !== void 0) params.set("quality", String(options.quality));
  if (options.maxSizeMb !== void 0) params.set("max_size_mb", String(options.maxSizeMb));
  const url = `${apiUrl}/recordings/${recordingId}/webp${params.toString() ? "?" + params.toString() : ""}`;
  if (debug) console.log(`[Browser] getWebp: ${url}`);
  const response = await fetch(url, {
    method: "GET",
    headers: { "Authorization": `Bearer ${config.apiKey}` }
  });
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    if (debug) console.error(`[Browser] getWebp error: ${response.status} - ${errorText}`);
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }
  const result = mapWebpResponse(await response.json());
  if (debug) console.log(`[Browser] WebP ready: ${result.webpUrl} (cached: ${result.cached})`);
  return result;
}
async function checkHealth(config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
  try {
    const response = await fetch(`${apiUrl}/health`, {
      method: "GET",
      headers: config.apiKey ? { "Authorization": `Bearer ${config.apiKey}` } : {}
    });
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    const data = await response.json();
    return {
      ok: true,
      google_configured: data.google_configured ?? false,
      database_configured: data.database_configured ?? false,
      s3_configured: data.s3_configured ?? false
    };
  } catch (error) {
    return {
      ok: false,
      google_configured: false,
      database_configured: false,
      s3_configured: false,
      error: error instanceof Error ? error.message : String(error)
    };
  }
}

// tools/browser/prompts.ts
var BROWSER_TOOL_DESCRIPTION = `Test and verify your implemented code in a live browser. This tool executes natural language test instructions and returns a video recording plus detailed logs to help you debug issues.

## When to Use
Use this AFTER coding is complete to verify your implementation:
- You've finished writing/modifying code and need to verify it works
- You need to test user interactions end-to-end (clicks, forms, navigation)
- You want to catch runtime errors, console warnings, or network failures
- You need visual confirmation that UI elements render and behave correctly

## What You Get Back
The tool returns debugging artifacts to help you identify and fix issues:
- **Video recording**: Watch exactly what happened in the browser session
- **Console logs**: All console.log, warnings, and errors with timestamps
- **Network logs**: Failed requests, 404s, API errors with screenshots
- **Error screenshots**: Visual snapshots captured when errors occur

## How to Write Good Tests
Be specific about the user journey you're testing:
\u274C Bad: "Test the login feature"
\u2705 Good: "Navigate to /login, enter 'test@example.com' and 'password123', click the Login button, verify we reach the /dashboard page"

Include verification steps:
\u2705 "Click the Add Item button, verify the item appears in the list"
\u2705 "Submit the form, verify a success message is displayed"

## Iterating on Failures
1. Run the test and review the video + logs
2. Identify the specific issue (console error, failed request, wrong behavior)
3. Fix the code based on the evidence
4. Re-run the test to verify the fix
5. Repeat until test passes

## Requirements
- **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)
- **Timing**: Use this after implementation, not during coding
- **Complexity**: Set maxSteps higher (20-30) for multi-step user workflows`;
var BROWSER_SYSTEM_PROMPT = `You are an AI agent designed to automate browser tasks to accomplish the <user_request>. Respond with a valid JSON object in the format: {"thinking": "Reason step-by-step about your current state, history, and the user request to decide your next goal and action. Analyze the browser state and screenshot to confirm the outcome of your last action.", "evaluation_previous_goal": "A concise, one-sentence evaluation of your last action's outcome (e.g., Success, Failure, or Uncertain).", "memory": "1-3 sentences summarizing key information and progress so far. This helps you track progress across multiple steps (e.g., items collected, pages visited).", "next_goal": "A clear, one-sentence description of your immediate next objective.", "action": [{"action_name": {"parameter": "value"}}]}`;

// tools/browser/anthropic.ts
var anthropic_exports = {};
__export(anthropic_exports, {
  browserTool: () => browserTool,
  createBrowserTool: () => createBrowserTool
});
var browserTool = {
  name: "browser_task",
  description: BROWSER_TOOL_DESCRIPTION,
  input_schema: {
    type: "object",
    properties: {
      task: {
        type: "string",
        description: 'Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'
      },
      url: {
        type: "string",
        description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
      },
      maxSteps: {
        type: "number",
        description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.",
        default: 10
      },
      region: {
        type: "string",
        enum: ["sfo", "lon"],
        description: "Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.",
        default: "sfo"
      }
    },
    required: ["task"]
  }
};
function formatResult(result) {
  if (result.success) {
    const parts = [
      "\u2705 Browser task completed successfully",
      `Steps taken: ${result.stepsTaken ?? 0}`,
      result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
      "",
      "Result:",
      result.result || "Task completed"
    ];
    return parts.filter(Boolean).join("\n");
  }
  return `\u274C Browser task failed: ${result.error || "Unknown error"}`;
}
function createBrowserTool(config) {
  return Object.assign({}, browserTool, {
    execute: async (input) => {
      return executeBrowserTask(input, config);
    },
    formatResult: (result) => {
      return formatResult(result);
    },
    getSystemPrompt: () => {
      return BROWSER_SYSTEM_PROMPT;
    }
  });
}

// tools/browser/openai.ts
var openai_exports = {};
__export(openai_exports, {
  browserTool: () => browserTool2,
  createBrowserTool: () => createBrowserTool2,
  execute: () => execute,
  formatResult: () => formatResult2,
  getSystemPrompt: () => getSystemPrompt
});
var browserTool2 = {
  type: "function",
  function: {
    name: "browser_task",
    description: BROWSER_TOOL_DESCRIPTION,
    parameters: {
      type: "object",
      properties: {
        task: {
          type: "string",
          description: 'Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'
        },
        url: {
          type: "string",
          description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
        },
        maxSteps: {
          type: "number",
          description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.",
          default: 10
        },
        region: {
          type: "string",
          enum: ["sfo", "lon"],
          description: "Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.",
          default: "sfo"
        }
      },
      required: ["task"]
    }
  }
};
async function execute(input, config) {
  const parsedInput = typeof input === "string" ? JSON.parse(input) : input;
  return executeBrowserTask(parsedInput, config);
}
function formatResult2(result) {
  if (result.success) {
    const parts = [
      "\u2705 Browser task completed successfully",
      `Steps taken: ${result.stepsTaken ?? 0}`,
      result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
      "",
      "Result:",
      result.result || "Task completed"
    ];
    return parts.filter(Boolean).join("\n");
  }
  return `\u274C Browser task failed: ${result.error || "Unknown error"}`;
}
function getSystemPrompt() {
  return BROWSER_SYSTEM_PROMPT;
}
function createBrowserTool2(config) {
  return Object.assign({}, browserTool2, {
    execute: async (input) => {
      return execute(input, config);
    },
    formatResult: (result) => {
      return formatResult2(result);
    },
    getSystemPrompt: () => {
      return getSystemPrompt();
    }
  });
}

// tools/browser/vercel.ts
var vercel_exports = {};
__export(vercel_exports, {
  browserTool: () => browserTool3,
  createBrowserTool: () => createBrowserTool3
});
var import_ai = require("ai");
var import_zod = require("zod");
function createBrowserTool3(config) {
  const schema = import_zod.z.object({
    task: import_zod.z.string().describe('Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'),
    url: import_zod.z.string().optional().describe("Starting URL (e.g., https://3000-xyz.e2b.dev)"),
    maxSteps: import_zod.z.number().min(1).max(50).default(10).describe("Maximum number of browser actions to take"),
    region: import_zod.z.enum(["sfo", "lon"]).default("sfo").describe("Browserless region: sfo (US West) or lon (Europe)")
  });
  return (0, import_ai.tool)({
    description: BROWSER_TOOL_DESCRIPTION,
    inputSchema: schema,
    execute: async (params) => {
      const { task, url, maxSteps, region } = params;
      const result = await executeBrowserTask(
        { task, url, maxSteps, region },
        config
      );
      if (result.success) {
        return {
          success: true,
          result: result.result,
          stepsTaken: result.stepsTaken,
          executionTimeMs: result.executionTimeMs
        };
      }
      return {
        success: false,
        error: result.error
      };
    }
  });
}
var browserTool3 = createBrowserTool3();

// tools/browser/gemini.ts
var gemini_exports = {};
__export(gemini_exports, {
  browserFunctionDeclaration: () => browserFunctionDeclaration,
  browserTool: () => browserTool4,
  createBrowserTool: () => createBrowserTool4,
  default: () => gemini_default,
  execute: () => execute2,
  formatResult: () => formatResult3,
  getSystemPrompt: () => getSystemPrompt2
});
var import_generative_ai = require("@google/generative-ai");
var TOOL_PARAMETERS = {
  type: import_generative_ai.SchemaType.OBJECT,
  properties: {
    task: {
      type: import_generative_ai.SchemaType.STRING,
      description: 'Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'
    },
    url: {
      type: import_generative_ai.SchemaType.STRING,
      description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
    },
    maxSteps: {
      type: import_generative_ai.SchemaType.NUMBER,
      description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows."
    },
    region: {
      type: import_generative_ai.SchemaType.STRING,
      description: "Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo."
    }
  },
  required: ["task"]
};
var browserFunctionDeclaration = {
  name: "browser_task",
  description: BROWSER_TOOL_DESCRIPTION,
  parameters: TOOL_PARAMETERS
};
async function execute2(input, config) {
  const parsedInput = typeof input === "string" ? JSON.parse(input) : input;
  return executeBrowserTask(parsedInput, config);
}
function formatResult3(result) {
  if (result.success) {
    const parts = [
      "\u2705 Browser task completed successfully",
      `Steps taken: ${result.stepsTaken ?? 0}`,
      result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
      "",
      "Result:",
      result.result || "Task completed"
    ];
    return parts.filter(Boolean).join("\n");
  }
  return `\u274C Browser task failed: ${result.error || "Unknown error"}`;
}
function getSystemPrompt2() {
  return BROWSER_SYSTEM_PROMPT;
}
function createBrowserTool4(config) {
  const declaration = {
    name: "browser_task",
    description: BROWSER_TOOL_DESCRIPTION,
    parameters: TOOL_PARAMETERS
  };
  return Object.assign(declaration, {
    execute: async (input) => {
      return execute2(input, config);
    },
    formatResult: (result) => {
      return formatResult3(result);
    },
    getSystemPrompt: () => {
      return getSystemPrompt2();
    }
  });
}
var browserTool4 = browserFunctionDeclaration;
var gemini_default = browserFunctionDeclaration;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  BROWSER_SYSTEM_PROMPT,
  BROWSER_TOOL_DESCRIPTION,
  BrowserClient,
  LIVE_PRESETS,
  MorphAPIError,
  MorphAuthenticationError,
  MorphError,
  MorphNotFoundError,
  MorphProfileLimitError,
  MorphRateLimitError,
  MorphValidationError,
  ProfilesClient,
  anthropic,
  buildEmbedCode,
  buildLiveIframe,
  buildLiveUrl,
  checkHealth,
  executeBrowserTask,
  executeWithRecording,
  gemini,
  getErrors,
  getRecording,
  getWebp,
  openai,
  parseAPIError,
  vercel,
  waitForRecording
});
//# sourceMappingURL=index.cjs.map