"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);
var program_exports = {};
__export(program_exports, {
  printResponse: () => printResponse,
  program: () => program
});
module.exports = __toCommonJS(program_exports);
var import_child_process = require("child_process");
var import_crypto = __toESM(require("crypto"));
var import_fs = __toESM(require("fs"));
var import_net = __toESM(require("net"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_socketConnection = require("./socketConnection");
const debugCli = (0, import_utilsBundle.debug)("pw:cli");
class Session {
  constructor(name, connection) {
    this._nextMessageId = 1;
    this._callbacks = /* @__PURE__ */ new Map();
    this.name = name;
    this._connection = connection;
    this._connection.onmessage = (message) => this._onMessage(message);
    this._connection.onclose = () => this.close();
  }
  async run(args) {
    return await this._send("run", { args });
  }
  async stop() {
    await this._send("stop");
    this.close();
  }
  async _send(method, params = {}) {
    const messageId = this._nextMessageId++;
    const message = {
      id: messageId,
      method,
      params
    };
    await this._connection.send(message);
    return new Promise((resolve, reject) => {
      this._callbacks.set(messageId, { resolve, reject });
    });
  }
  close() {
    for (const callback of this._callbacks.values())
      callback.reject(new Error("Session closed"));
    this._callbacks.clear();
    this._connection.close();
  }
  _onMessage(object) {
    if (object.id && this._callbacks.has(object.id)) {
      const callback = this._callbacks.get(object.id);
      this._callbacks.delete(object.id);
      if (object.error)
        callback.reject(new Error(object.error));
      else
        callback.resolve(object.result);
    } else if (object.id) {
      throw new Error(`Unexpected message id: ${object.id}`);
    } else {
      throw new Error(`Unexpected message without id: ${JSON.stringify(object)}`);
    }
  }
}
class SessionManager {
  constructor(options) {
    this._options = options;
  }
  async list() {
    const dir = daemonProfilesDir;
    try {
      const files = await import_fs.default.promises.readdir(dir);
      const sessions = /* @__PURE__ */ new Map();
      for (const file of files) {
        if (file.startsWith("ud-")) {
          const sessionName = file.split("-")[1];
          const live = await this._canConnect(sessionName);
          sessions.set(sessionName, live);
        }
      }
      return sessions;
    } catch {
      return /* @__PURE__ */ new Map();
    }
  }
  async run(args) {
    const sessionName = this._resolveSessionName(args.session);
    const session = await this._connect(sessionName);
    const result = await session.run(args);
    await printResponse(result);
    session.close();
  }
  async stop(sessionName) {
    sessionName = this._resolveSessionName(sessionName);
    if (!await this._canConnect(sessionName)) {
      console.log(`Session '${sessionName}' is not running.`);
      return;
    }
    const session = await this._connect(sessionName);
    await session.stop();
    console.log(`Session '${sessionName}' stopped.`);
  }
  async delete(sessionName) {
    sessionName = this._resolveSessionName(sessionName);
    if (await this._canConnect(sessionName)) {
      const session = await this._connect(sessionName);
      await session.stop();
    }
    const dataDirs = await import_fs.default.promises.readdir(daemonProfilesDir).catch(() => []);
    const matchingDirs = dataDirs.filter((dir) => dir.startsWith(`ud-${sessionName}-`));
    if (matchingDirs.length === 0) {
      console.log(`No user data found for session '${sessionName}'.`);
      return;
    }
    for (const dir of matchingDirs) {
      const userDataDir = import_path.default.resolve(daemonProfilesDir, dir);
      for (let i = 0; i < 5; i++) {
        try {
          await import_fs.default.promises.rm(userDataDir, { recursive: true });
          console.log(`Deleted user data for session '${sessionName}'.`);
          break;
        } catch (e) {
          if (e.code === "ENOENT") {
            console.log(`No user data found for session '${sessionName}'.`);
            break;
          }
          await new Promise((resolve) => setTimeout(resolve, 1e3));
          if (i === 4)
            throw e;
        }
      }
    }
    if (import_os.default.platform() !== "win32") {
      const socketPath = this._daemonSocketPath(sessionName);
      await import_fs.default.promises.unlink(socketPath).catch(() => {
      });
    }
  }
  async configure(args) {
    const sessionName = this._resolveSessionName(args.session);
    if (await this._canConnect(sessionName)) {
      const session2 = await this._connect(sessionName);
      await session2.stop();
    }
    this._options.config = args._[1];
    const session = await this._connect(sessionName);
    session.close();
  }
  async _connect(sessionName) {
    const socketPath = this._daemonSocketPath(sessionName);
    debugCli(`Connecting to daemon at ${socketPath}`);
    if (await this._canConnect(sessionName)) {
      debugCli(`Socket file exists, attempting to connect...`);
      try {
        return await this._connectToSocket(sessionName, socketPath);
      } catch (e) {
        if (import_os.default.platform() !== "win32")
          await import_fs.default.promises.unlink(socketPath).catch(() => {
          });
      }
    }
    await import_fs.default.promises.mkdir(daemonProfilesDir, { recursive: true });
    const userDataDir = import_path.default.resolve(daemonProfilesDir, `ud-${sessionName}`);
    const cliPath = import_path.default.join(__dirname, "../../../cli.js");
    debugCli(`Will launch daemon process: ${cliPath}`);
    const configFile = resolveConfigFile(this._options.config);
    const configArg = configFile !== void 0 ? [`--config=${configFile}`] : [];
    const headedArg = this._options.headed ? [`--daemon-headed`] : [];
    const outLog = import_path.default.join(daemonProfilesDir, "out.log");
    const errLog = import_path.default.join(daemonProfilesDir, "err.log");
    const out = import_fs.default.openSync(outLog, "w");
    const err = import_fs.default.openSync(errLog, "w");
    const child = (0, import_child_process.spawn)(process.execPath, [
      cliPath,
      "run-mcp-server",
      `--daemon=${socketPath}`,
      `--daemon-data-dir=${userDataDir}`,
      ...configArg,
      ...headedArg
    ], {
      detached: true,
      stdio: ["ignore", out, err],
      cwd: process.cwd()
      // Will be used as root.
    });
    child.unref();
    console.log(`<!-- Daemon for \`${sessionName}\` session started with pid ${child.pid}.`);
    if (configFile)
      console.log(`- Using config file at \`${import_path.default.relative(process.cwd(), configFile)}\`.`);
    const sessionSuffix = sessionName !== "default" ? ` "${sessionName}"` : "";
    console.log(`- You can stop the session daemon with \`playwright-cli session-stop${sessionSuffix}\` when done.`);
    console.log(`- You can delete the session data with \`playwright-cli session-delete${sessionSuffix}\` when done.`);
    console.log("-->");
    const maxRetries = 50;
    const retryDelay = 100;
    for (let i = 0; i < maxRetries; i++) {
      await new Promise((resolve) => setTimeout(resolve, 100));
      try {
        return await this._connectToSocket(sessionName, socketPath);
      } catch (e) {
        if (e.code !== "ENOENT")
          throw e;
        debugCli(`Retrying to connect to daemon at ${socketPath} (${i + 1}/${maxRetries})`);
      }
    }
    const outData = await import_fs.default.promises.readFile(outLog, "utf-8").catch(() => "");
    const errData = await import_fs.default.promises.readFile(errLog, "utf-8").catch(() => "");
    console.error(`Failed to connect to daemon at ${socketPath} after ${maxRetries * retryDelay}ms`);
    if (outData.length)
      console.log(outData);
    if (errData.length)
      console.error(errData);
    process.exit(1);
  }
  async _connectToSocket(sessionName, socketPath) {
    const socket = await new Promise((resolve, reject) => {
      const socket2 = import_net.default.createConnection(socketPath, () => {
        debugCli(`Connected to daemon at ${socketPath}`);
        resolve(socket2);
      });
      socket2.on("error", reject);
    });
    return new Session(sessionName, new import_socketConnection.SocketConnection(socket));
  }
  async _canConnect(sessionName) {
    const socketPath = this._daemonSocketPath(sessionName);
    return new Promise((resolve) => {
      const socket = import_net.default.createConnection(socketPath, () => {
        socket.destroy();
        resolve(true);
      });
      socket.on("error", () => {
        resolve(false);
      });
    });
  }
  _resolveSessionName(sessionName) {
    if (sessionName)
      return sessionName;
    if (process.env.PLAYWRIGHT_CLI_SESSION)
      return process.env.PLAYWRIGHT_CLI_SESSION;
    return "default";
  }
  _daemonSocketPath(sessionName) {
    const socketName = `${sessionName}.sock`;
    if (import_os.default.platform() === "win32")
      return `\\\\.\\pipe\\${installationDirHash}-${socketName}`;
    const socketsDir = process.env.PLAYWRIGHT_DAEMON_SOCKETS_DIR || import_path.default.join(import_os.default.tmpdir(), "playwright-cli");
    return import_path.default.join(socketsDir, installationDirHash, socketName);
  }
}
async function handleSessionCommand(sessionManager, subcommand, args) {
  if (subcommand === "list") {
    const sessions = await sessionManager.list();
    console.log("Sessions:");
    for (const [sessionName, live] of sessions.entries()) {
      const liveMarker = live ? " (live)" : "";
      console.log(`  ${sessionName}${liveMarker}`);
    }
    if (sessions.size === 0)
      console.log("  (no sessions)");
    return;
  }
  if (subcommand === "stop") {
    await sessionManager.stop(args._[1]);
    return;
  }
  if (subcommand === "stop-all") {
    const sessions = await sessionManager.list();
    for (const sessionName of sessions.keys())
      await sessionManager.stop(sessionName);
    return;
  }
  if (subcommand === "delete") {
    await sessionManager.delete(args._[1]);
    return;
  }
  if (subcommand === "config") {
    await sessionManager.configure(args);
    return;
  }
  console.error(`Unknown session subcommand: ${subcommand}`);
  process.exit(1);
}
const installationDirHash = (() => {
  const hash = import_crypto.default.createHash("sha1");
  hash.update(process.env.PLAYWRIGHT_DAEMON_INSTALL_DIR || require.resolve("../../../package.json"));
  return hash.digest("hex").substring(0, 16);
})();
const daemonProfilesDir = (() => {
  if (process.env.PLAYWRIGHT_DAEMON_SESSION_DIR)
    return process.env.PLAYWRIGHT_DAEMON_SESSION_DIR;
  let localCacheDir;
  if (process.platform === "linux")
    localCacheDir = process.env.XDG_CACHE_HOME || import_path.default.join(import_os.default.homedir(), ".cache");
  if (process.platform === "darwin")
    localCacheDir = import_path.default.join(import_os.default.homedir(), "Library", "Caches");
  if (process.platform === "win32")
    localCacheDir = process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local");
  if (!localCacheDir)
    throw new Error("Unsupported platform: " + process.platform);
  return import_path.default.join(localCacheDir, "ms-playwright", "daemon", installationDirHash);
})();
async function program(options) {
  const argv = process.argv.slice(2);
  const args = require("minimist")(argv, {
    boolean: ["help", "version", "headed"]
  });
  if (!argv.includes("--headed") && !argv.includes("--no-headed"))
    delete args.headed;
  const help = require("./help.json");
  const commandName = args._[0];
  if (args.version || args.v) {
    console.log(options.version);
    process.exit(0);
  }
  const command = help.commands[commandName];
  if (args.help || args.h) {
    if (command) {
      console.log(command);
    } else {
      console.log("playwright-cli - run playwright mcp commands from terminal\n");
      console.log(help.global);
    }
    process.exit(0);
  }
  if (!command) {
    console.error(`Unknown command: ${commandName}
`);
    console.log(help.global);
    process.exit(1);
  }
  const sessionManager = new SessionManager(args);
  if (commandName.startsWith("session")) {
    const subcommand = args._[0].split("-").slice(1).join("-");
    await handleSessionCommand(sessionManager, subcommand, args);
    return;
  }
  if (commandName === "config") {
    await handleSessionCommand(sessionManager, "config", args);
    return;
  }
  await sessionManager.run(args);
}
async function printResponse(response) {
  const { sections } = response;
  if (!sections) {
    console.log("### Error\n" + response.text);
    return;
  }
  const text = [];
  for (const section of sections) {
    text.push(`### ${section.title}`);
    for (const result of section.content) {
      if (!result.file) {
        if (result.text !== void 0)
          text.push(result.text);
        continue;
      }
      const generatedFileName = await outputFile(dateAsFileName(result.file.prefix, result.file.ext), { origin: "code" });
      const fileName = result.file.suggestedFilename ? await outputFile(result.file.suggestedFilename, { origin: "llm" }) : generatedFileName;
      text.push(`- [${result.title}](${import_path.default.relative(process.cwd(), fileName)})`);
      if (result.data)
        await import_fs.default.promises.writeFile(fileName, result.data);
      else if (result.isBase64)
        await import_fs.default.promises.writeFile(fileName, Buffer.from(result.text, "base64"));
      else
        await import_fs.default.promises.writeFile(fileName, result.text);
    }
  }
  console.log(text.join("\n"));
}
function dateAsFileName(prefix, extension) {
  const date = /* @__PURE__ */ new Date();
  return `${prefix}-${date.toISOString().replace(/[:.]/g, "-")}.${extension}`;
}
const outputDir = import_path.default.join(process.cwd(), ".playwright-cli");
async function outputFile(fileName, options) {
  await import_fs.default.promises.mkdir(outputDir, { recursive: true });
  if (options.origin === "code")
    return import_path.default.resolve(outputDir, fileName);
  if (options.origin === "llm") {
    fileName = fileName.split("\\").join("/");
    const resolvedFile = import_path.default.resolve(outputDir, fileName);
    if (!resolvedFile.startsWith(import_path.default.resolve(outputDir) + import_path.default.sep))
      throw new Error(`Resolved file path ${resolvedFile} is outside of the output directory ${outputDir}. Use relative file names to stay within the output directory.`);
    return resolvedFile;
  }
  return import_path.default.join(outputDir, sanitizeForFilePath(fileName));
}
function sanitizeForFilePath(s) {
  const sanitize = (s2) => s2.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
  const separator = s.lastIndexOf(".");
  if (separator === -1)
    return sanitize(s);
  return sanitize(s.substring(0, separator)) + "." + sanitize(s.substring(separator + 1));
}
function resolveConfigFile(configParam) {
  const configFile = configParam || process.env.PLAYWRIGHT_CLI_CONFIG;
  if (configFile)
    return import_path.default.resolve(process.cwd(), configFile);
  try {
    if (import_fs.default.existsSync(import_path.default.resolve(process.cwd(), "playwright-cli.json")))
      return import_path.default.resolve(process.cwd(), "playwright-cli.json");
  } catch {
  }
  return void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  printResponse,
  program
});
