import {
  API_BASE,
  BomTable,
  Button,
  CadViewer,
  CircuitJsonPreview,
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuPortal,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
  PCBViewer,
  PcbViewerWithContainerHeight,
  SchematicViewer,
  Tabs,
  TabsList,
  TabsTrigger,
  buttonVariants,
  cn,
  debug_default,
  linkify,
  registryKy,
  toast,
  useOrderDialog,
  useOrderDialogCli,
  useRunFrameStore
} from "./chunk-SL4ANLDQ.js";

// lib/components/RunFrame/RunFrame.tsx
import { createCircuitWebWorker } from "@tscircuit/eval/worker";
import Debug from "debug";
import { Loader2, Play, Square } from "lucide-react";
import { useEffect, useReducer, useRef as useRef2, useState } from "react";
import {
  orderedRenderPhases as orderedRenderPhases2
} from "@tscircuit/core";

// lib/render-logging/getPhaseTimingsFromRenderEvents.ts
import { orderedRenderPhases } from "@tscircuit/core";
var getPhaseTimingsFromRenderEvents = (renderEvents) => {
  const phaseTimings = {};
  if (!renderEvents) return phaseTimings;
  for (const renderPhase of orderedRenderPhases) {
    phaseTimings[renderPhase] = 0;
  }
  const startEvents = /* @__PURE__ */ new Map();
  for (const event of renderEvents) {
    const [, , phase, eventType] = event.type.split(":");
    if (eventType === "start") {
      startEvents.set(`${phase}:${event.renderId}`, event);
      continue;
    }
    if (eventType === "end") {
      const startEvent = startEvents.get(`${phase}:${event.renderId}`);
      if (startEvent) {
        const duration = event.createdAt - startEvent.createdAt;
        phaseTimings[phase] = (phaseTimings[phase] || 0) + duration;
      }
    }
  }
  return phaseTimings;
};

// lib/utils/getChangesBetweenFsMaps.tsx
var getChangesBetweenFsMaps = (fsMap1, fsMap2) => {
  const changes = {};
  for (const [path, oldContent] of fsMap1.entries()) {
    const newContent = fsMap2.get(path);
    if (newContent !== oldContent) {
      changes[path] = {
        old: oldContent,
        new: newContent
      };
    }
  }
  for (const [path, newContent] of fsMap2.entries()) {
    if (!fsMap1.has(path)) {
      changes[path] = {
        old: void 0,
        new: newContent
      };
    }
  }
  return changes;
};

// lib/components/RunFrame/runner-store/use-runner-store.ts
import { create } from "zustand";
import { devtools } from "zustand/middleware";
var useRunnerStore = create()(
  devtools(
    (set) => ({
      lastRunEvalVersion: void 0,
      setLastRunEvalVersion: (version) => {
        set({ lastRunEvalVersion: version });
      }
    }),
    { name: "runframe-runner-store" }
  )
);

// lib/components/RunFrame/useMutex.tsx
import { useCallback, useRef } from "react";
function useMutex() {
  const lockRef = useRef(Promise.resolve());
  const isLockedRef = useRef(false);
  const currentExecutionRef = useRef(null);
  const runWithMutex = useCallback(
    async (fn) => {
      await lockRef.current;
      const executionContext = { cancelled: false };
      currentExecutionRef.current = executionContext;
      let releaseLock;
      const newLock = new Promise((resolve) => {
        releaseLock = resolve;
      });
      try {
        lockRef.current = newLock;
        isLockedRef.current = true;
        return await fn();
      } catch (error) {
        if (!executionContext.cancelled) {
          throw error;
        }
      } finally {
        isLockedRef.current = false;
        currentExecutionRef.current = null;
        releaseLock();
      }
    },
    []
  );
  const cancel = useCallback(() => {
    if (currentExecutionRef.current) {
      currentExecutionRef.current.cancelled = true;
    }
    lockRef.current = Promise.resolve();
    isLockedRef.current = false;
  }, []);
  const isLocked = useCallback(() => isLockedRef.current, []);
  return { runWithMutex, isLocked, cancel };
}

// lib/components/RunFrame/RunFrame.tsx
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var numRenderPhases = 26;
var debug = Debug("run-frame:RunFrame");
var RunFrame = (props) => {
  const [circuitJson, setCircuitJson] = useRunFrameStore((s) => [
    s.circuitJson,
    s.setCircuitJson
  ]);
  const [error, setError] = useState(null);
  const cancelExecutionRef = useRef2(null);
  const [autoroutingGraphics, setAutoroutingGraphics] = useState(null);
  const [runCountTrigger, incRunCountTrigger] = useReducer(
    (acc, s) => acc + 1,
    0
  );
  const setLastRunEvalVersion = useRunnerStore((s) => s.setLastRunEvalVersion);
  const lastRunCountTriggerRef = useRef2(0);
  const runMutex = useMutex();
  const [isRunning, setIsRunning] = useState(false);
  useEffect(() => {
    const handleKeyDown = (e) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !isRunning) {
        incRunCountTrigger(1);
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [isRunning]);
  const [renderLog, setRenderLog] = useState(null);
  const [autoroutingLog, setAutoroutingLog] = useState({});
  const [activeTab, setActiveTab] = useState(
    props.defaultActiveTab ?? "pcb"
  );
  useEffect(() => {
    if (props.debug) Debug.enable("run-frame*");
  }, [props.debug]);
  const fsMap = props.fsMap instanceof Map ? props.fsMap : Object.entries(props.fsMap ?? {}).reduce(
    (m, [k, v]) => m.set(k, v),
    /* @__PURE__ */ new Map()
  );
  const lastFsMapRef = useRef2(null);
  const lastEntrypointRef = useRef2(null);
  useEffect(() => {
    const fsMapObj = fsMap instanceof Map ? Object.fromEntries(fsMap.entries()) : fsMap;
    if (!fsMapObj || Object.keys(fsMapObj).length === 0) {
      setError({
        error: "No files provided. Please provide at least one file with code to execute.",
        stack: ""
      });
      setIsRunning(false);
      return;
    }
    const wasTriggeredByRunButton = props.showRunButton && runCountTrigger !== lastRunCountTriggerRef.current;
    if (lastFsMapRef.current && circuitJson) {
      const changes = getChangesBetweenFsMaps(lastFsMapRef.current, fsMap);
      if (Object.keys(changes).length > 0) {
        debug("code changes detected");
      } else if (lastEntrypointRef.current !== props.entrypoint) {
        debug("render triggered by entrypoint change");
      } else if (!wasTriggeredByRunButton) {
        debug("render triggered without changes to fsMap, skipping");
        return;
      }
    }
    if (props.showRunButton && runCountTrigger === lastRunCountTriggerRef.current) {
      return;
    }
    lastFsMapRef.current = fsMap;
    lastEntrypointRef.current = props.entrypoint ?? null;
    lastRunCountTriggerRef.current = runCountTrigger;
    setIsRunning(true);
    const runWorker = async () => {
      debug("running render worker");
      setError(null);
      setRenderLog(null);
      const renderLog2 = { progress: 0 };
      let cancelled = false;
      cancelExecutionRef.current = () => {
        cancelled = true;
      };
      let evalVersion = props.evalVersion ?? "latest";
      if (!globalThis.runFrameWorker && props.forceLatestEvalVersion) {
        try {
          const response = await fetch(
            "https://data.jsdelivr.com/v1/package/npm/@tscircuit/eval"
          );
          if (response.ok) {
            const data = await response.json();
            if (data.tags?.latest) {
              evalVersion = data.tags.latest;
              setLastRunEvalVersion(evalVersion);
            }
          }
        } catch (err) {
        }
      }
      const worker = globalThis.runFrameWorker ?? await createCircuitWebWorker({
        evalVersion,
        webWorkerBlobUrl: props.evalWebWorkerBlobUrl,
        verbose: true
      });
      globalThis.runFrameWorker = worker;
      props.onRenderStarted?.();
      const fsMapObj2 = fsMap instanceof Map ? Object.fromEntries(fsMap.entries()) : fsMap;
      const renderIds = /* @__PURE__ */ new Set();
      const startRenderTime = Date.now();
      let lastRenderLogSet = Date.now();
      worker.on("autorouting:start", (event) => {
        setAutoroutingLog({
          ...autoroutingLog,
          [event.componentDisplayName]: {
            simpleRouteJson: event.simpleRouteJson
          }
        });
      });
      worker.on("board:renderPhaseStarted", (event) => {
        renderLog2.lastRenderEvent = event;
        renderLog2.eventsProcessed = (renderLog2.eventsProcessed ?? 0) + 1;
        const hasProcessedEnoughToEstimateProgress = renderLog2.eventsProcessed > 2;
        const estProgressLinear = orderedRenderPhases2.indexOf(event.phase) / numRenderPhases * 0.75 + renderLog2.eventsProcessed / 1e3 * 0.25;
        const estProgress = 1 - Math.exp(-estProgressLinear * 3);
        renderLog2.progress = estProgress;
        if (!cancelled) {
          setRenderLog({ ...renderLog2 });
        }
      });
      if (activeTab === "render_log") {
        worker.on("renderable:renderLifecycle:anyEvent", (event) => {
          renderLog2.renderEvents = renderLog2.renderEvents ?? [];
          event.createdAt = Date.now();
          renderLog2.renderEvents.push(event);
          if (Date.now() - lastRenderLogSet > 500) {
            renderLog2.phaseTimings = getPhaseTimingsFromRenderEvents(
              renderLog2.renderEvents ?? []
            );
            lastRenderLogSet = Date.now();
          }
          if (!cancelled) {
            setRenderLog({ ...renderLog2 });
          }
        });
      }
      worker.on("autorouting:progress", (event) => {
        setAutoroutingGraphics(event.debugGraphics);
      });
      const evalResult = await worker.executeWithFsMap({
        entrypoint: props.entrypoint,
        fsMap: fsMapObj2,
        ...props.mainComponentPath ? { mainComponentPath: props.mainComponentPath } : {}
      }).then(() => {
        return { success: true };
      }).catch((e) => {
        const message = e.message.replace("Error: ", "");
        props.onError?.(e);
        setError({ error: message, stack: e.stack });
        console.error(e);
        return { success: false };
      });
      if (!evalResult.success) {
        setIsRunning(false);
        return;
      }
      const $renderResult = worker.renderUntilSettled();
      debug("waiting for initial circuit json...");
      let circuitJson2 = await worker.getCircuitJson().catch((e) => {
        debug("error getting initial circuit json", e);
        props.onError?.(e);
        setError({ error: e.message, stack: e.stack });
        setIsRunning(false);
        return null;
      });
      if (!circuitJson2) return;
      debug("got initial circuit json");
      setCircuitJson(circuitJson2);
      props.onCircuitJsonChange?.(circuitJson2);
      props.onInitialRender?.({ circuitJson: circuitJson2 });
      await $renderResult;
      debug("getting final circuit json");
      circuitJson2 = await worker.getCircuitJson();
      props.onCircuitJsonChange?.(circuitJson2);
      setCircuitJson(circuitJson2);
      props.onRenderFinished?.({ circuitJson: circuitJson2 });
      setAutoroutingGraphics({});
      if (activeTab === "render_log") {
        renderLog2.phaseTimings = getPhaseTimingsFromRenderEvents(
          renderLog2.renderEvents ?? []
        );
      }
      renderLog2.progress = 1;
      if (!cancelled) {
        setRenderLog({ ...renderLog2 });
      }
      setIsRunning(false);
      cancelExecutionRef.current = null;
    };
    runMutex.runWithMutex(runWorker);
  }, [props.fsMap, props.entrypoint, runCountTrigger, props.evalVersion]);
  const lastEditEventRef = useRef2(null);
  const dragTimeout = useRef2(null);
  const handleEditEvent = (event) => {
    if (!event || event === null) {
      console.warn(
        "[RunFrame] handleEditEvent received null or undefined event."
      );
      return;
    }
    if (event.in_progress) {
      lastEditEventRef.current = event;
      if (dragTimeout.current) {
        clearTimeout(dragTimeout.current);
        dragTimeout.current = null;
      }
    } else {
      if (dragTimeout.current) {
        clearTimeout(dragTimeout.current);
      }
      dragTimeout.current = setTimeout(() => {
        const eventToSend = event || lastEditEventRef.current;
        props.onEditEvent?.(eventToSend);
        lastEditEventRef.current = null;
        dragTimeout.current = null;
      }, 100);
    }
  };
  const handleReportAutoroutingLog = async (name, data) => {
    await registryKy.post("autorouting/bug_reports/create", {
      json: {
        title: name,
        simple_route_json: data.simpleRouteJson
      }
    }).json().then(({ autorouting_bug_report }) => {
      window.open(
        `https://api.tscircuit.com/autorouting/bug_reports/view?autorouting_bug_report_id=${autorouting_bug_report.autorouting_bug_report_id}`,
        "_blank"
      );
    }).catch((error2) => {
      console.error("Failed to report autorouting bug", error2);
      if (error2.message.includes("401")) {
        alert("You must be logged in to report autorouting bugs");
      } else {
        alert(`Failed to report autorouting bug: ${error2.message}`);
      }
    });
  };
  return /* @__PURE__ */ jsx(
    CircuitJsonPreview,
    {
      code: fsMap.get(props.entrypoint ?? props.mainComponentPath),
      defaultActiveTab: props.defaultActiveTab,
      showToggleFullScreen: props.showToggleFullScreen,
      autoroutingGraphics,
      autoroutingLog,
      onReportAutoroutingLog: props.onReportAutoroutingLog || handleReportAutoroutingLog,
      leftHeaderContent: /* @__PURE__ */ jsxs(Fragment, { children: [
        props.showRunButton && /* @__PURE__ */ jsxs("div", { className: "rf-relative rf-inline-flex", children: [
          /* @__PURE__ */ jsxs(
            "button",
            {
              type: "button",
              onClick: () => {
                incRunCountTrigger(1);
              },
              className: "rf-flex rf-items-center rf-gap-2 rf-px-4 rf-py-2 rf-bg-blue-600 hover:rf-bg-blue-700 rf-text-white rf-rounded-md disabled:rf-opacity-50 transition-colors duration-200",
              disabled: isRunning,
              children: [
                "Run",
                " ",
                isRunning ? /* @__PURE__ */ jsx(Loader2, { className: "rf-w-3 rf-h-3 rf-animate-spin" }) : /* @__PURE__ */ jsx(Play, { className: "rf-w-3 rf-h-3" })
              ]
            }
          ),
          isRunning && /* @__PURE__ */ jsx("div", { className: "rf-flex rf-items-center rf-ml-1", children: /* @__PURE__ */ jsx(
            Button,
            {
              onClick: (e) => {
                e.stopPropagation();
                setIsRunning(false);
                setRenderLog(null);
                setError(null);
                if (cancelExecutionRef.current) {
                  cancelExecutionRef.current();
                  cancelExecutionRef.current = null;
                }
                runMutex.cancel();
                if (globalThis.runFrameWorker) {
                  globalThis.runFrameWorker.kill();
                  globalThis.runFrameWorker = null;
                }
              },
              variant: "ghost",
              size: "icon",
              className: "rf-text-red-300 hover:rf-text-red-400 hover:!rf-bg-transparent [&>svg]:rf-text-red-300 [&>svg]:hover:rf-text-red-400 rf-flex rf-items-center rf-justify-center",
              children: /* @__PURE__ */ jsx(
                Square,
                {
                  className: "!rf-h-2.5 !rf-w-2.5",
                  fill: "currentColor",
                  stroke: "currentColor"
                }
              )
            }
          ) })
        ] }),
        props.leftHeaderContent
      ] }),
      onActiveTabChange: setActiveTab,
      circuitJson,
      renderLog,
      isRunningCode: isRunning,
      errorMessage: error?.error,
      onEditEvent: handleEditEvent,
      editEvents: props.editEvents,
      defaultToFullScreen: props.defaultToFullScreen
    }
  );
};

// lib/components/RunFrameWithApi/RunFrameWithApi.tsx
import Debug2 from "debug";

// lib/hooks/use-edit-event-controller.ts
import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
var debug2 = debug_default.extend("useEditEventController");
var useEditEventController = () => {
  const applyEditEventsAndUpdateManualEditsJson = useRunFrameStore(
    (s) => s.applyEditEventsAndUpdateManualEditsJson
  );
  const [editEvents, setEditEvents] = useState2([]);
  const [isRendering, setIsRendering] = useState2(false);
  const unappliedEditEvents = editEvents.filter((ee) => !ee._applied);
  const appliedEditEvents = editEvents.filter((ee) => ee._applied);
  const editEventsForRender = isRendering ? editEvents : unappliedEditEvents;
  const pushEditEvent = useCallback2((ee) => {
    setEditEvents((prev) => [...prev, { ...ee, _applied: false }]);
  }, []);
  const markEditEventApplied = useCallback2((ee) => {
    setEditEvents(
      (prev) => prev.map(
        (event) => event === ee ? { ...event, _applied: true } : event
      )
    );
  }, []);
  const markAllEditEventsApplied = useCallback2(() => {
    setEditEvents((prev) => prev.map((ee) => ({ ...ee, _applied: true })));
  }, []);
  const markRenderStarted = useCallback2(() => {
    setIsRendering(true);
    if (editEvents.length === 0) return;
    debug2("removing edit events that are applied");
    setEditEvents((prev) => prev.filter((ee) => !ee._applied));
  }, [editEvents]);
  const markRenderComplete = useCallback2(() => {
    setIsRendering(false);
  }, []);
  useEffect2(() => {
    if (editEvents.filter((ee) => !ee._applied).length === 0) return;
    const timeout = setTimeout(() => {
      markAllEditEventsApplied();
      applyEditEventsAndUpdateManualEditsJson(
        editEvents
        //.filter((ee) => !ee._applied),
      );
    }, 1e3);
    return () => clearTimeout(timeout);
  }, [editEvents]);
  return {
    unappliedEditEvents,
    appliedEditEvents,
    editEventsForRender,
    pushEditEvent,
    markEditEventApplied,
    markRenderStarted,
    markRenderComplete,
    markAllEditEventsApplied
  };
};

// lib/hooks/use-sync-page-title.ts
import { useEffect as useEffect3 } from "react";
var useSyncPageTitle = () => {
  const fsMap = useRunFrameStore((s) => s.fsMap);
  useEffect3(() => {
    if (!document || !fsMap) return;
    const fileKeys = Array.from(fsMap.keys());
    const entrypoint = guessEntrypoint(fileKeys);
    const packageJsonContent = fsMap.get("package.json");
    try {
      if (packageJsonContent) {
        const parsedPackageJson = JSON.parse(packageJsonContent);
        if (parsedPackageJson?.name) {
          document.title = parsedPackageJson.name;
          return;
        }
      }
    } catch (e) {
    }
    if (entrypoint) {
      document.title = entrypoint;
    }
  }, [fsMap]);
};

// lib/components/RunFrameWithApi/RunFrameWithApi.tsx
import { useEffect as useEffect4 } from "react";
import { applyEditEventsToManualEditsFile } from "@tscircuit/core";
import { jsx as jsx2 } from "react/jsx-runtime";
var debug3 = Debug2("run-frame:RunFrameWithApi");
var guessEntrypoint = (files) => files.find((file) => file.includes("entrypoint.")) ?? files.find((file) => file.includes("index.")) ?? files.find((file) => file.includes("main.")) ?? files.find((file) => file.endsWith(".tsx"));
var guessManualEditsFilePath = (files) => files.find((file) => file.includes("manual-edits.")) ?? files.find((file) => file.includes("manual-edit.")) ?? files.find((file) => file.endsWith(".json"));
var RunFrameWithApi = (props) => {
  const { apiBaseUrl, leftHeaderContent } = props;
  useEffect4(() => {
    if (props.debug) Debug2.enable("run-frame*");
  }, [props.debug]);
  const { startPolling, stopPolling, loadInitialFiles } = useRunFrameStore(
    (s) => ({
      startPolling: s.startPolling,
      stopPolling: s.stopPolling,
      loadInitialFiles: s.loadInitialFiles
    })
  );
  const fsMap = useRunFrameStore((s) => s.fsMap);
  const circuitJson = useRunFrameStore((s) => s.circuitJson);
  useEffect4(() => {
    loadInitialFiles();
  }, []);
  useSyncPageTitle();
  const {
    editEventsForRender,
    pushEditEvent,
    markRenderStarted,
    markRenderComplete
  } = useEditEventController();
  useEffect4(() => {
    if (apiBaseUrl) {
      window.TSCIRCUIT_FILESERVER_API_BASE_URL = apiBaseUrl;
    }
  }, [apiBaseUrl]);
  useEffect4(() => {
    startPolling();
    return () => stopPolling();
  }, [startPolling, stopPolling]);
  return /* @__PURE__ */ jsx2(
    RunFrame,
    {
      fsMap,
      evalVersion: props.evalVersion,
      forceLatestEvalVersion: props.forceLatestEvalVersion,
      leftHeaderContent,
      defaultToFullScreen: props.defaultToFullScreen,
      showToggleFullScreen: props.showToggleFullScreen,
      onInitialRender: () => {
        debug3("onInitialRender / markRenderStarted");
        markRenderStarted();
      },
      onRenderFinished: () => {
        debug3("onRenderFinished / markRenderComplete");
        markRenderComplete();
      },
      editEvents: editEventsForRender,
      onEditEvent: (ee) => {
        pushEditEvent(ee);
        fetch(`${API_BASE}/events/create`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            event_type: "USER_CREATED_MANUAL_EDIT",
            ...ee
          })
        });
        const manualEditsFilePath = guessManualEditsFilePath(Array.from(fsMap.keys())) ?? "manual-edits.json";
        const manualEditsFile = fsMap.get(manualEditsFilePath);
        const updatedManualEdits = JSON.parse(
          manualEditsFile ?? "{}"
        );
        applyEditEventsToManualEditsFile({
          circuitJson,
          editEvents: [ee],
          manualEditsFile: updatedManualEdits
        });
        fetch(`${API_BASE}/files/upsert`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            file_path: manualEditsFilePath,
            text_content: JSON.stringify(updatedManualEdits),
            initiator: "runframe"
          })
        });
      }
    }
  );
};

// lib/hooks/use-local-storage-state.ts
import { useState as useState3, useEffect as useEffect5 } from "react";
function useLocalStorageState(key, initialValue) {
  const [state, setState] = useState3(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error("Error reading from localStorage:", error);
      return initialValue;
    }
  });
  useEffect5(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(state));
    } catch (error) {
      console.error("Error writing to localStorage:", error);
    }
  }, [key, state]);
  return [state, setState];
}

// lib/components/RunFrameForCli/LeftHeader.tsx
import { useEffect as useEffect8, useMemo as useMemo2, useState as useState6 } from "react";

// lib/components/RunFrameForCli/SelectSnippetDialog.tsx
import { useState as useState4 } from "react";
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
var SelectSnippetDialog = ({
  snippetNames,
  onSelect,
  onCancel,
  isOpen
}) => {
  const [selectedName, setSelectedName] = useState4("");
  const [searchInput, setSearchInput] = useState4("");
  if (!isOpen) return null;
  const filteredSnippets = snippetNames.filter(
    (name) => name.toLowerCase().includes(searchInput.toLowerCase())
  );
  const showCreateNew = searchInput && !snippetNames.includes(searchInput);
  const handleKeyDown = (e) => {
    if (e.key === "Enter") {
      if (filteredSnippets.length === 1) {
        setSelectedName(filteredSnippets[0]);
      } else if (showCreateNew) {
        setSelectedName(searchInput);
      }
    }
  };
  return /* @__PURE__ */ jsx3("div", { className: "rf-fixed rf-inset-0 rf-bg-black rf-bg-opacity-50 rf-flex rf-items-center rf-justify-center rf-z-[100]", children: /* @__PURE__ */ jsxs2("div", { className: "rf-bg-white rf-rounded-lg rf-p-6 rf-w-96", children: [
    /* @__PURE__ */ jsx3("h2", { className: "rf-text-lg rf-font-semibold rf-mb-4", children: "Select Snippet" }),
    /* @__PURE__ */ jsx3(
      "input",
      {
        type: "text",
        className: "rf-w-full rf-px-4 rf-py-2 rf-border rf-rounded rf-mb-4",
        placeholder: "Search snippets or new snippet name...",
        value: searchInput,
        onChange: (e) => setSearchInput(e.target.value),
        onKeyDown: handleKeyDown
      }
    ),
    /* @__PURE__ */ jsxs2("div", { className: "rf-h-60 rf-overflow-y-auto", children: [
      filteredSnippets.map((name) => /* @__PURE__ */ jsx3(
        "button",
        {
          type: "button",
          className: `w-full text-left px-4 py-2 rounded hover:bg-gray-100 ${selectedName === name ? "bg-blue-50" : ""}`,
          onClick: () => setSelectedName(name),
          children: name
        },
        name
      )),
      showCreateNew && /* @__PURE__ */ jsxs2(
        "button",
        {
          type: "button",
          className: `w-full text-left px-4 py-2 rounded hover:bg-gray-100 text-blue-500 ${selectedName === searchInput ? "bg-blue-50" : ""}`,
          onClick: () => setSelectedName(searchInput),
          children: [
            'Create new "',
            searchInput,
            '"'
          ]
        }
      )
    ] }),
    /* @__PURE__ */ jsxs2("div", { className: "rf-mt-4 rf-flex rf-justify-end rf-gap-2", children: [
      /* @__PURE__ */ jsx3(
        "button",
        {
          type: "button",
          className: "rf-px-4 rf-py-2 rf-text-gray-600 rf-hover:text-gray-800",
          onClick: onCancel,
          children: "Cancel"
        }
      ),
      /* @__PURE__ */ jsx3(
        "button",
        {
          type: "button",
          className: "rf-px-4 rf-py-2 rf-bg-blue-500 rf-text-white rf-rounded rf-hover:bg-blue-600 rf-disabled:opacity-50",
          onClick: () => selectedName && onSelect(selectedName),
          disabled: !selectedName,
          children: selectedName === searchInput ? `Create "${selectedName}"` : `Save to ${selectedName}`
        }
      )
    ] })
  ] }) });
};

// lib/components/RunFrameForCli/useEventHandler.ts
import { useEffect as useEffect6, useRef as useRef3 } from "react";
var useEventHandler = (callback) => {
  const lastProcessedEventId = useRef3(null);
  const recentEvents = useRunFrameStore((state) => state.recentEvents);
  useEffect6(() => {
    if (recentEvents.length === 0) return;
    const latestEvent = recentEvents[0];
    if (latestEvent.event_id !== lastProcessedEventId.current) {
      callback(latestEvent);
      lastProcessedEventId.current = latestEvent.event_id;
    }
  }, [recentEvents, callback]);
};

// lib/components/ui/alert-dialog.tsx
import * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
var AlertDialog = AlertDialogPrimitive.Root;
var AlertDialogPortal = AlertDialogPrimitive.Portal;
var AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
  AlertDialogPrimitive.Overlay,
  {
    className: cn(
      "rf-fixed rf-inset-0 rf-z-50 rf-bg-black/80 data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0",
      className
    ),
    ...props,
    ref
  }
));
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
var AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs3(AlertDialogPortal, { children: [
  /* @__PURE__ */ jsx4(AlertDialogOverlay, {}),
  /* @__PURE__ */ jsx4(
    AlertDialogPrimitive.Content,
    {
      ref,
      className: cn(
        "rf-fixed rf-left-[50%] rf-top-[50%] rf-z-50 rf-grid rf-w-full rf-max-w-lg rf-translate-x-[-50%] rf-translate-y-[-50%] rf-gap-4 rf-border rf-border-zinc-200 rf-bg-white rf-p-6 rf-shadow-lg rf-duration-200 data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[state=closed]:rf-slide-out-to-left-1/2 data-[state=closed]:rf-slide-out-to-top-[48%] data-[state=open]:rf-slide-in-from-left-1/2 data-[state=open]:rf-slide-in-from-top-[48%] sm:rf-rounded-lg dark:rf-border-zinc-800 dark:rf-bg-zinc-950",
        className
      ),
      ...props
    }
  )
] }));
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
var AlertDialogHeader = ({
  className,
  ...props
}) => /* @__PURE__ */ jsx4(
  "div",
  {
    className: cn(
      "rf-flex rf-flex-col rf-space-y-2 rf-text-center sm:rf-text-left",
      className
    ),
    ...props
  }
);
AlertDialogHeader.displayName = "AlertDialogHeader";
var AlertDialogFooter = ({
  className,
  ...props
}) => /* @__PURE__ */ jsx4(
  "div",
  {
    className: cn(
      "rf-flex rf-flex-col-reverse sm:rf-flex-row sm:rf-justify-end sm:rf-space-x-2",
      className
    ),
    ...props
  }
);
AlertDialogFooter.displayName = "AlertDialogFooter";
var AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
  AlertDialogPrimitive.Title,
  {
    ref,
    className: cn("rf-text-lg rf-font-semibold", className),
    ...props
  }
));
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
var AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
  AlertDialogPrimitive.Description,
  {
    ref,
    className: cn(
      "rf-text-sm rf-text-zinc-500 dark:rf-text-zinc-400",
      className
    ),
    ...props
  }
));
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
var AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
  AlertDialogPrimitive.Action,
  {
    ref,
    className: cn(buttonVariants(), className),
    ...props
  }
));
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
var AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
  AlertDialogPrimitive.Cancel,
  {
    ref,
    className: cn(
      buttonVariants({ variant: "outline" }),
      "rf-mt-2 sm:rf-mt-0",
      className
    ),
    ...props
  }
));
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;

// lib/components/ui/checkbox.tsx
import * as React2 from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react";
import { jsx as jsx5 } from "react/jsx-runtime";
var Checkbox = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
  CheckboxPrimitive.Root,
  {
    ref,
    className: cn(
      "rf-peer rf-h-4 rf-w-4 rf-shrink-0 rf-rounded-sm rf-border rf-border-zinc-200 rf-border-zinc-900 rf-shadow focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-zinc-950 disabled:rf-cursor-not-allowed disabled:rf-opacity-50 data-[state=checked]:rf-bg-zinc-900 data-[state=checked]:rf-text-zinc-50 dark:rf-border-zinc-800 dark:rf-border-zinc-50 dark:focus-visible:rf-ring-zinc-300 dark:data-[state=checked]:rf-bg-zinc-50 dark:data-[state=checked]:rf-text-zinc-900",
      className
    ),
    ...props,
    children: /* @__PURE__ */ jsx5(
      CheckboxPrimitive.Indicator,
      {
        className: cn(
          "rf-flex rf-items-center rf-justify-center rf-text-current"
        ),
        children: /* @__PURE__ */ jsx5(Check, { className: "rf-h-4 rf-w-4" })
      }
    )
  }
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;

// lib/components/ImportComponentDialog/ImportComponentDialog.tsx
import "react";
import { useState as useState5, useEffect as useEffect7 } from "react";
import { Loader2 as Loader22, Search, ExternalLink } from "lucide-react";

// lib/components/ui/input.tsx
import * as React3 from "react";
import { jsx as jsx6 } from "react/jsx-runtime";
var Input = React3.forwardRef(
  ({ className, type, ...props }, ref) => {
    return /* @__PURE__ */ jsx6(
      "input",
      {
        type,
        className: cn(
          "rf-flex rf-h-9 rf-w-full rf-rounded-md rf-border rf-border-zinc-200 rf-bg-white rf-px-3 rf-py-1 rf-text-sm rf-shadow-sm rf-transition-colors file:rf-border-0 file:rf-bg-transparent file:rf-text-sm file:rf-font-medium placeholder:rf-text-zinc-500 focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-zinc-950 disabled:rf-cursor-not-allowed disabled:rf-opacity-50 dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:rf-placeholder-zinc-400 dark:focus-visible:rf-ring-zinc-300",
          className
        ),
        ref,
        ...props
      }
    );
  }
);
Input.displayName = "Input";

// lib/components/ImportComponentDialog/jlc-api.ts
var searchJLCComponents = async (query, limit = 10) => {
  try {
    const encodedQuery = encodeURIComponent(query);
    const response = await fetch(
      `https://jlcsearch.tscircuit.com/api/search?limit=${limit}&q=${encodedQuery}`
    );
    if (!response.ok) {
      throw new Error(
        `JLC API error: ${response.status} ${response.statusText}`
      );
    }
    const data = await response.json();
    return data.components || [];
  } catch (error) {
    console.error("Error searching JLC components:", error);
    throw error;
  }
};
var mapJLCComponentToSearchResult = (jlcComponent) => {
  return {
    id: `jlc-${jlcComponent.lcsc}`,
    name: jlcComponent.mfr,
    description: jlcComponent.description,
    source: "jlcpcb",
    partNumber: `C${jlcComponent.lcsc}`,
    package: jlcComponent.package,
    price: jlcComponent.price
  };
};

// lib/components/ImportComponentDialog/tscircuit-registry-api.ts
var searchTscircuitComponents = async (query, limit = 10) => {
  try {
    const encodedQuery = encodeURIComponent(query);
    const response = await fetch(
      `https://registry-api.tscircuit.com/snippets/search?q=${encodedQuery}&limit=${limit}`
    );
    if (!response.ok) {
      throw new Error(
        `tscircuit Registry API error: ${response.status} ${response.statusText}`
      );
    }
    const data = await response.json();
    return data.snippets || [];
  } catch (error) {
    console.error("Error searching tscircuit components:", error);
    throw error;
  }
};
var mapTscircuitSnippetToSearchResult = (tscircuitSnippet) => {
  return {
    id: `tscircuit-${tscircuitSnippet.snippet_id}`,
    name: tscircuitSnippet.unscoped_name,
    description: tscircuitSnippet.description || `Component by ${tscircuitSnippet.owner_name}`,
    source: "tscircuit.com",
    partNumber: tscircuitSnippet.name,
    previewUrl: tscircuitSnippet.preview_url,
    // Additional tscircuit-specific properties
    code: tscircuitSnippet.code,
    owner: tscircuitSnippet.owner_name
  };
};

// lib/components/ImportComponentDialog/ImportComponentDialog.tsx
import { createSvgUrl as createPngUrl } from "@tscircuit/create-snippet-url";
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
var ImportComponentDialog = ({
  isOpen,
  onClose,
  onImport
}) => {
  const [searchQuery, setSearchQuery] = useState5("");
  const [searchResults, setSearchResults] = useState5(
    []
  );
  const [hasSearched, setHasSearched] = useState5(false);
  const [isLoading, setIsLoading] = useState5(false);
  const [selectedComponent, setSelectedComponent] = useState5(null);
  const [activeTab, setActiveTab] = useState5(
    "tscircuit.com"
  );
  const [detailsOpen, setDetailsOpen] = useState5(false);
  const [detailsComponent, setDetailsComponent] = useState5(null);
  const handleSearch = async () => {
    if (!searchQuery.trim()) return;
    setIsLoading(true);
    const isJlcPartNumber = /^C\d+/.test(searchQuery);
    if (isJlcPartNumber) {
      setActiveTab("jlcpcb");
    }
    try {
      if (activeTab === "jlcpcb") {
        const query = isJlcPartNumber ? searchQuery.substring(1) : searchQuery;
        const jlcComponents = await searchJLCComponents(query, 10);
        const mappedResults = jlcComponents.map(mapJLCComponentToSearchResult);
        setSearchResults(mappedResults);
      } else {
        const tscircuitComponents = await searchTscircuitComponents(
          searchQuery,
          10
        );
        const mappedResults = tscircuitComponents.map(
          mapTscircuitSnippetToSearchResult
        );
        setSearchResults(mappedResults);
      }
    } catch (error) {
      console.error("Error searching components:", error);
      setSearchResults([]);
    } finally {
      setIsLoading(false);
      setHasSearched(true);
    }
  };
  const handleKeyDown = (e) => {
    if (e.key === "Enter") {
      handleSearch();
    }
  };
  useEffect7(() => {
    setSearchResults([]);
    setSelectedComponent(null);
  }, [activeTab]);
  const showDetails = (component) => {
    setDetailsComponent(component);
    setDetailsOpen(true);
  };
  return /* @__PURE__ */ jsxs4(AlertDialog, { open: isOpen, onOpenChange: () => onClose(), children: [
    /* @__PURE__ */ jsxs4(AlertDialogContent, { className: "rf-max-w-3xl rf-w-full rf-max-h-[90vh] rf-overflow-y-auto rf-flex rf-flex-col", children: [
      /* @__PURE__ */ jsxs4(AlertDialogHeader, { children: [
        /* @__PURE__ */ jsx7(AlertDialogTitle, { children: "Import Component" }),
        /* @__PURE__ */ jsx7(AlertDialogDescription, { children: "Search for components from tscircuit.com or JLCPCB parts library." })
      ] }),
      /* @__PURE__ */ jsxs4(
        Tabs,
        {
          value: activeTab,
          onValueChange: (value) => setActiveTab(value),
          children: [
            /* @__PURE__ */ jsxs4(TabsList, { className: "rf-grid rf-w-full rf-grid-cols-2", children: [
              /* @__PURE__ */ jsx7(TabsTrigger, { value: "tscircuit.com", children: "tscircuit.com" }),
              /* @__PURE__ */ jsx7(TabsTrigger, { value: "jlcpcb", children: "JLCPCB Parts" })
            ] }),
            /* @__PURE__ */ jsxs4("div", { className: "rf-flex rf-items-center rf-gap-2 rf-mt-4", children: [
              /* @__PURE__ */ jsxs4("div", { className: "rf-relative rf-flex-grow", children: [
                /* @__PURE__ */ jsx7(Search, { className: "rf-absolute rf-left-2 rf-top-2.5 rf-h-4 rf-w-4 rf-text-muted-foreground" }),
                /* @__PURE__ */ jsx7(
                  Input,
                  {
                    placeholder: activeTab === "tscircuit.com" ? "Search components..." : "Search JLCPCB parts (e.g. C14663)...",
                    className: "rf-pl-8",
                    value: searchQuery,
                    onChange: (e) => setSearchQuery(e.target.value),
                    onKeyDown: handleKeyDown
                  }
                )
              ] }),
              /* @__PURE__ */ jsx7(Button, { onClick: handleSearch, disabled: isLoading, children: isLoading ? /* @__PURE__ */ jsx7(Loader22, { className: "rf-h-4 rf-w-4 rf-animate-spin" }) : "Search" })
            ] }),
            /* @__PURE__ */ jsx7("div", { className: "rf-mt-4 rf-flex-1 rf-min-h-[200px] !rf-max-h-[40vh] !rf-overflow-y-auto rf-border rf-rounded-md", children: searchResults.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "rf-divide-y", children: searchResults.map((result) => /* @__PURE__ */ jsxs4(
              "div",
              {
                className: `rf-p-3 rf-flex rf-items-center rf-justify-between rf-cursor-pointer hover:rf-bg-zinc-100 ${selectedComponent?.id === result.id ? "rf-bg-zinc-100" : ""}`,
                onClick: () => setSelectedComponent(result),
                children: [
                  /* @__PURE__ */ jsxs4("div", { children: [
                    /* @__PURE__ */ jsx7("div", { className: "rf-font-medium", children: result.name }),
                    /* @__PURE__ */ jsxs4("div", { className: "rf-text-sm rf-text-zinc-500", children: [
                      result.partNumber && /* @__PURE__ */ jsx7("span", { className: "rf-mr-2", children: result.partNumber }),
                      result.description
                    ] })
                  ] }),
                  /* @__PURE__ */ jsx7("div", { className: "rf-flex rf-gap-2", children: result.source === "tscircuit.com" && /* @__PURE__ */ jsx7(
                    Button,
                    {
                      variant: "outline",
                      size: "sm",
                      onClick: (e) => {
                        e.stopPropagation();
                        showDetails(result);
                      },
                      children: "See Details"
                    }
                  ) })
                ]
              },
              result.id
            )) }) : isLoading ? /* @__PURE__ */ jsxs4("div", { className: "rf-p-8 rf-text-center rf-text-zinc-500", children: [
              /* @__PURE__ */ jsx7(Loader22, { className: "rf-h-8 rf-w-8 rf-animate-spin rf-mx-auto rf-mb-2" }),
              /* @__PURE__ */ jsx7("p", { children: "Searching..." })
            ] }) : /* @__PURE__ */ jsx7("div", { className: "rf-p-8 rf-text-center rf-text-zinc-500", children: hasSearched ? "No results found" : "Enter a search term to find components" }) })
          ]
        }
      ),
      /* @__PURE__ */ jsxs4(AlertDialogFooter, { children: [
        /* @__PURE__ */ jsx7(AlertDialogCancel, { onClick: onClose, children: "Cancel" }),
        /* @__PURE__ */ jsx7(
          Button,
          {
            onClick: () => {
              if (selectedComponent) {
                onImport(selectedComponent);
                onClose();
              }
            },
            disabled: !selectedComponent,
            children: "Import Component"
          }
        )
      ] })
    ] }),
    /* @__PURE__ */ jsx7(AlertDialog, { open: detailsOpen, onOpenChange: setDetailsOpen, children: /* @__PURE__ */ jsxs4(AlertDialogContent, { className: "!rf-max-h-[70%] !rf-overflow-y-auto rf-flex rf-flex-col !rf-max-w-[60vw] !rf-overflow-x-hidden", children: [
      /* @__PURE__ */ jsxs4(AlertDialogHeader, { children: [
        /* @__PURE__ */ jsx7(AlertDialogTitle, { children: detailsComponent?.name }),
        /* @__PURE__ */ jsx7(AlertDialogDescription, { children: "Detailed information about the selected component" }),
        /* @__PURE__ */ jsxs4("div", { className: "rf-text-sm rf-text-muted-foreground", children: [
          detailsComponent?.partNumber && /* @__PURE__ */ jsx7("div", { className: "rf-font-mono rf-text-sm rf-mb-2", children: detailsComponent.partNumber }),
          detailsComponent?.description
        ] })
      ] }),
      detailsComponent?.source === "jlcpcb" && /* @__PURE__ */ jsxs4("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4", children: [
        /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "JLCPCB Details" }),
        /* @__PURE__ */ jsxs4("div", { className: "rf-grid rf-grid-cols-2 rf-gap-2", children: [
          detailsComponent.package && /* @__PURE__ */ jsxs4("div", { className: "rf-flex rf-flex-col", children: [
            /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Package" }),
            /* @__PURE__ */ jsx7("span", { className: "rf-font-medium", children: detailsComponent.package })
          ] }),
          detailsComponent.price !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "rf-flex rf-flex-col", children: [
            /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Price" }),
            /* @__PURE__ */ jsxs4("span", { className: "rf-font-medium", children: [
              "$",
              detailsComponent.price.toFixed(4)
            ] })
          ] })
        ] })
      ] }),
      detailsComponent?.source === "tscircuit.com" && /* @__PURE__ */ jsxs4("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4 !rf-max-w-[60vw] !rf-overflow-x-hidden", children: [
        /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "tscircuit Details" }),
        /* @__PURE__ */ jsx7("div", { className: "rf-grid rf-grid-cols-2 rf-gap-2", children: detailsComponent.owner && /* @__PURE__ */ jsxs4("div", { className: "rf-flex rf-flex-col", children: [
          /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Owner" }),
          /* @__PURE__ */ jsx7("span", { className: "rf-font-medium", children: detailsComponent.owner })
        ] }) }),
        detailsComponent.code && /* @__PURE__ */ jsxs4("div", { className: "rf-mt-2", children: [
          /* @__PURE__ */ jsx7("div", { className: "rf-text-xs rf-text-zinc-500 rf-mb-1", children: "Code Preview" }),
          /* @__PURE__ */ jsxs4("pre", { className: "rf-bg-zinc-50 rf-p-2 rf-rounded rf-text-xs rf-font-mono rf-max-h-32 rf-overflow-y-auto", children: [
            detailsComponent.code.substring(0, 500),
            detailsComponent.code.length > 500 && "..."
          ] })
        ] })
      ] }),
      /* @__PURE__ */ jsxs4("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4", children: [
        /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "Preview" }),
        detailsComponent?.source === "tscircuit.com" && detailsComponent.code ? /* @__PURE__ */ jsx7("div", { className: "rf-flex rf-justify-center", children: /* @__PURE__ */ jsx7("div", { className: "rf-border rf-rounded rf-p-4 rf-bg-zinc-50", children: /* @__PURE__ */ jsx7(
          "img",
          {
            src: createPngUrl(detailsComponent.code, "pcb"),
            alt: detailsComponent.name,
            className: "rf-w-full rf-aspect-video rf-object-contain"
          }
        ) }) }) : /* @__PURE__ */ jsx7("div", { className: "rf-text-center rf-text-zinc-500 rf-p-4", children: "No preview available" })
      ] }),
      /* @__PURE__ */ jsxs4("div", { className: "rf-flex rf-justify-between", children: [
        /* @__PURE__ */ jsxs4(
          Button,
          {
            variant: "outline",
            size: "sm",
            className: "rf-gap-1",
            onClick: () => {
              const url = detailsComponent?.source === "jlcpcb" ? `https://jlcpcb.com/partdetail/${detailsComponent.partNumber}` : `https://tscircuit.com/${detailsComponent.owner}/${detailsComponent?.name.split("/").pop()}`;
              window.open(url, "_blank");
            },
            children: [
              "View on",
              " ",
              detailsComponent?.source === "jlcpcb" ? "JLCPCB" : "tscircuit.com",
              " ",
              /* @__PURE__ */ jsx7(ExternalLink, { className: "rf-h-3 rf-w-3" })
            ]
          }
        ),
        /* @__PURE__ */ jsx7(
          Button,
          {
            onClick: () => {
              setDetailsOpen(false);
              if (detailsComponent) {
                onImport(detailsComponent);
                onClose();
              }
            },
            children: "Import Component"
          }
        )
      ] })
    ] }) })
  ] });
};

// lib/optional-features/exporting/formats/export-fabrication-files.ts
import JSZip from "jszip";
import {
  stringifyGerberCommandLayers,
  convertSoupToGerberCommands,
  convertSoupToExcellonDrillCommands,
  stringifyExcellonDrill
} from "circuit-json-to-gerber";
import {
  convertCircuitJsonToBomRows,
  convertBomRowsToCsv
} from "circuit-json-to-bom-csv";
import { convertCircuitJsonToPickAndPlaceCsv } from "circuit-json-to-pnp-csv";

// lib/optional-features/exporting/open-for-download.ts
var openForDownload = (content, opts) => {
  const { fileName, mimeType = "text/plain" } = opts;
  const blob = content instanceof Blob ? content : new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = fileName;
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }, 0);
};

// lib/optional-features/exporting/formats/export-fabrication-files.ts
var exportFabricationFiles = async ({
  circuitJson,
  projectName
}) => {
  const zip = new JSZip();
  const gerberLayerCmds = convertSoupToGerberCommands(circuitJson, {
    flip_y_axis: false
  });
  const gerberFileContents = stringifyGerberCommandLayers(gerberLayerCmds);
  for (const [fileName, fileContents] of Object.entries(gerberFileContents)) {
    zip.file(`gerber/${fileName}.gbr`, fileContents);
  }
  const drillCmds = convertSoupToExcellonDrillCommands({
    circuitJson,
    is_plated: true,
    flip_y_axis: false
  });
  const drillFileContents = stringifyExcellonDrill(drillCmds);
  zip.file("gerber/drill.drl", drillFileContents);
  const bomRows = await convertCircuitJsonToBomRows({ circuitJson });
  const bomCsv = await convertBomRowsToCsv(bomRows);
  zip.file("bom.csv", bomCsv);
  const pnpCsv = await convertCircuitJsonToPickAndPlaceCsv(circuitJson);
  zip.file("pick_and_place.csv", pnpCsv);
  const zipBlob = await zip.generateAsync({ type: "blob" });
  openForDownload(zipBlob, {
    fileName: `${projectName}_fabrication_files.zip`
  });
};

// lib/optional-features/exporting/export-and-download.ts
var availableExports = [
  { extension: "json", name: "Circuit JSON" },
  { extension: "zip", name: "Fabrication Files" }
  // { extension: "svg", name: "SVG" },
  // { extension: "dsn", name: "Specctra DSN" },
  // { extension: "glb", name: "GLB (Binary GLTF)" },
  // { extension: "kicad_mod", name: "KiCad Module" },
  // { extension: "kicad_project", name: "KiCad Project" },
  // { extension: "gbr", name: "Gerbers" },
];
var exportAndDownload = async ({
  exportName,
  circuitJson,
  projectName
}) => {
  if (exportName === "Fabrication Files") {
    exportFabricationFiles({ circuitJson, projectName });
    return;
  }
  if (exportName === "Circuit JSON") {
    openForDownload(JSON.stringify(circuitJson, null, 2), {
      fileName: `${projectName}.circuit.json`,
      mimeType: "application/json"
    });
    return;
  }
  throw new Error(`Unsupported export type: "${exportName}"`);
};

// lib/components/RunFrameForCli/LeftHeader.tsx
import { Toaster } from "react-hot-toast";

// lib/optional-features/importing/import-component-from-jlcpcb.ts
import { fetchEasyEDAComponent, convertRawEasyToTsx } from "easyeda/browser";
import ky from "ky";
var importComponentFromJlcpcb = async (jlcpcbPartNumber) => {
  const component = await fetchEasyEDAComponent(jlcpcbPartNumber, {
    // @ts-ignore
    fetch: (url, options) => {
      return fetch(`${API_BASE}/proxy`, {
        ...options,
        headers: {
          ...options?.headers,
          "X-Target-Url": url.toString(),
          "X-Sender-Origin": options?.headers?.origin ?? "",
          "X-Sender-Host": options?.headers?.host ?? "https://easyeda.com",
          "X-Sender-Referer": options?.headers?.referer ?? "",
          "X-Sender-User-Agent": options?.headers?.userAgent ?? "",
          "X-Sender-Cookie": options?.headers?.cookie ?? ""
        }
      });
    }
  });
  const tsx = await convertRawEasyToTsx(component);
  const fileName = tsx.match(/export const (\w+) = .*/)?.[1];
  if (!fileName) {
    console.error("COULD NOT DETERMINE FILE NAME OF CONVERTED COMPONENT:", tsx);
    throw new Error(`Could not determine file name of converted component`);
  }
  const filePath = `imports/${fileName}.tsx`;
  await ky.post(`${API_BASE}/files/upsert`, {
    json: {
      file_path: filePath,
      text_content: tsx
    }
  });
  return { filePath };
};

// lib/components/RunFrameForCli/LeftHeader.tsx
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
var RunframeCliLeftHeader = (props) => {
  const lastRunEvalVersion = useRunnerStore((s) => s.lastRunEvalVersion);
  const [snippetName, setSnippetName] = useState6(null);
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState6(false);
  const [hasNeverBeenSaved, setHasNeverBeenSaved] = useState6(true);
  const [isSaving, setIsSaving] = useState6(false);
  const [requestToSaveSentAt, setRequestToSaveSentAt] = useState6(
    null
  );
  const [availableSnippets, setAvailableSnippets] = useState6(
    null
  );
  const [isSelectSnippetDialogOpen, setIsSelectSnippetDialogOpen] = useState6(false);
  const [notificationMessage, setNotificationMessage] = useState6(
    null
  );
  const [errorMessage, setErrorMessage] = useState6(null);
  const [isError, setIsError] = useState6(false);
  const [isExporting, setisExporting] = useState6(false);
  const orderDialog = useOrderDialogCli();
  const pushEvent = useRunFrameStore((state) => state.pushEvent);
  const recentEvents = useRunFrameStore((state) => state.recentEvents);
  const firstRenderTime = useMemo2(() => Date.now(), []);
  useEventHandler((event) => {
    if (new Date(event.created_at).valueOf() < firstRenderTime + 500) return;
    if (event.event_type === "FILE_UPDATED") {
      setHasUnsavedChanges(true);
      return;
    }
    if (event.event_type === "SNIPPET_SAVED") {
      setHasUnsavedChanges(false);
      setHasNeverBeenSaved(false);
      setNotificationMessage("Snippet saved successfully.");
      setIsError(false);
      return;
    }
    if (event.event_type === "REQUEST_EXPORT") {
      setisExporting(true);
      setNotificationMessage("Export processing...");
      setIsError(false);
    }
    if (event.event_type === "EXPORT_CREATED") {
      setNotificationMessage(`Export created: ${event.exportFilePath}`);
      setIsError(false);
      setisExporting(false);
    }
  });
  useEffect8(() => {
    if (!isSaving || requestToSaveSentAt === null) return;
    const eventsSinceRequestToSave = recentEvents.filter(
      (event) => new Date(event.created_at).valueOf() > requestToSaveSentAt
    );
    const saveFailedEvent = eventsSinceRequestToSave.find(
      (event) => event.event_type === "FAILED_TO_SAVE_SNIPPET"
    );
    const saveSuccessEvent = eventsSinceRequestToSave.find(
      (event) => event.event_type === "SNIPPET_SAVED"
    );
    if (saveFailedEvent) {
      setIsSaving(false);
      setRequestToSaveSentAt(null);
      setErrorMessage(
        saveFailedEvent.message ?? "Failed to save snippet. See console for error."
      );
      console.error(saveFailedEvent.message);
      setIsError(true);
      if (saveFailedEvent.error_code === "SNIPPET_UNSET" && saveFailedEvent.available_snippet_names) {
        setAvailableSnippets(saveFailedEvent.available_snippet_names);
        setIsSelectSnippetDialogOpen(true);
      }
    }
    if (saveSuccessEvent) {
      setIsSaving(false);
      setRequestToSaveSentAt(null);
      setNotificationMessage("Snippet saved successfully.");
      setIsError(false);
    }
  }, [recentEvents, isSaving]);
  const triggerSaveSnippet = async () => {
    setIsSaving(true);
    setRequestToSaveSentAt(Date.now());
    setNotificationMessage(null);
    setIsError(false);
    await pushEvent({
      event_type: "REQUEST_TO_SAVE_SNIPPET",
      snippet_name: snippetName
    });
  };
  const circuitJson = useRunFrameStore((state) => state.circuitJson);
  const [isImportDialogOpen, setIsImportDialogOpen] = useState6(false);
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
    /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
      /* @__PURE__ */ jsx8(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx8("div", { className: "rf-whitespace-nowrap rf-text-xs font-medium rf-p-2 rf-mx-1 rf-cursor-pointer rf-relative", children: "File" }) }),
      /* @__PURE__ */ jsxs5(DropdownMenuContent, { children: [
        /* @__PURE__ */ jsx8(
          DropdownMenuItem,
          {
            className: "rf-text-xs",
            onSelect: triggerSaveSnippet,
            disabled: isSaving,
            children: isSaving ? "Saving..." : "Push"
          }
        ),
        parseInt(window.location.port) > 5e3 && /* @__PURE__ */ jsx8(
          DropdownMenuItem,
          {
            className: "rf-text-xs",
            onSelect: () => {
              orderDialog.open();
            },
            children: "Order"
          }
        ),
        /* @__PURE__ */ jsx8(
          DropdownMenuItem,
          {
            className: "rf-text-xs",
            onSelect: () => setIsImportDialogOpen(true),
            disabled: isSaving,
            children: "Import"
          }
        ),
        /* @__PURE__ */ jsxs5(DropdownMenuSub, { children: [
          /* @__PURE__ */ jsx8(
            DropdownMenuSubTrigger,
            {
              className: "rf-text-xs",
              disabled: isExporting,
              children: isExporting ? "Exporting..." : "Export"
            }
          ),
          /* @__PURE__ */ jsx8(DropdownMenuPortal, { children: /* @__PURE__ */ jsx8(DropdownMenuSubContent, { children: availableExports.map((exp, i) => /* @__PURE__ */ jsx8(
            DropdownMenuItem,
            {
              onSelect: () => {
                if (!circuitJson) {
                  toast.error("No Circuit JSON to export");
                  return;
                }
                exportAndDownload({
                  exportName: exp.name,
                  circuitJson,
                  projectName: snippetName ?? "Untitled"
                });
              },
              disabled: isExporting,
              children: /* @__PURE__ */ jsx8("span", { className: "rf-text-xs", children: exp.name })
            },
            i
          )) }) })
        ] }),
        /* @__PURE__ */ jsxs5(DropdownMenuSub, { children: [
          /* @__PURE__ */ jsx8(DropdownMenuSubTrigger, { className: "rf-text-xs", children: "Advanced" }),
          /* @__PURE__ */ jsx8(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs5(DropdownMenuSubContent, { children: [
            /* @__PURE__ */ jsx8(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-items-center rf-gap-2", children: [
              /* @__PURE__ */ jsx8(
                Checkbox,
                {
                  id: "load-latest-eval",
                  checked: props.shouldLoadLatestEval,
                  onCheckedChange: (checked) => {
                    props.onChangeShouldLoadLatestEval(checked === true);
                  }
                }
              ),
              /* @__PURE__ */ jsx8(
                "label",
                {
                  htmlFor: "load-latest-eval",
                  className: "rf-text-xs rf-cursor-pointer",
                  children: "Force Latest @tscircuit/eval"
                }
              )
            ] }) }),
            lastRunEvalVersion && /* @__PURE__ */ jsx8(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx8("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs5("span", { className: "rf-text-xs", children: [
              "@tscircuit/eval@",
              lastRunEvalVersion
            ] }) }) }),
            /* @__PURE__ */ jsx8(
              DropdownMenuItem,
              {
                className: "rf-flex rf-items-center rf-gap-2",
                onClick: () => {
                  window.open("/api/admin", "_blank");
                },
                children: /* @__PURE__ */ jsx8("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx8("span", { className: "rf-text-xs", children: "CLI Admin Panel" }) })
              }
            )
          ] }) })
        ] })
      ] }),
      /* @__PURE__ */ jsx8(AlertDialog, { open: isError, onOpenChange: setIsError, children: /* @__PURE__ */ jsxs5(AlertDialogContent, { children: [
        /* @__PURE__ */ jsxs5(AlertDialogHeader, { children: [
          /* @__PURE__ */ jsx8(AlertDialogTitle, { children: "Error Saving Snippet" }),
          /* @__PURE__ */ jsx8(AlertDialogDescription, { children: errorMessage })
        ] }),
        /* @__PURE__ */ jsx8(AlertDialogFooter, { children: /* @__PURE__ */ jsx8(AlertDialogCancel, { onClick: () => setIsError(false), children: "Dismiss" }) })
      ] }) }),
      /* @__PURE__ */ jsx8(
        SelectSnippetDialog,
        {
          snippetNames: availableSnippets ?? [],
          onSelect: async (name) => {
            setIsSaving(true);
            setRequestToSaveSentAt(Date.now());
            setSnippetName(name);
            await pushEvent({
              event_type: "REQUEST_TO_SAVE_SNIPPET",
              snippet_name: name
            });
            setIsSelectSnippetDialogOpen(false);
          },
          onCancel: () => setIsSelectSnippetDialogOpen(false),
          isOpen: isSelectSnippetDialogOpen
        }
      )
    ] }),
    /* @__PURE__ */ jsx8(
      ImportComponentDialog,
      {
        isOpen: isImportDialogOpen,
        onClose: () => setIsImportDialogOpen(false),
        onImport: async (component) => {
          toast.promise(
            async () => {
              if (component.source === "tscircuit.com") {
                await pushEvent({
                  event_type: "INSTALL_PACKAGE",
                  full_package_name: `@tsci/${component.owner}.${component.name}`
                });
                throw new Error("Not implemented");
              } else if (component.source === "jlcpcb") {
                const { filePath } = await importComponentFromJlcpcb(
                  component.partNumber
                );
                return { filePath };
              }
            },
            {
              loading: `Importing component: "${component.name}"`,
              error: (error) => {
                console.error("IMPORT ERROR", error);
                return `Error importing component: "${component.name}": ${error.toString()}`;
              },
              success: (data) => data?.filePath ? `Imported to "${data.filePath}"` : "Import Successful"
            }
          );
        }
      }
    ),
    /* @__PURE__ */ jsx8(Toaster, { position: "top-center", reverseOrder: false }),
    /* @__PURE__ */ jsx8(
      orderDialog.OrderDialog,
      {
        isOpen: orderDialog.isOpen,
        onClose: orderDialog.close,
        stage: orderDialog.stage,
        setStage: orderDialog.setStage
      }
    )
  ] });
};

// lib/components/RunFrameForCli/RunFrameForCli.tsx
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
var RunFrameForCli = (props) => {
  const [shouldLoadLatestEval, setLoadLatestEval] = useLocalStorageState(
    "load-latest-eval",
    true
  );
  return /* @__PURE__ */ jsx9(
    RunFrameWithApi,
    {
      debug: props.debug,
      forceLatestEvalVersion: shouldLoadLatestEval,
      defaultToFullScreen: true,
      showToggleFullScreen: false,
      leftHeaderContent: /* @__PURE__ */ jsxs6("div", { className: "rf-flex rf-items-center rf-justify-between", children: [
        /* @__PURE__ */ jsx9(
          RunframeCliLeftHeader,
          {
            shouldLoadLatestEval,
            onChangeShouldLoadLatestEval: (newShouldLoadLatestEval) => {
              setLoadLatestEval(newShouldLoadLatestEval);
              globalThis.runFrameWorker = null;
            }
          }
        ),
        props.scenarioSelectorContent
      ] })
    }
  );
};
export {
  BomTable,
  CadViewer,
  CircuitJsonPreview,
  PCBViewer as PcbViewer,
  PcbViewerWithContainerHeight,
  RunFrame,
  RunFrameForCli,
  RunFrameWithApi,
  SchematicViewer,
  guessEntrypoint,
  guessManualEditsFilePath,
  linkify,
  useOrderDialog,
  useOrderDialogCli
};
