import {
  AuthManager,
  BUILT_IN_RULES,
  CollectorServer,
  Counter,
  EventStore,
  Gauge,
  HttpServer,
  MetricsRegistry,
  OtelExporter,
  PmStore,
  ProjectDiscovery,
  ProjectManager,
  Redactor,
  RingBuffer,
  SessionManager,
  SessionRateLimiter,
  SqliteStore,
  Wal,
  calculateActiveMinutes,
  calculateCostMicrodollars,
  findPidsInDirectory,
  generateApiKey,
  generateProjectId,
  getListenPorts,
  getOrCreateProjectId,
  getPidsOnPort,
  getProcessCwd,
  getProcessMemoryMB,
  isSqliteAvailable,
  isValidProjectId,
  loadTlsOptions,
  migrateProjectIds,
  otelOptionsFromEnv,
  parseOtelHeaders,
  parseProcessList,
  parseSessionJsonl,
  randomSpanId,
  readProjectConfig,
  resolveProjectAppNames,
  resolveTlsConfig,
  scaffoldProjectConfig,
  traceIdFromSession,
  writeProjectConfig
} from "./chunk-VNRQCY6B.js";
import {
  safeLog
} from "./chunk-CYDXIW4L.js";
import {
  __require
} from "./chunk-UP2VWCW5.js";

// src/issue-detector.ts
function detectIssues(events) {
  const issues = [];
  const networkEvents = events.filter((e) => e.eventType === "network");
  const consoleEvents = events.filter((e) => e.eventType === "console");
  const renderEvents = events.filter((e) => e.eventType === "render");
  const stateEvents = events.filter((e) => e.eventType === "state");
  const perfEvents = events.filter((e) => e.eventType === "performance");
  const dbEvents = events.filter((e) => e.eventType === "database");
  issues.push(...detectFailedRequests(networkEvents));
  issues.push(...detectSlowRequests(networkEvents));
  issues.push(...detectN1Requests(networkEvents));
  issues.push(...detectConsoleErrorSpam(consoleEvents));
  issues.push(...detectHighErrorRate(consoleEvents));
  issues.push(...detectExcessiveRerenders(renderEvents));
  issues.push(...detectLargeStateUpdates(stateEvents));
  issues.push(...detectPoorWebVitals(perfEvents));
  issues.push(...detectSlowDbQueries(dbEvents));
  issues.push(...detectN1DbQueries(dbEvents));
  const order = { high: 0, medium: 1, low: 2 };
  issues.sort((a, b) => order[a.severity] - order[b.severity]);
  return issues;
}
function detectFailedRequests(events) {
  const failed = events.filter((e) => e.status >= 400);
  if (failed.length === 0) return [];
  const grouped = /* @__PURE__ */ new Map();
  for (const e of failed) {
    const key = `${e.status} ${e.method} ${e.url}`;
    const arr = grouped.get(key) ?? [];
    arr.push(e);
    grouped.set(key, arr);
  }
  return Array.from(grouped.entries()).map(([key, evts]) => ({
    id: `failed-request-${key}`,
    pattern: "failed_requests",
    severity: evts[0].status >= 500 ? "high" : "medium",
    title: `Failed request: ${key}`,
    description: `${evts.length} request(s) returned ${evts[0].status}`,
    evidence: evts.slice(0, 3).map(
      (e) => `${e.method} ${e.url} \u2192 ${e.status} (${e.duration.toFixed(0)}ms) at ${new Date(e.timestamp).toISOString()}`
    ),
    suggestion: evts[0].status >= 500 ? "Server error \u2014 check backend logs for this endpoint" : "Client error \u2014 verify the request URL, auth headers, and payload"
  }));
}
function detectSlowRequests(events) {
  const slow = events.filter((e) => e.duration > 3e3);
  if (slow.length === 0) return [];
  return [{
    id: "slow-requests",
    pattern: "slow_requests",
    severity: "medium",
    title: `${slow.length} slow network request(s) (>3s)`,
    description: `Slowest: ${slow.sort((a, b) => b.duration - a.duration)[0].url} at ${(slow[0].duration / 1e3).toFixed(1)}s`,
    evidence: slow.slice(0, 5).map(
      (e) => `${e.method} ${e.url} \u2192 ${(e.duration / 1e3).toFixed(1)}s (status ${e.status})`
    ),
    suggestion: "Consider adding loading states, pagination, or caching for these endpoints"
  }];
}
function detectN1Requests(events) {
  const issues = [];
  const grouped = /* @__PURE__ */ new Map();
  for (const e of events) {
    const key = `${e.method} ${e.url}`;
    const arr = grouped.get(key) ?? [];
    arr.push(e);
    grouped.set(key, arr);
  }
  for (const [key, evts] of grouped) {
    if (evts.length <= 5) continue;
    const sorted = evts.sort((a, b) => a.timestamp - b.timestamp);
    let windowStart = sorted[0].timestamp;
    let windowCount = 1;
    for (let i = 1; i < sorted.length; i++) {
      if (sorted[i].timestamp - windowStart <= 2e3) {
        windowCount++;
      } else {
        windowStart = sorted[i].timestamp;
        windowCount = 1;
      }
      if (windowCount > 5) {
        issues.push({
          id: `n1-${key}`,
          pattern: "n1_requests",
          severity: "medium",
          title: `Possible N+1: ${key}`,
          description: `Called ${evts.length} times total, with ${windowCount}+ in a 2s window. This often happens when each list item fetches its own data.`,
          evidence: [
            `Total calls: ${evts.length}`,
            `Time span: ${((sorted[sorted.length - 1].timestamp - sorted[0].timestamp) / 1e3).toFixed(1)}s`,
            `First call: ${new Date(sorted[0].timestamp).toISOString()}`
          ],
          suggestion: "Lift the data fetch to the parent component, use a batch endpoint, or add a shared cache (e.g. React Query with a shared cache key)"
        });
        break;
      }
    }
  }
  return issues;
}
function detectConsoleErrorSpam(events) {
  const issues = [];
  const errors = events.filter((e) => e.level === "error");
  const grouped = /* @__PURE__ */ new Map();
  for (const e of errors) {
    const key = e.message.slice(0, 200);
    const arr = grouped.get(key) ?? [];
    arr.push(e);
    grouped.set(key, arr);
  }
  for (const [msg, evts] of grouped) {
    if (evts.length <= 5) continue;
    const sorted = evts.sort((a, b) => a.timestamp - b.timestamp);
    const span = sorted[sorted.length - 1].timestamp - sorted[0].timestamp;
    if (span <= 1e4) {
      const truncated = msg.length > 80 ? msg.slice(0, 80) + "..." : msg;
      issues.push({
        id: `error-spam-${msg.slice(0, 50)}`,
        pattern: "console_error_spam",
        severity: "medium",
        title: `Error spam: "${truncated}"`,
        description: `Repeated ${evts.length} times in ${(span / 1e3).toFixed(1)}s. This usually indicates a re-render loop or a recurring failed operation.`,
        evidence: [
          `Count: ${evts.length}`,
          `Time span: ${(span / 1e3).toFixed(1)}s`,
          ...evts[0].stackTrace ? [`Stack: ${evts[0].stackTrace.split("\n")[0]}`] : []
        ],
        suggestion: "Check for re-render loops, retry loops without backoff, or error boundaries that keep re-mounting"
      });
    }
  }
  return issues;
}
function detectHighErrorRate(events) {
  if (events.length < 10) return [];
  const errors = events.filter((e) => e.level === "error");
  const errorRate = errors.length / events.length;
  if (errorRate > 0.3) {
    return [{
      id: "high-error-rate",
      pattern: "high_error_rate",
      severity: "high",
      title: `High console error rate: ${(errorRate * 100).toFixed(0)}%`,
      description: `${errors.length} of ${events.length} console messages are errors. This suggests a systemic issue.`,
      evidence: [
        `Error count: ${errors.length}`,
        `Total console messages: ${events.length}`,
        `Error rate: ${(errorRate * 100).toFixed(0)}%`
      ],
      suggestion: "Check for unhandled promise rejections, missing error boundaries, or misconfigured API endpoints"
    }];
  }
  return [];
}
function detectExcessiveRerenders(events) {
  const issues = [];
  const seen = /* @__PURE__ */ new Set();
  for (const event of events) {
    for (const profile of event.profiles) {
      if (profile.suspicious && !seen.has(profile.componentName)) {
        seen.add(profile.componentName);
        issues.push({
          id: `excessive-rerenders-${profile.componentName}`,
          pattern: "excessive_rerenders",
          severity: "medium",
          title: `Excessive re-renders: <${profile.componentName}>`,
          description: `Rendering at ${profile.renderVelocity.toFixed(1)}/sec (${profile.renderCount} renders in snapshot). Last cause: ${profile.lastRenderCause}.`,
          evidence: [
            `Render velocity: ${profile.renderVelocity.toFixed(1)}/sec`,
            `Render count: ${profile.renderCount}`,
            `Avg duration: ${profile.avgDuration.toFixed(1)}ms`,
            `Last cause: ${profile.lastRenderCause}`
          ],
          suggestion: profile.lastRenderCause === "parent" ? `Wrap <${profile.componentName}> with React.memo() to prevent unnecessary re-renders from parent` : profile.lastRenderCause === "props" ? `Check if props passed to <${profile.componentName}> are stable (useMemo/useCallback for object/function props)` : `Audit state updates in <${profile.componentName}> \u2014 consider batching or debouncing`
        });
      }
    }
  }
  return issues;
}
function detectLargeStateUpdates(events) {
  const issues = [];
  const seen = /* @__PURE__ */ new Set();
  for (const event of events) {
    if (event.phase !== "update") continue;
    const stateStr = JSON.stringify(event.state);
    const sizeKB = Math.round(stateStr.length / 1024);
    if (sizeKB > 100 && !seen.has(event.storeId)) {
      seen.add(event.storeId);
      issues.push({
        id: `large-state-${event.storeId}`,
        pattern: "large_state_update",
        severity: "medium",
        title: `Large state update: ${event.storeId} (${sizeKB}KB)`,
        description: `Store "${event.storeId}" (${event.library}) has a state snapshot of ${sizeKB}KB. Large state can cause slow serialization and re-renders.`,
        evidence: [
          `Store: ${event.storeId}`,
          `Library: ${event.library}`,
          `State size: ${sizeKB}KB`,
          ...event.diff ? [`Changed keys: ${Object.keys(event.diff).join(", ")}`] : []
        ],
        suggestion: "Consider normalizing or splitting the store, and use selectors to subscribe to specific slices"
      });
    }
  }
  return issues;
}
function detectSlowDbQueries(events) {
  const slow = events.filter((e) => e.duration > 500);
  if (slow.length === 0) return [];
  const sorted = slow.sort((a, b) => b.duration - a.duration);
  return [{
    id: "slow-db-queries",
    pattern: "slow_db_queries",
    severity: "medium",
    title: `${slow.length} slow database quer${slow.length === 1 ? "y" : "ies"} (>500ms)`,
    description: `Slowest: ${sorted[0].query.slice(0, 100)} at ${sorted[0].duration.toFixed(0)}ms`,
    evidence: sorted.slice(0, 5).map(
      (e) => `${e.operation} on ${e.tablesAccessed.join(", ") || "?"} \u2192 ${e.duration.toFixed(0)}ms (${e.source})`
    ),
    suggestion: "Add indexes on columns used in WHERE/ORDER BY clauses, or reduce result set size with LIMIT"
  }];
}
function detectN1DbQueries(events) {
  const issues = [];
  const grouped = /* @__PURE__ */ new Map();
  for (const e of events) {
    if (e.operation !== "SELECT") continue;
    const table = e.tablesAccessed[0];
    if (!table) continue;
    const arr = grouped.get(table) ?? [];
    arr.push(e);
    grouped.set(table, arr);
  }
  for (const [table, evts] of grouped) {
    if (evts.length <= 5) continue;
    const sorted = evts.sort((a, b) => a.timestamp - b.timestamp);
    let windowStart = sorted[0].timestamp;
    let windowCount = 1;
    for (let i = 1; i < sorted.length; i++) {
      if (sorted[i].timestamp - windowStart <= 2e3) {
        windowCount++;
      } else {
        windowStart = sorted[i].timestamp;
        windowCount = 1;
      }
      if (windowCount > 5) {
        issues.push({
          id: `n1-db-${table}`,
          pattern: "n1_db_queries",
          severity: "high",
          title: `Possible N+1 DB queries on "${table}"`,
          description: `${evts.length} SELECT queries on "${table}" total, with ${windowCount}+ in a 2s window. This is a classic N+1 pattern.`,
          evidence: [
            `Table: ${table}`,
            `Total SELECTs: ${evts.length}`,
            `Peak burst: ${windowCount}+ in 2s`,
            `Sources: ${[...new Set(evts.map((e) => e.source))].join(", ")}`
          ],
          suggestion: "Use a JOIN, subquery, or batch fetch (e.g. WHERE id IN (...)) instead of querying per item"
        });
        break;
      }
    }
  }
  return issues;
}
function detectPoorWebVitals(events) {
  const issues = [];
  const seen = /* @__PURE__ */ new Set();
  for (const event of events) {
    if (event.rating !== "poor" || seen.has(event.metricName)) continue;
    seen.add(event.metricName);
    const isHighSeverity = event.metricName === "LCP" || event.metricName === "CLS";
    const suggestions = {
      LCP: "Optimize largest image/text block \u2014 preload hero images, use next-gen formats, reduce server response time",
      FCP: "Reduce render-blocking resources \u2014 inline critical CSS, defer non-essential JS",
      CLS: "Set explicit dimensions on images/videos, avoid injecting content above the fold",
      TTFB: "Improve server response time \u2014 add CDN, optimize database queries, enable caching",
      FID: "Break up long tasks \u2014 use requestIdleCallback, code-split heavy modules",
      INP: "Optimize event handlers \u2014 avoid synchronous layouts, defer non-critical work"
    };
    issues.push({
      id: `poor-vital-${event.metricName}`,
      pattern: "poor_web_vital",
      severity: isHighSeverity ? "high" : "medium",
      title: `Poor ${event.metricName}: ${event.value}${event.metricName === "CLS" ? "" : "ms"}`,
      description: `${event.metricName} is rated "poor" (value: ${event.value}). This directly impacts user experience and SEO.`,
      evidence: [
        `Metric: ${event.metricName}`,
        `Value: ${event.value}${event.metricName === "CLS" ? "" : "ms"}`,
        `Rating: ${event.rating}`,
        ...event.element ? [`Element: ${event.element}`] : []
      ],
      suggestion: suggestions[event.metricName] ?? "Review performance best practices at web.dev"
    });
  }
  return issues;
}

// src/engines/api-discovery.ts
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
var NUMERIC_RE = /^\d+$/;
var MONGO_ID_RE = /^[0-9a-f]{24}$/i;
var SHORT_HASH_RE = /^[0-9a-f]{8,}$/i;
var LONG_ALPHANUM_RE = /^[a-zA-Z0-9_-]{20,}$/;
var BASE64_RE = /^[a-zA-Z0-9+/=_-]{16,}$/;
function normalizeSegment(segment) {
  if (UUID_RE.test(segment)) return ":id";
  if (NUMERIC_RE.test(segment)) return ":id";
  if (MONGO_ID_RE.test(segment)) return ":id";
  if (SHORT_HASH_RE.test(segment) && segment.length >= 8) return ":id";
  if (LONG_ALPHANUM_RE.test(segment)) return ":id";
  if (BASE64_RE.test(segment) && segment.length >= 16) return ":token";
  return segment;
}
function normalizeUrl(url) {
  try {
    const parsed = new URL(url);
    const baseUrl = parsed.origin;
    const segments = parsed.pathname.split("/").filter(Boolean);
    const normalized = segments.map(normalizeSegment);
    return { baseUrl, normalizedPath: "/" + normalized.join("/") };
  } catch {
    return { baseUrl: "unknown", normalizedPath: url };
  }
}
var SERVICE_PATTERNS = [
  [/\.supabase\.co$/, "Supabase"],
  [/\.workers\.dev$/, "Cloudflare Workers"],
  [/\.vercel\.app$/, "Vercel"],
  [/api\.stripe\.com$/, "Stripe"],
  [/\.railway\.app$/, "Railway"],
  [/\.netlify\.app$/, "Netlify"],
  [/\.fly\.dev$/, "Fly.io"],
  [/\.render\.com$/, "Render"],
  [/api\.github\.com$/, "GitHub API"],
  [/api\.openai\.com$/, "OpenAI"],
  [/api\.anthropic\.com$/, "Anthropic"],
  [/\.clerk\.dev$/, "Clerk"],
  [/\.auth0\.com$/, "Auth0"],
  [/\.firebase(io|app)\.com$/, "Firebase"],
  [/\.amazonaws\.com$/, "AWS"],
  [/\.googleapis\.com$/, "Google APIs"],
  [/^(localhost|127\.0\.0\.1)$/, "Your API"]
];
function detectService(hostname) {
  for (const [pattern, name] of SERVICE_PATTERNS) {
    if (pattern.test(hostname)) return name;
  }
  const parts = hostname.split(".");
  if (parts.length >= 2) {
    return parts.slice(-2).join(".");
  }
  return hostname;
}
function detectAuth(headers) {
  const authHeader = headers["authorization"] || headers["Authorization"];
  if (authHeader) {
    if (authHeader.startsWith("Bearer ")) return { type: "bearer", headerName: "Authorization" };
    if (authHeader.startsWith("Basic ")) return { type: "basic", headerName: "Authorization" };
    return { type: "api_key", headerName: "Authorization" };
  }
  for (const key of Object.keys(headers)) {
    const lower = key.toLowerCase();
    if (lower.includes("api-key") || lower.includes("apikey") || lower === "x-api-key") {
      return { type: "api_key", headerName: key };
    }
  }
  if (headers["cookie"] || headers["Cookie"]) {
    return { type: "cookie" };
  }
  return { type: "none" };
}
function inferFieldType(value) {
  if (value === null) return "null";
  if (Array.isArray(value)) return "array";
  return typeof value;
}
function walkObject(obj, prefix = "") {
  const fields = [];
  if (obj === null || obj === void 0 || typeof obj !== "object") return fields;
  if (Array.isArray(obj)) {
    fields.push({ path: prefix || "[]", type: "array", nullable: false, example: `[${obj.length} items]` });
    if (obj.length > 0 && typeof obj[0] === "object" && obj[0] !== null) {
      const itemFields = walkObject(obj[0], prefix ? `${prefix}[]` : "[]");
      fields.push(...itemFields);
    }
    return fields;
  }
  for (const [key, value] of Object.entries(obj)) {
    const path = prefix ? `${prefix}.${key}` : key;
    const type = inferFieldType(value);
    fields.push({
      path,
      type,
      nullable: value === null,
      example: typeof value === "string" ? value.slice(0, 50) : value
    });
    if (type === "object" && value !== null) {
      fields.push(...walkObject(value, path));
    }
  }
  return fields;
}
function inferContract(events) {
  const samples = events.slice(-10);
  const responseBodies = samples.filter((e) => e.responseBody).map((e) => {
    try {
      return JSON.parse(e.responseBody);
    } catch {
      return null;
    }
  }).filter(Boolean);
  if (responseBodies.length === 0) return void 0;
  const allFields = /* @__PURE__ */ new Map();
  for (const body of responseBodies) {
    const fields = walkObject(body);
    for (const field of fields) {
      const existing = allFields.get(field.path);
      if (existing) {
        existing.types.add(field.type);
        if (field.nullable) existing.nullable = true;
      } else {
        allFields.set(field.path, {
          types: /* @__PURE__ */ new Set([field.type]),
          nullable: field.nullable,
          example: field.example
        });
      }
    }
  }
  const responseFields = [];
  for (const [path, info] of allFields) {
    responseFields.push({
      path,
      type: [...info.types].join(" | "),
      nullable: info.nullable,
      example: info.example
    });
  }
  return { responseFields, sampleCount: responseBodies.length };
}
function percentile(sorted, p) {
  if (sorted.length === 0) return 0;
  const idx = Math.ceil(sorted.length * (p / 100)) - 1;
  return sorted[Math.max(0, idx)];
}
function endpointKey(method, normalizedPath, baseUrl) {
  return `${method.toUpperCase()} ${baseUrl}${normalizedPath}`;
}
var ApiDiscoveryEngine = class {
  endpoints = /* @__PURE__ */ new Map();
  store;
  lastRebuildEventCount = 0;
  isDirty = true;
  constructor(store) {
    this.store = store;
  }
  /** Mark the cache dirty so the next read triggers a rebuild */
  markDirty() {
    this.isDirty = true;
  }
  rebuild() {
    const events = this.store.getNetworkRequests();
    if (!this.isDirty && events.length === this.lastRebuildEventCount) {
      return;
    }
    this.endpoints.clear();
    for (const event of events) {
      this.ingestEvent(event);
    }
    this.lastRebuildEventCount = events.length;
    this.isDirty = false;
  }
  ingestEvent(event) {
    const { baseUrl, normalizedPath } = normalizeUrl(event.url);
    let hostname;
    try {
      hostname = new URL(event.url).hostname;
    } catch {
      hostname = "unknown";
    }
    const key = endpointKey(event.method, normalizedPath, baseUrl);
    const existing = this.endpoints.get(key);
    if (existing) {
      existing.events.push(event);
      return;
    }
    this.endpoints.set(key, {
      normalizedPath,
      method: event.method.toUpperCase(),
      baseUrl,
      service: detectService(hostname),
      events: [event],
      auth: detectAuth(event.requestHeaders),
      graphqlOperation: event.graphqlOperation
    });
  }
  // --- Refinement pass: parameterize segments with high cardinality ---
  refineEndpoints() {
    const groups = /* @__PURE__ */ new Map();
    for (const ep of this.endpoints.values()) {
      const segments = ep.normalizedPath.split("/").filter(Boolean);
      const groupKey = `${ep.method}|${ep.baseUrl}|${segments.length}`;
      const group = groups.get(groupKey) ?? [];
      group.push(ep);
      groups.set(groupKey, group);
    }
    for (const group of groups.values()) {
      if (group.length <= 5) continue;
      const segmentSets = [];
      for (const ep of group) {
        const segments = ep.normalizedPath.split("/").filter(Boolean);
        for (let i = 0; i < segments.length; i++) {
          if (!segmentSets[i]) segmentSets[i] = /* @__PURE__ */ new Map();
          segmentSets[i].set(segments[i], (segmentSets[i].get(segments[i]) ?? 0) + 1);
        }
      }
      for (let i = 0; i < segmentSets.length; i++) {
        if (segmentSets[i] && segmentSets[i].size > 5) {
          for (const ep of group) {
            const segments = ep.normalizedPath.split("/").filter(Boolean);
            if (segments[i] && segments[i] !== ":id" && segments[i] !== ":token") {
              segments[i] = ":id";
              ep.normalizedPath = "/" + segments.join("/");
            }
          }
        }
      }
    }
    const merged = /* @__PURE__ */ new Map();
    for (const ep of this.endpoints.values()) {
      const key = endpointKey(ep.method, ep.normalizedPath, ep.baseUrl);
      const existing = merged.get(key);
      if (existing) {
        existing.events.push(...ep.events);
      } else {
        merged.set(key, { ...ep });
      }
    }
    this.endpoints = merged;
  }
  // --- Public API ---
  /**
   * Resolve a projectId to the set of sessionIds that belong to it. Returns
   * null when no projectId is supplied (caller should skip filtering). Returns
   * an empty set when the projectId has no known sessions — in that case
   * every endpoint should be excluded from results.
   *
   * The endpoints map is global (built from all network events across every
   * project), so any project-scoped read MUST filter ep.events by sessionId
   * to avoid bleeding traffic from one project into another's tool output.
   */
  resolveProjectSessionIds(projectId) {
    if (!projectId) return null;
    return new Set(this.store.getSessionIdsForProjectId(projectId));
  }
  getCatalog(filter) {
    this.rebuild();
    this.refineEndpoints();
    const sessionIds = this.resolveProjectSessionIds(filter?.projectId);
    const results = [];
    for (const ep of this.endpoints.values()) {
      if (filter?.service && ep.service !== filter.service) continue;
      const events = sessionIds ? ep.events.filter((e) => sessionIds.has(e.sessionId)) : ep.events;
      if (events.length === 0) continue;
      if (filter?.minCalls && events.length < filter.minCalls) continue;
      const timestamps = events.map((e) => e.timestamp);
      results.push({
        normalizedPath: ep.normalizedPath,
        method: ep.method,
        baseUrl: ep.baseUrl,
        service: ep.service,
        callCount: events.length,
        firstSeen: Math.min(...timestamps),
        lastSeen: Math.max(...timestamps),
        auth: ep.auth,
        contract: inferContract(events),
        graphqlOperation: ep.graphqlOperation
      });
    }
    return results.sort((a, b) => b.callCount - a.callCount);
  }
  getHealth(filter) {
    this.rebuild();
    this.refineEndpoints();
    const since = filter?.sinceSeconds ? Date.now() - filter.sinceSeconds * 1e3 : 0;
    const sessionIds = this.resolveProjectSessionIds(filter?.projectId);
    const results = [];
    for (const ep of this.endpoints.values()) {
      if (filter?.endpoint) {
        const key = `${ep.method} ${ep.normalizedPath}`;
        if (!key.includes(filter.endpoint)) continue;
      }
      const events = ep.events.filter((e) => {
        if (e.timestamp < since) return false;
        if (sessionIds && !sessionIds.has(e.sessionId)) return false;
        return true;
      });
      if (events.length === 0) continue;
      const durations = events.map((e) => e.duration).sort((a, b) => a - b);
      const errorCount = events.filter((e) => e.status >= 400).length;
      const errorCodes = {};
      for (const e of events) {
        if (e.status >= 400) {
          errorCodes[e.status] = (errorCodes[e.status] ?? 0) + 1;
        }
      }
      results.push({
        normalizedPath: ep.normalizedPath,
        method: ep.method,
        service: ep.service,
        callCount: events.length,
        successRate: (events.length - errorCount) / events.length,
        avgLatency: durations.reduce((s, d) => s + d, 0) / durations.length,
        p50Latency: percentile(durations, 50),
        p95Latency: percentile(durations, 95),
        errorRate: errorCount / events.length,
        errorCodes
      });
    }
    return results.sort((a, b) => b.callCount - a.callCount);
  }
  getDocumentation(filter) {
    const catalog = this.getCatalog(filter ? { service: filter.service, projectId: filter.projectId } : void 0);
    const health = this.getHealth(filter ? { projectId: filter.projectId } : void 0);
    const healthMap = new Map(health.map((h) => [`${h.method} ${h.normalizedPath}`, h]));
    const lines = ["# API Documentation (Auto-Generated from Traffic)", ""];
    const byService = /* @__PURE__ */ new Map();
    for (const ep of catalog) {
      const list = byService.get(ep.service) ?? [];
      list.push(ep);
      byService.set(ep.service, list);
    }
    for (const [service, endpoints] of byService) {
      lines.push(`## ${service}`, "");
      for (const ep of endpoints) {
        const h = healthMap.get(`${ep.method} ${ep.normalizedPath}`);
        lines.push(`### ${ep.method} ${ep.normalizedPath}`);
        lines.push(`- Base URL: ${ep.baseUrl}`);
        lines.push(`- Calls: ${ep.callCount}`);
        lines.push(`- Auth: ${ep.auth.type}${ep.auth.headerName ? ` (${ep.auth.headerName})` : ""}`);
        if (h) {
          lines.push(`- Avg Latency: ${h.avgLatency.toFixed(0)}ms`);
          lines.push(`- P95 Latency: ${h.p95Latency.toFixed(0)}ms`);
          lines.push(`- Error Rate: ${(h.errorRate * 100).toFixed(1)}%`);
        }
        if (ep.graphqlOperation) {
          lines.push(`- GraphQL: ${ep.graphqlOperation.type} ${ep.graphqlOperation.name}`);
        }
        if (ep.contract) {
          lines.push("- Response Shape:");
          for (const field of ep.contract.responseFields.slice(0, 20)) {
            lines.push(`  - \`${field.path}\`: ${field.type}${field.nullable ? " (nullable)" : ""}`);
          }
          if (ep.contract.responseFields.length > 20) {
            lines.push(`  - ... and ${ep.contract.responseFields.length - 20} more fields`);
          }
        }
        lines.push("");
      }
    }
    return lines.join("\n");
  }
  getServiceMap(filter) {
    this.rebuild();
    this.refineEndpoints();
    const sessionIds = this.resolveProjectSessionIds(filter?.projectId);
    const services = /* @__PURE__ */ new Map();
    for (const ep of this.endpoints.values()) {
      const events = sessionIds ? ep.events.filter((e) => sessionIds.has(e.sessionId)) : ep.events;
      if (events.length === 0) continue;
      const existing = services.get(ep.service);
      if (existing) {
        existing.endpoints.add(`${ep.method} ${ep.normalizedPath}`);
        existing.totalCalls += events.length;
        existing.totalDuration += events.reduce((s, e) => s + e.duration, 0);
        existing.errorCount += events.filter((e) => e.status >= 400).length;
      } else {
        let detectedPlatform;
        try {
          const hostname = new URL(ep.baseUrl).hostname;
          for (const [pattern, name] of SERVICE_PATTERNS) {
            if (pattern.test(hostname)) {
              detectedPlatform = name;
              break;
            }
          }
        } catch {
        }
        services.set(ep.service, {
          baseUrl: ep.baseUrl,
          endpoints: /* @__PURE__ */ new Set([`${ep.method} ${ep.normalizedPath}`]),
          totalCalls: events.length,
          totalDuration: events.reduce((s, e) => s + e.duration, 0),
          errorCount: events.filter((e) => e.status >= 400).length,
          auth: ep.auth,
          platform: detectedPlatform
        });
      }
    }
    const results = [];
    for (const [name, data] of services) {
      results.push({
        name,
        baseUrl: data.baseUrl,
        endpointCount: data.endpoints.size,
        totalCalls: data.totalCalls,
        avgLatency: data.totalCalls > 0 ? data.totalDuration / data.totalCalls : 0,
        errorRate: data.totalCalls > 0 ? data.errorCount / data.totalCalls : 0,
        auth: data.auth,
        detectedPlatform: data.platform
      });
    }
    return results.sort((a, b) => b.totalCalls - a.totalCalls);
  }
  getApiChanges(sessionA, sessionB) {
    const allEvents = this.store.getNetworkRequests();
    const eventsA = allEvents.filter((e) => e.sessionId === sessionA);
    const eventsB = allEvents.filter((e) => e.sessionId === sessionB);
    const catalogA = this.buildCatalogFromEvents(eventsA);
    const catalogB = this.buildCatalogFromEvents(eventsB);
    const changes = [];
    const allKeys = /* @__PURE__ */ new Set([...catalogA.keys(), ...catalogB.keys()]);
    for (const key of allKeys) {
      const a = catalogA.get(key);
      const b = catalogB.get(key);
      if (!a && b) {
        changes.push({
          normalizedPath: b.normalizedPath,
          method: b.method,
          changeType: "added"
        });
      } else if (a && !b) {
        changes.push({
          normalizedPath: a.normalizedPath,
          method: a.method,
          changeType: "removed"
        });
      } else if (a && b) {
        const contractA = inferContract(a.events);
        const contractB = inferContract(b.events);
        if (contractA && contractB) {
          const fieldsA = new Map(contractA.responseFields.map((f) => [f.path, f.type]));
          const fieldsB = new Map(contractB.responseFields.map((f) => [f.path, f.type]));
          const fieldChanges = [];
          for (const [path, type] of fieldsB) {
            if (!fieldsA.has(path)) {
              fieldChanges.push({ path, change: "added", newType: type });
            } else if (fieldsA.get(path) !== type) {
              fieldChanges.push({ path, change: "type_changed", oldType: fieldsA.get(path), newType: type });
            }
          }
          for (const [path] of fieldsA) {
            if (!fieldsB.has(path)) {
              fieldChanges.push({ path, change: "removed", oldType: fieldsA.get(path) });
            }
          }
          if (fieldChanges.length > 0) {
            changes.push({
              normalizedPath: a.normalizedPath,
              method: a.method,
              changeType: "modified",
              fieldChanges
            });
          }
        }
      }
    }
    return changes;
  }
  buildCatalogFromEvents(events) {
    const catalog = /* @__PURE__ */ new Map();
    for (const event of events) {
      const { baseUrl, normalizedPath } = normalizeUrl(event.url);
      let hostname;
      try {
        hostname = new URL(event.url).hostname;
      } catch {
        hostname = "unknown";
      }
      const key = endpointKey(event.method, normalizedPath, baseUrl);
      const existing = catalog.get(key);
      if (existing) {
        existing.events.push(event);
      } else {
        catalog.set(key, {
          normalizedPath,
          method: event.method.toUpperCase(),
          baseUrl,
          service: detectService(hostname),
          events: [event],
          auth: detectAuth(event.requestHeaders),
          graphqlOperation: event.graphqlOperation
        });
      }
    }
    return catalog;
  }
  detectIssues(projectId) {
    const issues = [];
    const health = this.getHealth({ projectId });
    for (const ep of health) {
      if (ep.errorRate > 0.5 && ep.callCount >= 3) {
        issues.push({
          id: `api-degradation-${ep.method}-${ep.normalizedPath}`,
          pattern: "api_degradation",
          severity: "medium",
          title: `API Degradation: ${ep.method} ${ep.normalizedPath}`,
          description: `Error rate is ${(ep.errorRate * 100).toFixed(0)}% (${Object.entries(ep.errorCodes).map(([k, v]) => `${k}: ${v}`).join(", ")})`,
          evidence: [`${ep.callCount} calls, ${(ep.errorRate * 100).toFixed(0)}% errors`],
          suggestion: "Check server logs for this endpoint. Verify the backend is healthy."
        });
      }
      if (ep.p95Latency > 5e3 && ep.callCount >= 3) {
        issues.push({
          id: `high-latency-${ep.method}-${ep.normalizedPath}`,
          pattern: "high_latency_endpoint",
          severity: "medium",
          title: `High Latency: ${ep.method} ${ep.normalizedPath}`,
          description: `P95 latency is ${(ep.p95Latency / 1e3).toFixed(1)}s`,
          evidence: [`p50: ${ep.p50Latency.toFixed(0)}ms, p95: ${ep.p95Latency.toFixed(0)}ms, avg: ${ep.avgLatency.toFixed(0)}ms`],
          suggestion: "Consider adding caching, optimizing the query, or paginating the response."
        });
      }
    }
    const services = this.getServiceMap({ projectId });
    const catalog = this.getCatalog({ projectId });
    for (const service of services) {
      const serviceEndpoints = catalog.filter((ep) => ep.service === service.name);
      const authTypes = new Set(serviceEndpoints.map((ep) => ep.auth.type));
      if (authTypes.size > 1 && !authTypes.has("none")) {
        issues.push({
          id: `auth-inconsistency-${service.name}`,
          pattern: "auth_inconsistency",
          severity: "medium",
          title: `Auth Inconsistency: ${service.name}`,
          description: `Mixed auth patterns detected: ${[...authTypes].join(", ")}`,
          evidence: serviceEndpoints.map((ep) => `${ep.method} ${ep.normalizedPath}: ${ep.auth.type}`),
          suggestion: "Verify that all endpoints for this service use consistent authentication."
        });
      }
    }
    return issues;
  }
};

// src/engines/query-monitor.ts
function percentile2(sorted, p) {
  if (sorted.length === 0) return 0;
  const idx = Math.ceil(sorted.length * (p / 100)) - 1;
  return sorted[Math.max(0, idx)];
}
function aggregateQueryStats(events) {
  const groups = /* @__PURE__ */ new Map();
  for (const e of events) {
    const key = e.normalizedQuery;
    const group = groups.get(key) ?? [];
    group.push(e);
    groups.set(key, group);
  }
  const stats = [];
  for (const [normalizedQuery, groupEvents] of groups) {
    const durations = groupEvents.map((e) => e.duration).sort((a, b) => a - b);
    const totalDuration = durations.reduce((s, d) => s + d, 0);
    const tables = /* @__PURE__ */ new Set();
    for (const e of groupEvents) {
      for (const t of e.tablesAccessed) tables.add(t);
    }
    const rowCounts = groupEvents.filter((e) => e.rowsReturned !== void 0).map((e) => e.rowsReturned);
    stats.push({
      normalizedQuery,
      tables: [...tables],
      operation: groupEvents[0].operation,
      callCount: groupEvents.length,
      avgDuration: totalDuration / groupEvents.length,
      maxDuration: Math.max(...durations),
      p95Duration: percentile2(durations, 95),
      totalDuration,
      avgRowsReturned: rowCounts.length > 0 ? rowCounts.reduce((s, r) => s + r, 0) / rowCounts.length : 0
    });
  }
  return stats.sort((a, b) => b.totalDuration - a.totalDuration);
}
function detectN1Queries(events) {
  const issues = [];
  const tableWindows = /* @__PURE__ */ new Map();
  for (const e of events) {
    if (e.operation !== "SELECT") continue;
    for (const table of e.tablesAccessed) {
      const entry = tableWindows.get(table) ?? { timestamps: [], queries: [] };
      entry.timestamps.push(e.timestamp);
      entry.queries.push(e.query);
      tableWindows.set(table, entry);
    }
  }
  for (const [table, data] of tableWindows) {
    const sorted = data.timestamps.sort((a, b) => a - b);
    let windowStart = 0;
    for (let i = 0; i < sorted.length; i++) {
      while (sorted[i] - sorted[windowStart] > 2e3) windowStart++;
      const windowSize = i - windowStart + 1;
      if (windowSize > 5) {
        issues.push({
          id: `n1-${table}-${sorted[windowStart]}`,
          pattern: "n1_db_query",
          severity: "high",
          title: `N+1 Query Pattern: ${table}`,
          description: `${windowSize} SELECT queries on table "${table}" within 2 seconds. This is a classic N+1 query pattern.`,
          evidence: [
            `${windowSize} queries in ${((sorted[i] - sorted[windowStart]) / 1e3).toFixed(1)}s`,
            `Sample: ${data.queries[windowStart]?.slice(0, 100)}`
          ],
          suggestion: `Use a JOIN or batch query (e.g., WHERE id IN (...)) instead of querying "${table}" in a loop.`
        });
        windowStart = i + 1;
      }
    }
  }
  return issues;
}
function detectSlowQueries(events, thresholdMs = 500) {
  const issues = [];
  const seen = /* @__PURE__ */ new Set();
  for (const e of events) {
    if (e.duration >= thresholdMs && !seen.has(e.normalizedQuery)) {
      seen.add(e.normalizedQuery);
      issues.push({
        id: `slow-query-${e.eventId}`,
        pattern: "slow_db_query",
        severity: e.duration > 2e3 ? "high" : "medium",
        title: `Slow Query: ${e.duration.toFixed(0)}ms`,
        description: `Query took ${e.duration.toFixed(0)}ms (threshold: ${thresholdMs}ms). Tables: ${e.tablesAccessed.join(", ") || "unknown"}.`,
        evidence: [
          `Duration: ${e.duration.toFixed(0)}ms`,
          `Query: ${e.query.slice(0, 150)}`,
          e.rowsReturned !== void 0 ? `Rows returned: ${e.rowsReturned}` : ""
        ].filter(Boolean),
        suggestion: "Consider adding indexes, reducing the result set, or optimizing the query."
      });
    }
  }
  return issues;
}
function suggestIndexes(events) {
  const suggestions = [];
  const seen = /* @__PURE__ */ new Set();
  const WHERE_COL_RE = /WHERE\s+.*?["'`]?(\w+)["'`]?\s*(=|>|<|>=|<=|!=|LIKE|IN|IS)\s/gi;
  const ORDER_COL_RE = /ORDER\s+BY\s+["'`]?(\w+)["'`]?/gi;
  for (const e of events) {
    if (e.duration < 100) continue;
    for (const table of e.tablesAccessed) {
      const columns = [];
      let match;
      const whereRe = new RegExp(WHERE_COL_RE.source, WHERE_COL_RE.flags);
      while ((match = whereRe.exec(e.query)) !== null) {
        columns.push(match[1]);
      }
      const orderRe = new RegExp(ORDER_COL_RE.source, ORDER_COL_RE.flags);
      while ((match = orderRe.exec(e.query)) !== null) {
        columns.push(match[1]);
      }
      if (columns.length === 0) continue;
      const key = `${table}:${columns.sort().join(",")}`;
      if (seen.has(key)) continue;
      seen.add(key);
      suggestions.push({
        table,
        columns,
        reason: `Query taking ${e.duration.toFixed(0)}ms uses these columns in WHERE/ORDER BY`,
        estimatedImpact: e.duration > 1e3 ? "high" : e.duration > 300 ? "medium" : "low",
        queryPattern: e.normalizedQuery.slice(0, 150)
      });
    }
  }
  return suggestions;
}
function detectOverfetching(events) {
  const issues = [];
  const seen = /* @__PURE__ */ new Set();
  for (const e of events) {
    if (e.operation !== "SELECT") continue;
    if (e.query.match(/SELECT\s+\*/i) && e.rowsReturned !== void 0 && e.rowsReturned > 100) {
      const key = e.normalizedQuery;
      if (seen.has(key)) continue;
      seen.add(key);
      issues.push({
        id: `overfetch-${e.eventId}`,
        pattern: "overfetching",
        severity: e.rowsReturned > 1e3 ? "high" : "medium",
        title: `Overfetching: SELECT * returning ${e.rowsReturned} rows`,
        description: `Query uses SELECT * and returns ${e.rowsReturned} rows. Tables: ${e.tablesAccessed.join(", ")}.`,
        evidence: [
          `Query: ${e.query.slice(0, 150)}`,
          `Rows: ${e.rowsReturned}`
        ],
        suggestion: "Select only the columns you need and add LIMIT if appropriate."
      });
    }
  }
  return issues;
}

// src/db/connections.ts
var ConnectionManager = class {
  connections = /* @__PURE__ */ new Map();
  async addConnection(config) {
    const client = await this.createClient(config);
    this.connections.set(config.id, {
      config,
      client,
      isHealthy: true,
      lastChecked: Date.now()
    });
  }
  getConnection(id) {
    return this.connections.get(id);
  }
  listConnections() {
    return Array.from(this.connections.values()).map((c) => ({
      id: c.config.id,
      type: c.config.type,
      label: c.config.label,
      isHealthy: c.isHealthy
    }));
  }
  async healthCheck(id) {
    const conn = this.connections.get(id);
    if (!conn) return false;
    try {
      if (conn.config.type === "postgres") {
        const pg = conn.client;
        await pg.query("SELECT 1");
      } else if (conn.config.type === "mysql") {
        const mysql = conn.client;
        await mysql.query("SELECT 1");
      } else if (conn.config.type === "sqlite") {
        const db = conn.client;
        db.prepare("SELECT 1").get();
      }
      conn.isHealthy = true;
    } catch {
      conn.isHealthy = false;
    }
    conn.lastChecked = Date.now();
    return conn.isHealthy;
  }
  async closeConnection(id) {
    const conn = this.connections.get(id);
    if (!conn) return;
    try {
      if (conn.config.type === "postgres") {
        await conn.client.end();
      } else if (conn.config.type === "mysql") {
        await conn.client.end();
      } else if (conn.config.type === "sqlite") {
        conn.client.close();
      }
    } catch {
    }
    this.connections.delete(id);
  }
  async closeAll() {
    const ids = [...this.connections.keys()];
    for (const id of ids) {
      await this.closeConnection(id);
    }
  }
  // Dynamic require wrapper to avoid TypeScript module resolution at compile time
  // eslint-disable-next-line @typescript-eslint/no-require-imports
  dynamicRequire(mod) {
    try {
      return __require(mod);
    } catch {
      throw new Error(`Module '${mod}' not found. Install it: npm install ${mod}`);
    }
  }
  async createClient(config) {
    switch (config.type) {
      case "postgres": {
        try {
          const pg = this.dynamicRequire("pg");
          const pool = new pg.Pool({ connectionString: config.connectionString });
          await pool.query("SELECT 1");
          return pool;
        } catch (err) {
          throw new Error(`Failed to connect to PostgreSQL: ${err.message}. Ensure 'pg' is installed.`);
        }
      }
      case "mysql": {
        try {
          const mysql2 = this.dynamicRequire("mysql2/promise");
          const pool = mysql2.createPool(config.connectionString);
          await pool.query("SELECT 1");
          return pool;
        } catch (err) {
          throw new Error(`Failed to connect to MySQL: ${err.message}. Ensure 'mysql2' is installed.`);
        }
      }
      case "sqlite": {
        try {
          const BetterSqlite3 = this.dynamicRequire("better-sqlite3");
          return new BetterSqlite3(config.connectionString);
        } catch (err) {
          throw new Error(`Failed to open SQLite: ${err.message}. Ensure 'better-sqlite3' is installed.`);
        }
      }
      default:
        throw new Error(`Unsupported database type: ${config.type}`);
    }
  }
};

// src/db/schema-introspector.ts
var SchemaIntrospector = class {
  async introspect(connection, tableName) {
    switch (connection.config.type) {
      case "postgres":
        return this.introspectPostgres(connection, tableName);
      case "mysql":
        return this.introspectMysql(connection, tableName);
      case "sqlite":
        return this.introspectSqlite(connection, tableName);
      default:
        throw new Error(`Unsupported database type: ${connection.config.type}`);
    }
  }
  async introspectPostgres(conn, tableName) {
    const pg = conn.client;
    const tableFilter = tableName ? `AND table_name = $1` : "";
    const tableParams = tableName ? [tableName] : [];
    const tablesResult = await pg.query(
      `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ${tableFilter} ORDER BY table_name`,
      tableParams
    );
    const tables = [];
    for (const row of tablesResult.rows) {
      const tName = row.table_name;
      const colsResult = await pg.query(
        `SELECT column_name, data_type, is_nullable, column_default
         FROM information_schema.columns
         WHERE table_schema = 'public' AND table_name = $1
         ORDER BY ordinal_position`,
        [tName]
      );
      const pkResult = await pg.query(
        `SELECT kcu.column_name
         FROM information_schema.table_constraints tc
         JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
         WHERE tc.table_schema = 'public' AND tc.table_name = $1 AND tc.constraint_type = 'PRIMARY KEY'`,
        [tName]
      );
      const pkColumns = new Set(pkResult.rows.map((r) => r.column_name));
      const columns = colsResult.rows.map((r) => ({
        name: r.column_name,
        type: r.data_type,
        nullable: r.is_nullable === "YES",
        defaultValue: r.column_default,
        isPrimaryKey: pkColumns.has(r.column_name)
      }));
      const fkResult = await pg.query(
        `SELECT kcu.column_name, ccu.table_name AS referenced_table, ccu.column_name AS referenced_column
         FROM information_schema.table_constraints tc
         JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
         JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
         WHERE tc.table_schema = 'public' AND tc.table_name = $1 AND tc.constraint_type = 'FOREIGN KEY'`,
        [tName]
      );
      const foreignKeys = fkResult.rows.map((r) => ({
        column: r.column_name,
        referencedTable: r.referenced_table,
        referencedColumn: r.referenced_column
      }));
      const idxResult = await pg.query(
        `SELECT indexname, indexdef FROM pg_indexes WHERE tablename = $1 AND schemaname = 'public'`,
        [tName]
      );
      const indexes = idxResult.rows.map((r) => {
        const indexDef = r.indexdef;
        const isUnique = indexDef.includes("UNIQUE");
        const colMatch = indexDef.match(/\(([^)]+)\)/);
        const idxCols = colMatch ? colMatch[1].split(",").map((c) => c.trim().replace(/"/g, "")) : [];
        return {
          name: r.indexname,
          columns: idxCols,
          unique: isUnique
        };
      });
      const countResult = await pg.query(
        `SELECT reltuples::bigint AS estimate FROM pg_class WHERE relname = $1`,
        [tName]
      );
      const rowCount = countResult.rows[0]?.estimate;
      tables.push({ name: tName, columns, foreignKeys, indexes, rowCount: rowCount ?? void 0 });
    }
    return { connectionId: conn.config.id, tables, fetchedAt: Date.now() };
  }
  async introspectMysql(conn, tableName) {
    const mysql = conn.client;
    const tableFilter = tableName ? `AND table_name = ?` : "";
    const tableParams = tableName ? [tableName] : [];
    const [tableRows] = await mysql.query(
      `SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() ${tableFilter} ORDER BY table_name`,
      tableParams
    );
    const tables = [];
    for (const row of tableRows) {
      const tName = row.table_name;
      const [colRows] = await mysql.query(
        `SELECT column_name, data_type, is_nullable, column_default, column_key
         FROM information_schema.columns
         WHERE table_schema = DATABASE() AND table_name = ?
         ORDER BY ordinal_position`,
        [tName]
      );
      const columns = colRows.map((r) => ({
        name: r.column_name,
        type: r.data_type,
        nullable: r.is_nullable === "YES",
        defaultValue: r.column_default,
        isPrimaryKey: r.column_key === "PRI"
      }));
      const [fkRows] = await mysql.query(
        `SELECT column_name, referenced_table_name, referenced_column_name
         FROM information_schema.key_column_usage
         WHERE table_schema = DATABASE() AND table_name = ? AND referenced_table_name IS NOT NULL`,
        [tName]
      );
      const foreignKeys = fkRows.map((r) => ({
        column: r.column_name,
        referencedTable: r.referenced_table_name,
        referencedColumn: r.referenced_column_name
      }));
      const [idxRows] = await mysql.query(`SHOW INDEX FROM \`${tName}\``);
      const indexMap = /* @__PURE__ */ new Map();
      for (const r of idxRows) {
        const name = r.Key_name;
        const existing = indexMap.get(name) ?? { columns: [], unique: r.Non_unique === 0 };
        existing.columns.push(r.Column_name);
        indexMap.set(name, existing);
      }
      const indexes = Array.from(indexMap.entries()).map(([name, data]) => ({
        name,
        columns: data.columns,
        unique: data.unique
      }));
      tables.push({ name: tName, columns, foreignKeys, indexes });
    }
    return { connectionId: conn.config.id, tables, fetchedAt: Date.now() };
  }
  async introspectSqlite(conn, tableName) {
    const db = conn.client;
    let tableNames;
    if (tableName) {
      tableNames = [tableName];
    } else {
      const rows = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`).all();
      tableNames = rows.map((r) => r.name);
    }
    const tables = [];
    for (const tName of tableNames) {
      const colRows = db.prepare(`PRAGMA table_info("${tName}")`).all();
      const columns = colRows.map((r) => ({
        name: r.name,
        type: r.type,
        nullable: r.notnull === 0,
        defaultValue: r.dflt_value,
        isPrimaryKey: r.pk > 0
      }));
      const fkRows = db.prepare(`PRAGMA foreign_key_list("${tName}")`).all();
      const foreignKeys = fkRows.map((r) => ({
        column: r.from,
        referencedTable: r.table,
        referencedColumn: r.to
      }));
      const idxRows = db.prepare(`PRAGMA index_list("${tName}")`).all();
      const indexes = idxRows.map((r) => {
        const idxInfoRows = db.prepare(`PRAGMA index_info("${r.name}")`).all();
        return {
          name: r.name,
          columns: idxInfoRows.map((ir) => ir.name),
          unique: r.unique === 1
        };
      });
      const countRow = db.prepare(`SELECT COUNT(*) as count FROM "${tName}"`).all()[0];
      const rowCount = countRow?.count;
      tables.push({ name: tName, columns, foreignKeys, indexes, rowCount });
    }
    return { connectionId: conn.config.id, tables, fetchedAt: Date.now() };
  }
};

// src/db/data-browser.ts
var MAX_AFFECTED_ROWS = 100;
var DataBrowser = class {
  async read(connection, options) {
    const limit = Math.min(options.limit ?? 50, 1e3);
    const offset = options.offset ?? 0;
    switch (connection.config.type) {
      case "postgres":
        return this.readPostgres(connection, options, limit, offset);
      case "mysql":
        return this.readMysql(connection, options, limit, offset);
      case "sqlite":
        return this.readSqlite(connection, options, limit, offset);
      default:
        throw new Error(`Unsupported database type: ${connection.config.type}`);
    }
  }
  async write(connection, options) {
    this.assertLocalhost(connection);
    if ((options.operation === "update" || options.operation === "delete") && !options.where) {
      return { success: false, affectedRows: 0, error: "WHERE clause is required for UPDATE and DELETE operations" };
    }
    switch (connection.config.type) {
      case "postgres":
        return this.writePostgres(connection, options);
      case "mysql":
        return this.writeMysql(connection, options);
      case "sqlite":
        return this.writeSqlite(connection, options);
      default:
        throw new Error(`Unsupported database type: ${connection.config.type}`);
    }
  }
  assertLocalhost(connection) {
    const connStr = connection.config.connectionString ?? "";
    const isLocal = connStr.includes("localhost") || connStr.includes("127.0.0.1") || connStr.includes("0.0.0.0") || connection.config.type === "sqlite";
    if (!isLocal) {
      throw new Error("Write operations are only allowed on localhost/local database connections. This safety guard prevents accidental modification of production databases.");
    }
  }
  // --- PostgreSQL ---
  async readPostgres(conn, opts, limit, offset) {
    const pg = conn.client;
    const where = opts.where ? `WHERE ${opts.where}` : "";
    const orderBy = opts.orderBy ? `ORDER BY ${opts.orderBy}` : "";
    const countResult = await pg.query(`SELECT COUNT(*) as total FROM "${opts.table}" ${where}`);
    const total = parseInt(countResult.rows[0].total, 10);
    const result = await pg.query(`SELECT * FROM "${opts.table}" ${where} ${orderBy} LIMIT ${limit} OFFSET ${offset}`);
    return { rows: result.rows, total, limit, offset };
  }
  async writePostgres(conn, opts) {
    const pg = conn.client;
    try {
      if (opts.operation !== "insert" && opts.where) {
        const countResult = await pg.query(`SELECT COUNT(*) as cnt FROM "${opts.table}" WHERE ${opts.where}`);
        const count = parseInt(countResult.rows[0].cnt, 10);
        if (count > MAX_AFFECTED_ROWS) {
          return { success: false, affectedRows: 0, error: `Operation would affect ${count} rows (max ${MAX_AFFECTED_ROWS}). Narrow your WHERE clause.` };
        }
      }
      await pg.query("BEGIN");
      let result;
      switch (opts.operation) {
        case "insert": {
          const cols = Object.keys(opts.data);
          const vals = Object.values(opts.data).map((v) => typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v);
          result = await pg.query(`INSERT INTO "${opts.table}" (${cols.join(", ")}) VALUES (${vals.join(", ")})`);
          break;
        }
        case "update": {
          const sets = Object.entries(opts.data).map(
            ([k, v]) => `${k} = ${typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v}`
          );
          result = await pg.query(`UPDATE "${opts.table}" SET ${sets.join(", ")} WHERE ${opts.where}`);
          break;
        }
        case "delete":
          result = await pg.query(`DELETE FROM "${opts.table}" WHERE ${opts.where}`);
          break;
        default:
          throw new Error(`Unknown operation: ${opts.operation}`);
      }
      await pg.query("COMMIT");
      return { success: true, affectedRows: result.rowCount };
    } catch (err) {
      await pg.query("ROLLBACK").catch(() => {
      });
      return { success: false, affectedRows: 0, error: err.message };
    }
  }
  // --- MySQL ---
  async readMysql(conn, opts, limit, offset) {
    const mysql = conn.client;
    const where = opts.where ? `WHERE ${opts.where}` : "";
    const orderBy = opts.orderBy ? `ORDER BY ${opts.orderBy}` : "";
    const [countRows] = await mysql.query(`SELECT COUNT(*) as total FROM \`${opts.table}\` ${where}`);
    const total = countRows[0].total;
    const [rows] = await mysql.query(`SELECT * FROM \`${opts.table}\` ${where} ${orderBy} LIMIT ${limit} OFFSET ${offset}`);
    return { rows, total, limit, offset };
  }
  async writeMysql(conn, opts) {
    const mysql = conn.client;
    try {
      if (opts.operation !== "insert" && opts.where) {
        const [countRows] = await mysql.query(`SELECT COUNT(*) as cnt FROM \`${opts.table}\` WHERE ${opts.where}`);
        const count = countRows[0].cnt;
        if (count > MAX_AFFECTED_ROWS) {
          return { success: false, affectedRows: 0, error: `Operation would affect ${count} rows (max ${MAX_AFFECTED_ROWS}).` };
        }
      }
      await mysql.query("START TRANSACTION");
      let result;
      switch (opts.operation) {
        case "insert": {
          const cols = Object.keys(opts.data);
          const vals = Object.values(opts.data).map((v) => typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v);
          result = await mysql.query(`INSERT INTO \`${opts.table}\` (${cols.join(", ")}) VALUES (${vals.join(", ")})`);
          break;
        }
        case "update": {
          const sets = Object.entries(opts.data).map(
            ([k, v]) => `\`${k}\` = ${typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v}`
          );
          result = await mysql.query(`UPDATE \`${opts.table}\` SET ${sets.join(", ")} WHERE ${opts.where}`);
          break;
        }
        case "delete":
          result = await mysql.query(`DELETE FROM \`${opts.table}\` WHERE ${opts.where}`);
          break;
        default:
          throw new Error(`Unknown operation: ${opts.operation}`);
      }
      await mysql.query("COMMIT");
      return { success: true, affectedRows: result[0].affectedRows };
    } catch (err) {
      await mysql.query("ROLLBACK").catch(() => {
      });
      return { success: false, affectedRows: 0, error: err.message };
    }
  }
  // --- SQLite ---
  async readSqlite(conn, opts, limit, offset) {
    const db = conn.client;
    const where = opts.where ? `WHERE ${opts.where}` : "";
    const orderBy = opts.orderBy ? `ORDER BY ${opts.orderBy}` : "";
    const countRow = db.prepare(`SELECT COUNT(*) as total FROM "${opts.table}" ${where}`).get();
    const total = countRow.total;
    const rows = db.prepare(`SELECT * FROM "${opts.table}" ${where} ${orderBy} LIMIT ${limit} OFFSET ${offset}`).all();
    return { rows, total, limit, offset };
  }
  async writeSqlite(conn, opts) {
    const db = conn.client;
    try {
      if (opts.operation !== "insert" && opts.where) {
        const countRow = db.prepare(`SELECT COUNT(*) as cnt FROM "${opts.table}" WHERE ${opts.where}`).get();
        const count = countRow.cnt;
        if (count > MAX_AFFECTED_ROWS) {
          return { success: false, affectedRows: 0, error: `Operation would affect ${count} rows (max ${MAX_AFFECTED_ROWS}).` };
        }
      }
      db.exec("BEGIN");
      let changes;
      switch (opts.operation) {
        case "insert": {
          const cols = Object.keys(opts.data);
          const vals = Object.values(opts.data).map((v) => typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v);
          const result = db.prepare(`INSERT INTO "${opts.table}" (${cols.join(", ")}) VALUES (${vals.join(", ")})`).run();
          changes = result.changes;
          break;
        }
        case "update": {
          const sets = Object.entries(opts.data).map(
            ([k, v]) => `"${k}" = ${typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v}`
          );
          const result = db.prepare(`UPDATE "${opts.table}" SET ${sets.join(", ")} WHERE ${opts.where}`).run();
          changes = result.changes;
          break;
        }
        case "delete": {
          const result = db.prepare(`DELETE FROM "${opts.table}" WHERE ${opts.where}`).run();
          changes = result.changes;
          break;
        }
        default:
          throw new Error(`Unknown operation: ${opts.operation}`);
      }
      db.exec("COMMIT");
      return { success: true, affectedRows: changes };
    } catch (err) {
      try {
        db.exec("ROLLBACK");
      } catch {
      }
      return { success: false, affectedRows: 0, error: err.message };
    }
  }
};

// src/engines/process-monitor.ts
var PROCESS_PATTERNS = [
  [/next[\s-]dev|next-server/, "next"],
  [/vite/, "vite"],
  [/webpack[\s-]dev[\s-]server|webpack serve/, "webpack"],
  [/wrangler/, "wrangler"],
  [/prisma\s+studio|prisma\s+dev/, "prisma"],
  [/docker/, "docker"],
  [/postgres|pg_/, "postgres"],
  [/mysqld/, "mysql"],
  [/redis-server/, "redis"],
  [/\bbun\b/, "bun"],
  [/\bdeno\b/, "deno"],
  [/\bpython[23]?\b/, "python"],
  [/\bnode\b/, "node"]
];
function detectProcessType(command) {
  for (const [pattern, type] of PROCESS_PATTERNS) {
    if (pattern.test(command)) return type;
  }
  return "unknown";
}
var ProcessMonitor = class {
  store;
  scanInterval = null;
  processes = /* @__PURE__ */ new Map();
  lastActivity = /* @__PURE__ */ new Map();
  constructor(store) {
    this.store = store;
  }
  start(intervalMs = 1e4) {
    this.scan();
    this.scanInterval = setInterval(() => this.scan(), intervalMs);
    this.scanInterval.unref?.();
  }
  stop() {
    if (this.scanInterval) {
      clearInterval(this.scanInterval);
      this.scanInterval = null;
    }
  }
  scan() {
    const allProcesses = parseProcessList();
    const relevantTypes = /* @__PURE__ */ new Set([
      "next",
      "vite",
      "webpack",
      "wrangler",
      "prisma",
      "docker",
      "postgres",
      "mysql",
      "redis",
      "bun",
      "deno"
    ]);
    const foundPids = /* @__PURE__ */ new Set();
    for (const proc of allProcesses) {
      const type = detectProcessType(proc.command);
      if (type === "unknown" || type === "python") continue;
      if (type === "node" && !relevantTypes.has(type)) {
        if (!proc.command.includes("server") && !proc.command.includes("dev") && !proc.command.includes("start")) {
          continue;
        }
      }
      foundPids.add(proc.pid);
      const existing = this.processes.get(proc.pid);
      const ports = existing?.ports ?? getListenPorts(proc.pid);
      const cwd = existing?.cwd ?? getProcessCwd(proc.pid);
      const memoryMB = getProcessMemoryMB(proc.pid);
      const lastActive = this.lastActivity.get(proc.pid) ?? Date.now();
      const isOrphaned = Date.now() - lastActive > 30 * 60 * 1e3;
      this.processes.set(proc.pid, {
        pid: proc.pid,
        command: proc.command.slice(0, 200),
        type,
        cpuPercent: proc.cpu,
        memoryMB,
        ports,
        cwd,
        isOrphaned
      });
    }
    for (const pid of this.processes.keys()) {
      if (!foundPids.has(pid)) {
        this.processes.delete(pid);
        this.lastActivity.delete(pid);
      }
    }
  }
  getProcesses(filter) {
    const results = Array.from(this.processes.values());
    return results.filter((p) => {
      if (filter?.type && p.type !== filter.type) return false;
      if (filter?.project && p.project !== filter.project) return false;
      return true;
    });
  }
  killProcess(pid, signal = "SIGTERM") {
    try {
      process.kill(pid, signal);
      this.processes.delete(pid);
      return { success: true };
    } catch (err) {
      return { success: false, error: err.message };
    }
  }
  getPortUsage(port) {
    const results = [];
    for (const proc of this.processes.values()) {
      for (const p of proc.ports) {
        if (port !== void 0 && p !== port) continue;
        results.push({
          port: p,
          pid: proc.pid,
          process: proc.command.slice(0, 100),
          type: proc.type,
          project: proc.project
        });
      }
    }
    return results.sort((a, b) => a.port - b.port);
  }
  detectIssues() {
    const issues = [];
    for (const proc of this.processes.values()) {
      if (proc.isOrphaned) {
        issues.push({
          id: `orphaned-${proc.pid}`,
          pattern: "orphaned_process",
          severity: "low",
          title: `Orphaned Process: ${proc.type} (PID ${proc.pid})`,
          description: `Dev server process has had no activity for 30+ minutes.`,
          evidence: [
            `PID: ${proc.pid}`,
            `Type: ${proc.type}`,
            `Memory: ${proc.memoryMB.toFixed(0)}MB`,
            `Command: ${proc.command.slice(0, 100)}`
          ],
          suggestion: `Kill with: kill ${proc.pid}`
        });
      }
      if (proc.memoryMB > 1024) {
        issues.push({
          id: `high-memory-${proc.pid}`,
          pattern: "high_memory_process",
          severity: "medium",
          title: `High Memory: ${proc.type} using ${proc.memoryMB.toFixed(0)}MB`,
          description: `Process is using ${proc.memoryMB.toFixed(0)}MB of memory (>1GB).`,
          evidence: [
            `PID: ${proc.pid}`,
            `Memory: ${proc.memoryMB.toFixed(0)}MB`,
            `CPU: ${proc.cpuPercent}%`
          ],
          suggestion: "Restart the process or investigate memory leaks."
        });
      }
    }
    return issues;
  }
};

// src/engines/infra-connector.ts
function createVercelClient(projectId, token) {
  const baseUrl = "https://api.vercel.com";
  const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
  return {
    name: "Vercel",
    async getDeployments(opts) {
      const limit = opts?.limit ?? 10;
      const url = opts?.deployId ? `${baseUrl}/v13/deployments/${opts.deployId}` : `${baseUrl}/v6/deployments?projectId=${projectId}&limit=${limit}`;
      const res = await fetch(url, { headers });
      if (!res.ok) return [];
      const data = await res.json();
      if (opts?.deployId) {
        return [mapVercelDeployment(data, projectId)];
      }
      const deployments = data.deployments ?? [];
      return deployments.map((d) => mapVercelDeployment(d, projectId));
    },
    async getRuntimeLogs(opts) {
      void opts;
      return [];
    },
    async getBuildStatus() {
      const res = await fetch(`${baseUrl}/v6/deployments?projectId=${projectId}&limit=1`, { headers });
      if (!res.ok) return null;
      const data = await res.json();
      const deployments = data.deployments ?? [];
      if (deployments.length === 0) return null;
      const latest = deployments[0];
      return {
        platform: "Vercel",
        project: projectId,
        latestDeployId: latest.uid,
        status: mapVercelStatus(latest.state),
        url: latest.url ? `https://${latest.url}` : void 0,
        lastDeployed: latest.created
      };
    }
  };
}
function mapVercelDeployment(d, projectId) {
  return {
    id: d.uid,
    platform: "Vercel",
    project: projectId,
    status: mapVercelStatus(d.state ?? d.readyState),
    url: d.url ? `https://${d.url}` : void 0,
    branch: d.meta?.githubCommitRef,
    commit: d.meta?.githubCommitSha,
    createdAt: d.created ?? d.createdAt,
    readyAt: d.ready,
    errorMessage: void 0
  };
}
function mapVercelStatus(state) {
  if (state === "READY" || state === "ready") return "ready";
  if (state === "ERROR" || state === "error") return "error";
  if (state === "CANCELED" || state === "canceled") return "canceled";
  return "building";
}
function createCloudflareClient(accountId, workerName, token) {
  const baseUrl = `https://api.cloudflare.com/client/v4/accounts/${accountId}`;
  const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
  return {
    name: "Cloudflare Workers",
    async getDeployments(opts) {
      void opts;
      const res = await fetch(`${baseUrl}/workers/scripts/${workerName}`, { headers });
      if (!res.ok) return [];
      const data = await res.json();
      const result = data.result;
      if (!result) return [];
      return [{
        id: result.id ?? workerName,
        platform: "Cloudflare Workers",
        project: workerName,
        status: "ready",
        createdAt: new Date(result.modified_on).getTime()
      }];
    },
    async getRuntimeLogs(opts) {
      void opts;
      return [];
    },
    async getBuildStatus() {
      const res = await fetch(`${baseUrl}/workers/scripts/${workerName}`, { headers });
      if (!res.ok) return null;
      const data = await res.json();
      const result = data.result;
      if (!result) return null;
      return {
        platform: "Cloudflare Workers",
        project: workerName,
        latestDeployId: result.id ?? workerName,
        status: "ready",
        lastDeployed: new Date(result.modified_on).getTime()
      };
    }
  };
}
function createRailwayClient(projectId, token) {
  const graphqlUrl = "https://backboard.railway.app/graphql/v2";
  async function gql(query, variables) {
    const res = await fetch(graphqlUrl, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ query, variables })
    });
    if (!res.ok) return {};
    return await res.json();
  }
  return {
    name: "Railway",
    async getDeployments(opts) {
      const limit = opts?.limit ?? 10;
      const data = await gql(`
        query($projectId: String!, $first: Int) {
          deployments(input: { projectId: $projectId }, first: $first) {
            edges {
              node {
                id
                status
                createdAt
                url
                meta { branch commitHash }
              }
            }
          }
        }
      `, { projectId, first: limit });
      const edges = data.data?.deployments?.edges ?? [];
      return edges.map((edge) => {
        const d = edge.node;
        const meta = d.meta;
        return {
          id: d.id,
          platform: "Railway",
          project: projectId,
          status: mapRailwayStatus(d.status),
          url: d.url,
          branch: meta?.branch,
          commit: meta?.commitHash,
          createdAt: new Date(d.createdAt).getTime()
        };
      });
    },
    async getRuntimeLogs(opts) {
      void opts;
      return [];
    },
    async getBuildStatus() {
      const data = await gql(`
        query($projectId: String!) {
          deployments(input: { projectId: $projectId }, first: 1) {
            edges {
              node { id status createdAt url }
            }
          }
        }
      `, { projectId });
      const edges = data.data?.deployments?.edges ?? [];
      if (edges.length === 0) return null;
      const d = edges[0].node;
      return {
        platform: "Railway",
        project: projectId,
        latestDeployId: d.id,
        status: mapRailwayStatus(d.status),
        url: d.url,
        lastDeployed: new Date(d.createdAt).getTime()
      };
    }
  };
}
function mapRailwayStatus(status) {
  if (status === "SUCCESS") return "ready";
  if (status === "FAILED") return "error";
  if (status === "REMOVED" || status === "CANCELLED") return "canceled";
  return "building";
}
var InfraConnector = class {
  store;
  clients = /* @__PURE__ */ new Map();
  constructor(store) {
    this.store = store;
  }
  loadFromConfig(projectManager, projectName) {
    const config = projectManager.getInfrastructureConfig(projectName);
    if (!config?.deployments) return;
    for (const [key, deployment] of Object.entries(config.deployments)) {
      switch (deployment.platform) {
        case "vercel": {
          const token = process.env.VERCEL_TOKEN ?? "";
          if (token && deployment.project_id) {
            this.clients.set(key, createVercelClient(deployment.project_id, token));
          }
          break;
        }
        case "cloudflare": {
          const token = process.env.CLOUDFLARE_API_TOKEN ?? "";
          if (token && deployment.account_id && deployment.worker_name) {
            this.clients.set(key, createCloudflareClient(deployment.account_id, deployment.worker_name, token));
          }
          break;
        }
        case "railway": {
          const token = process.env.RAILWAY_TOKEN ?? "";
          if (token && deployment.project_id) {
            this.clients.set(key, createRailwayClient(deployment.project_id, token));
          }
          break;
        }
      }
    }
  }
  async getDeployLogs(project, platform, deployId) {
    const results = [];
    for (const [key, client] of this.clients) {
      if (platform && client.name.toLowerCase() !== platform.toLowerCase()) continue;
      void key;
      try {
        const logs = await client.getDeployments({ deployId, limit: 10 });
        results.push(...logs);
      } catch {
      }
    }
    return results.sort((a, b) => b.createdAt - a.createdAt);
  }
  async getRuntimeLogs(project, opts) {
    const results = [];
    for (const [, client] of this.clients) {
      if (opts?.platform && client.name.toLowerCase() !== opts.platform.toLowerCase()) continue;
      try {
        const logs = await client.getRuntimeLogs(opts);
        results.push(...logs);
      } catch {
      }
    }
    return results.sort((a, b) => b.timestamp - a.timestamp);
  }
  async getBuildStatus(project) {
    const results = [];
    for (const [, client] of this.clients) {
      try {
        const status = await client.getBuildStatus();
        if (status) results.push(status);
      } catch {
      }
    }
    return results;
  }
  getInfraOverview(project) {
    const networkEvents = this.store.getNetworkRequests();
    const detectedPlatforms = /* @__PURE__ */ new Set();
    for (const event of networkEvents) {
      try {
        const hostname = new URL(event.url).hostname;
        if (hostname.includes("vercel")) detectedPlatforms.add("Vercel");
        if (hostname.includes("cloudflare") || hostname.includes("workers.dev")) detectedPlatforms.add("Cloudflare");
        if (hostname.includes("railway")) detectedPlatforms.add("Railway");
        if (hostname.includes("supabase")) detectedPlatforms.add("Supabase");
        if (hostname.includes("firebase")) detectedPlatforms.add("Firebase");
        if (hostname.includes("netlify")) detectedPlatforms.add("Netlify");
      } catch {
      }
    }
    const platforms = Array.from(this.clients.entries()).map(([, client]) => ({
      name: client.name,
      configured: true,
      deployCount: 0,
      status: "configured"
    }));
    return [{
      project: project ?? "default",
      platforms,
      detectedFromTraffic: [...detectedPlatforms]
    }];
  }
};

// src/session-differ.ts
var CHANGE_THRESHOLD = 0.1;
function classifyDelta(percentChange) {
  if (percentChange > CHANGE_THRESHOLD) return "regression";
  if (percentChange < -CHANGE_THRESHOLD) return "improvement";
  return "unchanged";
}
function computeDeltas(before, after, keyPrefix = "") {
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)]);
  const deltas = [];
  for (const key of allKeys) {
    const bVal = before[key] ?? 0;
    const aVal = after[key] ?? 0;
    const delta = aVal - bVal;
    const percentChange = bVal !== 0 ? delta / bVal : aVal !== 0 ? 1 : 0;
    deltas.push({
      key: keyPrefix ? `${keyPrefix}:${key}` : key,
      before: bVal,
      after: aVal,
      delta,
      percentChange,
      classification: classifyDelta(percentChange)
    });
  }
  return deltas.filter((d) => d.classification !== "unchanged");
}
function compareSessions(metricsA, metricsB) {
  const endpointLatencyA = {};
  const endpointLatencyB = {};
  for (const [key, data] of Object.entries(metricsA.endpoints)) {
    endpointLatencyA[key] = data.avgLatency;
  }
  for (const [key, data] of Object.entries(metricsB.endpoints)) {
    endpointLatencyB[key] = data.avgLatency;
  }
  const componentRendersA = {};
  const componentRendersB = {};
  for (const [key, data] of Object.entries(metricsA.components)) {
    componentRendersA[key] = data.renderCount;
  }
  for (const [key, data] of Object.entries(metricsB.components)) {
    componentRendersB[key] = data.renderCount;
  }
  const storeUpdatesA = {};
  const storeUpdatesB = {};
  for (const [key, data] of Object.entries(metricsA.stores)) {
    storeUpdatesA[key] = data.updateCount;
  }
  for (const [key, data] of Object.entries(metricsB.stores)) {
    storeUpdatesB[key] = data.updateCount;
  }
  const vitalsA = {};
  const vitalsB = {};
  for (const [key, data] of Object.entries(metricsA.webVitals)) {
    vitalsA[key] = data.value;
  }
  for (const [key, data] of Object.entries(metricsB.webVitals)) {
    vitalsB[key] = data.value;
  }
  const queryDurA = {};
  const queryDurB = {};
  for (const [key, data] of Object.entries(metricsA.queries)) {
    queryDurA[key] = data.avgDuration;
  }
  for (const [key, data] of Object.entries(metricsB.queries)) {
    queryDurB[key] = data.avgDuration;
  }
  return {
    sessionA: metricsA.sessionId,
    sessionB: metricsB.sessionId,
    endpointDeltas: computeDeltas(endpointLatencyA, endpointLatencyB, "endpoint"),
    componentDeltas: computeDeltas(componentRendersA, componentRendersB, "component"),
    storeDeltas: computeDeltas(storeUpdatesA, storeUpdatesB, "store"),
    webVitalDeltas: computeDeltas(vitalsA, vitalsB, "vital"),
    queryDeltas: computeDeltas(queryDurA, queryDurB, "query"),
    overallDelta: {
      errorCountDelta: metricsB.errorCount - metricsA.errorCount,
      totalEventsDelta: metricsB.totalEvents - metricsA.totalEvents
    }
  };
}
export {
  ApiDiscoveryEngine,
  AuthManager,
  BUILT_IN_RULES,
  CollectorServer,
  ConnectionManager,
  Counter,
  DataBrowser,
  EventStore,
  Gauge,
  HttpServer,
  InfraConnector,
  MetricsRegistry,
  OtelExporter,
  PmStore,
  ProcessMonitor,
  ProjectDiscovery,
  ProjectManager,
  Redactor,
  RingBuffer,
  SchemaIntrospector,
  SessionManager,
  SessionRateLimiter,
  SqliteStore,
  Wal,
  aggregateQueryStats,
  calculateActiveMinutes,
  calculateCostMicrodollars,
  compareSessions,
  detectIssues,
  detectN1Queries,
  detectOverfetching,
  detectSlowQueries,
  findPidsInDirectory,
  generateApiKey,
  generateProjectId,
  getListenPorts,
  getOrCreateProjectId,
  getPidsOnPort,
  getProcessCwd,
  getProcessMemoryMB,
  isSqliteAvailable,
  isValidProjectId,
  loadTlsOptions,
  migrateProjectIds,
  otelOptionsFromEnv,
  parseOtelHeaders,
  parseProcessList,
  parseSessionJsonl,
  randomSpanId,
  readProjectConfig,
  resolveProjectAppNames,
  resolveTlsConfig,
  safeLog,
  scaffoldProjectConfig,
  suggestIndexes,
  traceIdFromSession,
  writeProjectConfig
};
//# sourceMappingURL=index.js.map