"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 traceCli_exports = {};
__export(traceCli_exports, {
  addTraceCommands: () => addTraceCommands,
  loadTrace: () => loadTrace,
  loadTraceModel: () => loadTraceModel,
  traceAction: () => traceAction,
  traceActions: () => traceActions,
  traceAttachment: () => traceAttachment,
  traceAttachments: () => traceAttachments,
  traceConsole: () => traceConsole,
  traceErrors: () => traceErrors,
  traceInfo: () => traceInfo,
  traceRequest: () => traceRequest,
  traceRequests: () => traceRequests,
  traceScreenshot: () => traceScreenshot,
  traceSnapshot: () => traceSnapshot
});
module.exports = __toCommonJS(traceCli_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_traceModel = require("../../utils/isomorphic/trace/traceModel");
var import_traceLoader = require("../../utils/isomorphic/trace/traceLoader");
var import_protocolFormatter = require("../../utils/isomorphic/protocolFormatter");
var import_locatorGenerators = require("../../utils/isomorphic/locatorGenerators");
var import_formatUtils = require("../../utils/isomorphic/formatUtils");
var import_traceParser = require("./traceParser");
function addTraceCommands(program, logErrorAndExit) {
  const traceCommand = program.command("trace").description("inspect trace files from the command line");
  traceCommand.command("info <trace>").description("show trace metadata").action(function(trace) {
    traceInfo(trace).catch(logErrorAndExit);
  });
  traceCommand.command("actions <trace>").description("list actions in the trace").option("--grep <pattern>", "filter actions by title pattern").option("--errors-only", "only show failed actions").action(function(trace, options) {
    traceActions(trace, options).catch(logErrorAndExit);
  });
  traceCommand.command("action <trace> <action-id>").description("show details of a specific action").action(function(trace, actionId) {
    traceAction(trace, actionId).catch(logErrorAndExit);
  });
  traceCommand.command("requests <trace>").description("show network requests").option("--grep <pattern>", "filter by URL pattern").option("--method <method>", "filter by HTTP method").option("--status <code>", "filter by status code").option("--failed", "only show failed requests (status >= 400)").action(function(trace, options) {
    traceRequests(trace, options).catch(logErrorAndExit);
  });
  traceCommand.command("request <trace> <request-id>").description("show details of a specific network request").action(function(trace, requestId) {
    traceRequest(trace, requestId).catch(logErrorAndExit);
  });
  traceCommand.command("console <trace>").description("show console messages").option("--errors-only", "only show errors").option("--warnings", "show errors and warnings").option("--browser", "only browser console messages").option("--stdio", "only stdout/stderr").action(function(trace, options) {
    traceConsole(trace, options).catch(logErrorAndExit);
  });
  traceCommand.command("errors <trace>").description("show errors with stack traces").action(function(trace) {
    traceErrors(trace).catch(logErrorAndExit);
  });
  traceCommand.command("snapshot <trace> <action-id>").description("save or serve DOM snapshot for an action").option("--name <name>", "snapshot phase: before, input, or after", "before").option("-o, --output <path>", "output file path").option("--serve", "serve snapshot on local HTTP server").option("--port <port>", "port for serve mode").action(function(trace, actionId, options) {
    traceSnapshot(trace, actionId, options).catch(logErrorAndExit);
  });
  traceCommand.command("screenshot <trace> <action-id>").description("save screencast screenshot for an action").option("-o, --output <path>", "output file path").action(function(trace, actionId, options) {
    traceScreenshot(trace, actionId, options).catch(logErrorAndExit);
  });
  traceCommand.command("attachments <trace>").description("list trace attachments").action(function(trace) {
    traceAttachments(trace).catch(logErrorAndExit);
  });
  traceCommand.command("attachment <trace> <attachment-id>").description("extract a trace attachment by its number").option("-o, --output <path>", "output file path").action(function(trace, attachmentId, options) {
    traceAttachment(trace, attachmentId, options).catch(logErrorAndExit);
  });
  traceCommand.command("install-skill").description("install SKILL.md for LLM integration").action(function() {
    installSkill().catch(logErrorAndExit);
  });
}
async function loadTrace(traceFile) {
  const filePath = import_path.default.resolve(traceFile);
  if (!import_fs.default.existsSync(filePath))
    throw new Error(`Trace file not found: ${filePath}`);
  const backend = new import_traceParser.ZipTraceLoaderBackend(filePath);
  const loader = new import_traceLoader.TraceLoader();
  await loader.load(backend, () => void 0);
  return { model: new import_traceModel.TraceModel(filePath, loader.contextEntries), loader };
}
async function loadTraceModel(traceFile) {
  return (await loadTrace(traceFile)).model;
}
function formatTimestamp(ms, base) {
  const relative = ms - base;
  if (relative < 0)
    return "0:00.000";
  const totalMs = Math.floor(relative);
  const minutes = Math.floor(totalMs / 6e4);
  const seconds = Math.floor(totalMs % 6e4 / 1e3);
  const millis = totalMs % 1e3;
  return `${minutes}:${seconds.toString().padStart(2, "0")}.${millis.toString().padStart(3, "0")}`;
}
function actionTitle(action, sdkLanguage) {
  return (0, import_protocolFormatter.renderTitleForCall)({ ...action, type: action.class }) || `${action.class}.${action.method}`;
}
function actionLocator(action, sdkLanguage) {
  return action.params.selector ? (0, import_locatorGenerators.asLocatorDescription)(sdkLanguage || "javascript", action.params.selector) : void 0;
}
const cliOutputDir = ".playwright-cli";
async function saveOutputFile(fileName, content, explicitOutput) {
  let outFile;
  if (explicitOutput) {
    outFile = explicitOutput;
  } else {
    await import_fs.default.promises.mkdir(cliOutputDir, { recursive: true });
    outFile = import_path.default.join(cliOutputDir, fileName);
  }
  await import_fs.default.promises.writeFile(outFile, content);
  return outFile;
}
function padEnd(str, len) {
  return str.length >= len ? str : str + " ".repeat(len - str.length);
}
function padStart(str, len) {
  return str.length >= len ? str : " ".repeat(len - str.length) + str;
}
function buildOrdinalMap(model) {
  const actions = model.actions.filter((a) => a.group !== "configuration");
  const { rootItem } = (0, import_traceModel.buildActionTree)(actions);
  const ordinalToCallId = /* @__PURE__ */ new Map();
  const callIdToOrdinal = /* @__PURE__ */ new Map();
  let ordinal = 1;
  const visit = (item) => {
    ordinalToCallId.set(ordinal, item.action.callId);
    callIdToOrdinal.set(item.action.callId, ordinal);
    ordinal++;
    for (const child of item.children)
      visit(child);
  };
  for (const child of rootItem.children)
    visit(child);
  return { ordinalToCallId, callIdToOrdinal };
}
function resolveActionId(actionId, model) {
  const ordinal = parseInt(actionId, 10);
  if (!isNaN(ordinal)) {
    const { ordinalToCallId } = buildOrdinalMap(model);
    const callId = ordinalToCallId.get(ordinal);
    if (callId)
      return model.actions.find((a) => a.callId === callId);
  }
  return model.actions.find((a) => a.callId === actionId);
}
async function traceActions(traceFile, options) {
  const model = await loadTraceModel(traceFile);
  const lang = model.sdkLanguage;
  const { callIdToOrdinal } = buildOrdinalMap(model);
  const actions = filterActions(model.actions, options, lang);
  const { rootItem } = (0, import_traceModel.buildActionTree)(actions);
  console.log(`  ${padStart("#", 4)} ${padEnd("Time", 9)}  ${padEnd("Action", 55)} ${padStart("Duration", 8)}`);
  console.log(`  ${"\u2500".repeat(4)} ${"\u2500".repeat(9)}  ${"\u2500".repeat(55)} ${"\u2500".repeat(8)}`);
  const visit = (item, indent) => {
    const action = item.action;
    const ordinal = callIdToOrdinal.get(action.callId) ?? "?";
    const ts = formatTimestamp(action.startTime, model.startTime);
    const duration = action.endTime ? (0, import_formatUtils.msToString)(action.endTime - action.startTime) : "running";
    const title = actionTitle(action, lang);
    const locator = actionLocator(action, lang);
    const error = action.error ? "  \u2717" : "";
    const prefix = `  ${padStart(ordinal + ".", 4)} ${ts}  ${indent}`;
    console.log(`${prefix}${padEnd(title, Math.max(1, 55 - indent.length))} ${padStart(duration, 8)}${error}`);
    if (locator)
      console.log(`${" ".repeat(prefix.length)}${locator}`);
    for (const child of item.children)
      visit(child, indent + "  ");
  };
  for (const child of rootItem.children)
    visit(child, "");
}
function filterActions(actions, options, lang) {
  let result = actions.filter((a) => a.group !== "configuration");
  if (options.grep) {
    const pattern = new RegExp(options.grep, "i");
    result = result.filter((a) => pattern.test(actionTitle(a, lang)) || pattern.test(actionLocator(a, lang) || ""));
  }
  if (options.errorsOnly)
    result = result.filter((a) => !!a.error);
  return result;
}
async function traceAction(traceFile, actionId) {
  const model = await loadTraceModel(traceFile);
  const lang = model.sdkLanguage;
  const action = resolveActionId(actionId, model);
  if (!action) {
    console.error(`Action '${actionId}' not found. Use 'trace actions' to see available action IDs.`);
    process.exitCode = 1;
    return;
  }
  const title = actionTitle(action, lang);
  console.log(`
  ${title}
`);
  console.log("  Time");
  console.log(`    start:     ${formatTimestamp(action.startTime, model.startTime)}`);
  const duration = action.endTime ? (0, import_formatUtils.msToString)(action.endTime - action.startTime) : action.error ? "Timed Out" : "Running";
  console.log(`    duration:  ${duration}`);
  const paramKeys = Object.keys(action.params).filter((name) => name !== "info");
  if (paramKeys.length) {
    console.log("\n  Parameters");
    for (const key of paramKeys) {
      const value = formatParamValue(action.params[key]);
      console.log(`    ${key}: ${value}`);
    }
  }
  if (action.result) {
    console.log("\n  Return value");
    for (const [key, value] of Object.entries(action.result))
      console.log(`    ${key}: ${formatParamValue(value)}`);
  }
  if (action.error) {
    console.log("\n  Error");
    console.log(`    ${action.error.message}`);
  }
  if (action.log.length) {
    console.log("\n  Log");
    for (const entry of action.log) {
      const time = entry.time !== -1 ? formatTimestamp(entry.time, model.startTime) : "";
      console.log(`    ${padEnd(time, 12)} ${entry.message}`);
    }
  }
  if (action.stack?.length) {
    console.log("\n  Source");
    for (const frame of action.stack.slice(0, 5)) {
      const file = frame.file.replace(/.*[/\\](.*)/, "$1");
      console.log(`    ${file}:${frame.line}:${frame.column}`);
    }
  }
  const snapshots = [];
  if (action.beforeSnapshot)
    snapshots.push("before");
  if (action.inputSnapshot)
    snapshots.push("input");
  if (action.afterSnapshot)
    snapshots.push("after");
  if (snapshots.length) {
    console.log("\n  Snapshots");
    console.log(`    available: ${snapshots.join(", ")}`);
    console.log(`    usage:     npx playwright trace snapshot <trace> ${actionId} --name <${snapshots.join("|")}>`);
  }
  console.log("");
}
function formatParamValue(value) {
  if (value === void 0 || value === null)
    return String(value);
  if (typeof value === "string")
    return `"${value}"`;
  if (typeof value !== "object")
    return String(value);
  if (value.guid)
    return "<handle>";
  return JSON.stringify(value).slice(0, 1e3);
}
async function traceRequests(traceFile, options) {
  const model = await loadTraceModel(traceFile);
  let indexed = model.resources.map((r, i) => ({ resource: r, ordinal: i + 1 }));
  if (options.grep) {
    const pattern = new RegExp(options.grep, "i");
    indexed = indexed.filter(({ resource: r }) => pattern.test(r.request.url));
  }
  if (options.method)
    indexed = indexed.filter(({ resource: r }) => r.request.method.toLowerCase() === options.method.toLowerCase());
  if (options.status) {
    const code = parseInt(options.status, 10);
    indexed = indexed.filter(({ resource: r }) => r.response.status === code);
  }
  if (options.failed)
    indexed = indexed.filter(({ resource: r }) => r.response.status >= 400 || r.response.status === -1);
  if (!indexed.length) {
    console.log("  No network requests");
    return;
  }
  console.log(`  ${padStart("#", 4)} ${padEnd("Method", 8)} ${padEnd("Status", 8)} ${padEnd("Name", 45)} ${padStart("Duration", 10)} ${padStart("Size", 8)} ${padEnd("Route", 10)}`);
  console.log(`  ${"\u2500".repeat(4)} ${"\u2500".repeat(8)} ${"\u2500".repeat(8)} ${"\u2500".repeat(45)} ${"\u2500".repeat(10)} ${"\u2500".repeat(8)} ${"\u2500".repeat(10)}`);
  for (const { resource: r, ordinal } of indexed) {
    let name;
    try {
      const url = new URL(r.request.url);
      name = url.pathname.substring(url.pathname.lastIndexOf("/") + 1);
      if (!name)
        name = url.host;
      if (url.search)
        name += url.search;
    } catch {
      name = r.request.url;
    }
    if (name.length > 45)
      name = name.substring(0, 42) + "...";
    const status = r.response.status > 0 ? String(r.response.status) : "ERR";
    const size = r.response._transferSize > 0 ? r.response._transferSize : r.response.bodySize;
    const route = formatRouteStatus(r);
    console.log(`  ${padStart(ordinal + ".", 4)} ${padEnd(r.request.method, 8)} ${padEnd(status, 8)} ${padEnd(name, 45)} ${padStart((0, import_formatUtils.msToString)(r.time), 10)} ${padStart((0, import_formatUtils.bytesToString)(size), 8)} ${padEnd(route, 10)}`);
  }
}
async function traceRequest(traceFile, requestId) {
  const model = await loadTraceModel(traceFile);
  const ordinal = parseInt(requestId, 10);
  const resource = !isNaN(ordinal) && ordinal >= 1 && ordinal <= model.resources.length ? model.resources[ordinal - 1] : void 0;
  if (!resource) {
    console.error(`Request '${requestId}' not found. Use 'trace requests' to see available request IDs.`);
    process.exitCode = 1;
    return;
  }
  const r = resource;
  const status = r.response.status > 0 ? `${r.response.status} ${r.response.statusText}` : "ERR";
  const size = r.response._transferSize > 0 ? r.response._transferSize : r.response.bodySize;
  console.log(`
  ${r.request.method} ${r.request.url}
`);
  console.log("  General");
  console.log(`    status:    ${status}`);
  console.log(`    duration:  ${(0, import_formatUtils.msToString)(r.time)}`);
  console.log(`    size:      ${(0, import_formatUtils.bytesToString)(size)}`);
  if (r.response.content.mimeType)
    console.log(`    type:      ${r.response.content.mimeType}`);
  const route = formatRouteStatus(r);
  if (route)
    console.log(`    route:     ${route}`);
  if (r.serverIPAddress)
    console.log(`    server:    ${r.serverIPAddress}${r._serverPort ? ":" + r._serverPort : ""}`);
  if (r.response._failureText)
    console.log(`    error:     ${r.response._failureText}`);
  if (r.request.headers.length) {
    console.log("\n  Request headers");
    for (const h of r.request.headers)
      console.log(`    ${h.name}: ${h.value}`);
  }
  if (r.request.postData) {
    console.log("\n  Request body");
    console.log(`    type: ${r.request.postData.mimeType}`);
    if (r.request.postData.text) {
      const text = r.request.postData.text.length > 2e3 ? r.request.postData.text.substring(0, 2e3) + "..." : r.request.postData.text;
      console.log(`    ${text}`);
    }
  }
  if (r.response.headers.length) {
    console.log("\n  Response headers");
    for (const h of r.response.headers)
      console.log(`    ${h.name}: ${h.value}`);
  }
  if (r._securityDetails) {
    console.log("\n  Security");
    if (r._securityDetails.protocol)
      console.log(`    protocol:  ${r._securityDetails.protocol}`);
    if (r._securityDetails.subjectName)
      console.log(`    subject:   ${r._securityDetails.subjectName}`);
    if (r._securityDetails.issuer)
      console.log(`    issuer:    ${r._securityDetails.issuer}`);
  }
  console.log("");
}
function formatRouteStatus(r) {
  if (r._wasAborted)
    return "aborted";
  if (r._wasContinued)
    return "continued";
  if (r._wasFulfilled)
    return "fulfilled";
  if (r._apiRequest)
    return "api";
  return "";
}
async function traceConsole(traceFile, options) {
  const model = await loadTraceModel(traceFile);
  const items = [];
  for (const event of model.events) {
    if (event.type === "console") {
      if (options.stdio)
        continue;
      const level = event.messageType;
      if (options.errorsOnly && level !== "error")
        continue;
      if (options.warnings && level !== "error" && level !== "warning")
        continue;
      const url = event.location.url;
      const filename = url ? url.substring(url.lastIndexOf("/") + 1) : "<anonymous>";
      items.push({
        type: "browser",
        level,
        text: event.text,
        location: `${filename}:${event.location.lineNumber}`,
        timestamp: event.time
      });
    }
    if (event.type === "event" && event.method === "pageError") {
      if (options.stdio)
        continue;
      const error = event.params.error;
      items.push({
        type: "browser",
        level: "error",
        text: error?.error?.message || String(error?.value || ""),
        timestamp: event.time
      });
    }
  }
  for (const event of model.stdio) {
    if (options.browser)
      continue;
    if (options.errorsOnly && event.type !== "stderr")
      continue;
    if (options.warnings && event.type !== "stderr")
      continue;
    let text = "";
    if (event.text)
      text = event.text.trim();
    if (event.base64)
      text = Buffer.from(event.base64, "base64").toString("utf-8").trim();
    if (!text)
      continue;
    items.push({
      type: event.type,
      level: event.type === "stderr" ? "error" : "info",
      text,
      timestamp: event.timestamp
    });
  }
  items.sort((a, b) => a.timestamp - b.timestamp);
  if (!items.length) {
    console.log("  No console entries");
    return;
  }
  for (const item of items) {
    const ts = formatTimestamp(item.timestamp, model.startTime);
    const source = item.type === "browser" ? "[browser]" : `[${item.type}]`;
    const level = padEnd(item.level, 8);
    const location = item.location ? `  ${item.location}` : "";
    console.log(`  ${ts}  ${padEnd(source, 10)} ${level} ${item.text}${location}`);
  }
}
async function traceErrors(traceFile) {
  const model = await loadTraceModel(traceFile);
  const lang = model.sdkLanguage;
  if (!model.errorDescriptors.length) {
    console.log("  No errors");
    return;
  }
  for (const error of model.errorDescriptors) {
    if (error.action) {
      const title = actionTitle(error.action, lang);
      console.log(`
  \u2717 ${title}`);
    } else {
      console.log(`
  \u2717 Error`);
    }
    if (error.stack?.length) {
      const frame = error.stack[0];
      const file = frame.file.replace(/.*[/\\](.*)/, "$1");
      console.log(`    at ${file}:${frame.line}:${frame.column}`);
    }
    console.log("");
    const indented = error.message.split("\n").map((l) => `    ${l}`).join("\n");
    console.log(indented);
  }
  console.log("");
}
async function traceSnapshot(traceFile, actionId, options) {
  const { model, loader } = await loadTrace(traceFile);
  const action = resolveActionId(actionId, model);
  if (!action) {
    console.error(`Action '${actionId}' not found.`);
    process.exitCode = 1;
    return;
  }
  const pageId = action.pageId;
  if (!pageId) {
    console.error(`Action '${actionId}' has no associated page.`);
    process.exitCode = 1;
    return;
  }
  const callId = action.callId;
  const storage = loader.storage();
  let snapshotName;
  let renderer;
  if (options.name) {
    snapshotName = options.name;
    renderer = storage.snapshotByName(pageId, `${snapshotName}@${callId}`);
  } else {
    for (const candidate of ["input", "before", "after"]) {
      renderer = storage.snapshotByName(pageId, `${candidate}@${callId}`);
      if (renderer) {
        snapshotName = candidate;
        break;
      }
    }
  }
  if (!renderer || !snapshotName) {
    console.error(`No snapshot found for action '${actionId}'.`);
    process.exitCode = 1;
    return;
  }
  const snapshotKey = `${snapshotName}@${callId}`;
  const rendered = renderer.render();
  const defaultName = `snapshot-${actionId}-${snapshotName}.html`;
  if (options.serve) {
    const { SnapshotServer } = require("../../utils/isomorphic/trace/snapshotServer");
    const { HttpServer } = require("../../server/utils/httpServer");
    const snapshotServer = new SnapshotServer(storage, (sha1) => loader.resourceForSha1(sha1));
    const httpServer = new HttpServer();
    httpServer.routePrefix("/snapshot", (request, response) => {
      const url = new URL("http://localhost" + request.url);
      const searchParams = url.searchParams;
      searchParams.set("name", snapshotKey);
      const snapshotResponse = snapshotServer.serveSnapshot(pageId, searchParams, "/snapshot");
      response.statusCode = snapshotResponse.status;
      snapshotResponse.headers.forEach((value, key) => response.setHeader(key, value));
      snapshotResponse.text().then((text) => response.end(text));
      return true;
    });
    httpServer.routePrefix("/", (request, response) => {
      response.statusCode = 302;
      response.setHeader("Location", "/snapshot");
      response.end();
      return true;
    });
    await httpServer.start({ preferredPort: options.port || 0 });
    console.log(`Snapshot served at ${httpServer.urlPrefix("human-readable")}`);
    return;
  }
  const outFile = await saveOutputFile(defaultName, rendered.html, options.output);
  console.log(`  Snapshot saved to ${outFile}`);
}
async function traceScreenshot(traceFile, actionId, options) {
  const { model, loader } = await loadTrace(traceFile);
  const action = resolveActionId(actionId, model);
  if (!action) {
    console.error(`Action '${actionId}' not found.`);
    process.exitCode = 1;
    return;
  }
  const pageId = action.pageId;
  if (!pageId) {
    console.error(`Action '${actionId}' has no associated page.`);
    process.exitCode = 1;
    return;
  }
  const callId = action.callId;
  const storage = loader.storage();
  const snapshotNames = ["input", "before", "after"];
  let sha1;
  for (const name of snapshotNames) {
    const renderer = storage.snapshotByName(pageId, `${name}@${callId}`);
    sha1 = renderer?.closestScreenshot();
    if (sha1)
      break;
  }
  if (!sha1) {
    console.error(`No screenshot found for action '${actionId}'.`);
    process.exitCode = 1;
    return;
  }
  const blob = await loader.resourceForSha1(sha1);
  if (!blob) {
    console.error(`Screenshot resource not found.`);
    process.exitCode = 1;
    return;
  }
  const defaultName = `screenshot-${actionId}.png`;
  const buffer = Buffer.from(await blob.arrayBuffer());
  const outFile = await saveOutputFile(defaultName, buffer, options.output);
  console.log(`  Screenshot saved to ${outFile}`);
}
async function traceAttachments(traceFile) {
  const model = await loadTraceModel(traceFile);
  if (!model.attachments.length) {
    console.log("  No attachments");
    return;
  }
  const { callIdToOrdinal } = buildOrdinalMap(model);
  console.log(`  ${padStart("#", 4)} ${padEnd("Name", 40)} ${padEnd("Content-Type", 30)} ${padEnd("Action", 8)}`);
  console.log(`  ${"\u2500".repeat(4)} ${"\u2500".repeat(40)} ${"\u2500".repeat(30)} ${"\u2500".repeat(8)}`);
  for (let i = 0; i < model.attachments.length; i++) {
    const a = model.attachments[i];
    const actionOrdinal = callIdToOrdinal.get(a.callId);
    console.log(`  ${padStart(i + 1 + ".", 4)} ${padEnd(a.name, 40)} ${padEnd(a.contentType, 30)} ${padEnd(actionOrdinal !== void 0 ? String(actionOrdinal) : a.callId, 8)}`);
  }
}
async function traceAttachment(traceFile, attachmentId, options) {
  const { model, loader } = await loadTrace(traceFile);
  const ordinal = parseInt(attachmentId, 10);
  const attachment = !isNaN(ordinal) && ordinal >= 1 && ordinal <= model.attachments.length ? model.attachments[ordinal - 1] : void 0;
  if (!attachment) {
    console.error(`Attachment '${attachmentId}' not found. Use 'trace attachments' to see available attachments.`);
    process.exitCode = 1;
    return;
  }
  let content;
  if (attachment.sha1) {
    const blob = await loader.resourceForSha1(attachment.sha1);
    if (blob)
      content = Buffer.from(await blob.arrayBuffer());
  } else if (attachment.base64) {
    content = Buffer.from(attachment.base64, "base64");
  }
  if (!content) {
    console.error(`Could not extract attachment content.`);
    process.exitCode = 1;
    return;
  }
  const outFile = await saveOutputFile(attachment.name, content, options.output);
  console.log(`  Attachment saved to ${outFile}`);
}
async function traceInfo(traceFile) {
  const model = await loadTraceModel(traceFile);
  const info = {
    browser: model.browserName || "unknown",
    platform: model.platform || "unknown",
    playwrightVersion: model.playwrightVersion || "unknown",
    title: model.title || "",
    duration: (0, import_formatUtils.msToString)(model.endTime - model.startTime),
    durationMs: model.endTime - model.startTime,
    startTime: model.wallTime ? new Date(model.wallTime).toISOString() : "unknown",
    viewport: model.options.viewport ? `${model.options.viewport.width}x${model.options.viewport.height}` : "default",
    actions: model.actions.length,
    pages: model.pages.length,
    network: model.resources.length,
    errors: model.errorDescriptors.length,
    attachments: model.attachments.length,
    consoleMessages: model.events.filter((e) => e.type === "console").length
  };
  console.log("");
  console.log(`  Browser:      ${info.browser}`);
  console.log(`  Platform:     ${info.platform}`);
  console.log(`  Playwright:   ${info.playwrightVersion}`);
  if (info.title)
    console.log(`  Title:        ${info.title}`);
  console.log(`  Duration:     ${info.duration}`);
  console.log(`  Start time:   ${info.startTime}`);
  console.log(`  Viewport:     ${info.viewport}`);
  console.log(`  Actions:      ${info.actions}`);
  console.log(`  Pages:        ${info.pages}`);
  console.log(`  Network:      ${info.network} requests`);
  console.log(`  Errors:       ${info.errors}`);
  console.log(`  Attachments:  ${info.attachments}`);
  console.log(`  Console:      ${info.consoleMessages} messages`);
  console.log("");
}
async function installSkill() {
  const cwd = process.cwd();
  const skillSource = import_path.default.join(__dirname, "SKILL.md");
  const destDir = import_path.default.join(cwd, ".claude", "playwright-trace");
  await import_fs.default.promises.mkdir(destDir, { recursive: true });
  const destFile = import_path.default.join(destDir, "SKILL.md");
  await import_fs.default.promises.copyFile(skillSource, destFile);
  console.log(`\u2705 Skill installed to \`${import_path.default.relative(cwd, destFile)}\`.`);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  addTraceCommands,
  loadTrace,
  loadTraceModel,
  traceAction,
  traceActions,
  traceAttachment,
  traceAttachments,
  traceConsole,
  traceErrors,
  traceInfo,
  traceRequest,
  traceRequests,
  traceScreenshot,
  traceSnapshot
});
