/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
If you want to view the source, please visit the GitHub repository.
*/

var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/main.ts
var main_exports = {};
__export(main_exports, {
  default: () => OpenCodePlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian4 = require("obsidian");

// src/types.ts
var DEFAULT_SETTINGS = {
  port: 14096,
  hostname: "127.0.0.1",
  autoStart: false,
  opencodePath: "opencode",
  projectDirectory: "",
  startupTimeout: 15e3,
  defaultViewLocation: "sidebar"
};
var OPENCODE_VIEW_TYPE = "opencode-view";

// src/OpenCodeView.ts
var import_obsidian2 = require("obsidian");

// src/icons.ts
var import_obsidian = require("obsidian");
var OPENCODE_ICON_NAME = "opencode-logo";
var OPENCODE_LOGO_SVG = `<svg viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M18 24H6V12H18V24Z" fill="currentColor" opacity="0.4"/>
  <path d="M18 6H6V24H18V6ZM24 30H0V0H24V30Z" fill="currentColor"/>
</svg>`;
function registerOpenCodeIcons() {
  (0, import_obsidian.addIcon)(OPENCODE_ICON_NAME, OPENCODE_LOGO_SVG);
}

// src/OpenCodeView.ts
var OpenCodeView = class extends import_obsidian2.ItemView {
  constructor(leaf, plugin) {
    super(leaf);
    this.iframeEl = null;
    this.currentState = "stopped";
    this.unsubscribeStateChange = null;
    this.plugin = plugin;
  }
  getViewType() {
    return OPENCODE_VIEW_TYPE;
  }
  getDisplayText() {
    return "OpenCode";
  }
  getIcon() {
    return OPENCODE_ICON_NAME;
  }
  async onOpen() {
    this.contentEl.empty();
    this.contentEl.addClass("opencode-container");
    this.unsubscribeStateChange = this.plugin.onProcessStateChange((state) => {
      this.currentState = state;
      this.updateView();
    });
    this.currentState = this.plugin.getProcessState();
    this.updateView();
    if (this.currentState === "stopped") {
      this.plugin.startServer();
    }
  }
  async onClose() {
    if (this.unsubscribeStateChange) {
      this.unsubscribeStateChange();
      this.unsubscribeStateChange = null;
    }
    if (this.iframeEl) {
      this.iframeEl.src = "about:blank";
      this.iframeEl = null;
    }
  }
  updateView() {
    switch (this.currentState) {
      case "stopped":
        this.renderStoppedState();
        break;
      case "starting":
        this.renderStartingState();
        break;
      case "running":
        this.renderRunningState();
        break;
      case "error":
        this.renderErrorState();
        break;
    }
  }
  renderStoppedState() {
    this.contentEl.empty();
    const statusContainer = this.contentEl.createDiv({
      cls: "opencode-status-container"
    });
    const iconEl = statusContainer.createDiv({ cls: "opencode-status-icon" });
    (0, import_obsidian2.setIcon)(iconEl, "power-off");
    statusContainer.createEl("h3", { text: "OpenCode is stopped" });
    statusContainer.createEl("p", {
      text: "Click the button below to start the OpenCode server.",
      cls: "opencode-status-message"
    });
    const startButton = statusContainer.createEl("button", {
      text: "Start OpenCode",
      cls: "mod-cta"
    });
    startButton.addEventListener("click", () => {
      this.plugin.startServer();
    });
  }
  renderStartingState() {
    this.contentEl.empty();
    const statusContainer = this.contentEl.createDiv({
      cls: "opencode-status-container"
    });
    const loadingEl = statusContainer.createDiv({ cls: "opencode-loading" });
    loadingEl.createDiv({ cls: "opencode-spinner" });
    statusContainer.createEl("h3", { text: "Starting OpenCode..." });
    statusContainer.createEl("p", {
      text: "Please wait while the server starts up.",
      cls: "opencode-status-message"
    });
  }
  renderRunningState() {
    this.contentEl.empty();
    const headerEl = this.contentEl.createDiv({ cls: "opencode-header" });
    const titleSection = headerEl.createDiv({ cls: "opencode-header-title" });
    const iconEl = titleSection.createSpan();
    (0, import_obsidian2.setIcon)(iconEl, OPENCODE_ICON_NAME);
    titleSection.createSpan({ text: "OpenCode" });
    const actionsEl = headerEl.createDiv({ cls: "opencode-header-actions" });
    const reloadButton = actionsEl.createEl("button", {
      attr: { "aria-label": "Reload" }
    });
    (0, import_obsidian2.setIcon)(reloadButton, "refresh-cw");
    reloadButton.addEventListener("click", () => {
      this.reloadIframe();
    });
    const stopButton = actionsEl.createEl("button", {
      attr: { "aria-label": "Stop server" }
    });
    (0, import_obsidian2.setIcon)(stopButton, "square");
    stopButton.addEventListener("click", () => {
      this.plugin.stopServer();
    });
    const iframeContainer = this.contentEl.createDiv({
      cls: "opencode-iframe-container"
    });
    console.log("[OpenCode] Loading iframe with URL:", this.plugin.getServerUrl());
    this.iframeEl = iframeContainer.createEl("iframe", {
      cls: "opencode-iframe",
      attr: {
        src: this.plugin.getServerUrl(),
        frameborder: "0",
        allow: "clipboard-read; clipboard-write"
      }
    });
    this.iframeEl.addEventListener("error", () => {
      console.error("Failed to load OpenCode iframe");
    });
  }
  renderErrorState() {
    this.contentEl.empty();
    const statusContainer = this.contentEl.createDiv({
      cls: "opencode-status-container opencode-error"
    });
    const iconEl = statusContainer.createDiv({ cls: "opencode-status-icon" });
    (0, import_obsidian2.setIcon)(iconEl, "alert-circle");
    statusContainer.createEl("h3", { text: "Failed to start OpenCode" });
    const errorMessage = this.plugin.getLastError();
    if (errorMessage) {
      statusContainer.createEl("p", {
        text: errorMessage,
        cls: "opencode-status-message opencode-error-message"
      });
    } else {
      statusContainer.createEl("p", {
        text: "There was an error starting the OpenCode server.",
        cls: "opencode-status-message"
      });
    }
    const buttonContainer = statusContainer.createDiv({
      cls: "opencode-button-group"
    });
    const retryButton = buttonContainer.createEl("button", {
      text: "Retry",
      cls: "mod-cta"
    });
    retryButton.addEventListener("click", () => {
      this.plugin.startServer();
    });
    const settingsButton = buttonContainer.createEl("button", {
      text: "Open Settings"
    });
    settingsButton.addEventListener("click", () => {
      this.app.setting.open();
      this.app.setting.openTabById("obsidian-opencode");
    });
  }
  reloadIframe() {
    if (this.iframeEl) {
      const src = this.iframeEl.src;
      this.iframeEl.src = "about:blank";
      setTimeout(() => {
        if (this.iframeEl) {
          this.iframeEl.src = src;
        }
      }, 100);
    }
  }
};

// src/SettingsTab.ts
var import_obsidian3 = require("obsidian");
var import_fs = require("fs");
var import_os = require("os");
function expandTilde(path) {
  if (path === "~") {
    return (0, import_os.homedir)();
  }
  if (path.startsWith("~/")) {
    return path.replace("~", (0, import_os.homedir)());
  }
  return path;
}
var OpenCodeSettingTab = class extends import_obsidian3.PluginSettingTab {
  constructor(app, plugin) {
    super(app, plugin);
    this.validateTimeout = null;
    this.plugin = plugin;
  }
  display() {
    const { containerEl } = this;
    containerEl.empty();
    containerEl.createEl("h2", { text: "OpenCode Settings" });
    containerEl.createEl("h3", { text: "Server Configuration" });
    new import_obsidian3.Setting(containerEl).setName("Port").setDesc("Port number for the OpenCode web server").addText(
      (text) => text.setPlaceholder("14096").setValue(this.plugin.settings.port.toString()).onChange(async (value) => {
        const port = parseInt(value, 10);
        if (!isNaN(port) && port > 0 && port < 65536) {
          this.plugin.settings.port = port;
          await this.plugin.saveSettings();
        }
      })
    );
    new import_obsidian3.Setting(containerEl).setName("Hostname").setDesc("Hostname to bind the server to (usually 127.0.0.1)").addText(
      (text) => text.setPlaceholder("127.0.0.1").setValue(this.plugin.settings.hostname).onChange(async (value) => {
        this.plugin.settings.hostname = value || "127.0.0.1";
        await this.plugin.saveSettings();
      })
    );
    new import_obsidian3.Setting(containerEl).setName("OpenCode path").setDesc(
      "Path to the OpenCode executable. Leave as 'opencode' if it's in your PATH."
    ).addText(
      (text) => text.setPlaceholder("opencode").setValue(this.plugin.settings.opencodePath).onChange(async (value) => {
        this.plugin.settings.opencodePath = value || "opencode";
        await this.plugin.saveSettings();
      })
    );
    new import_obsidian3.Setting(containerEl).setName("Project directory").setDesc(
      "Override the starting directory for OpenCode. Leave empty to use the vault root. Supports ~ for home directory."
    ).addText(
      (text) => text.setPlaceholder("/path/to/project or ~/project").setValue(this.plugin.settings.projectDirectory).onChange((value) => {
        if (this.validateTimeout) {
          clearTimeout(this.validateTimeout);
        }
        this.validateTimeout = setTimeout(async () => {
          await this.validateAndSetProjectDirectory(value);
        }, 500);
      })
    );
    containerEl.createEl("h3", { text: "Behavior" });
    new import_obsidian3.Setting(containerEl).setName("Auto-start server").setDesc(
      "Automatically start the OpenCode server when Obsidian opens (not recommended for faster startup)"
    ).addToggle(
      (toggle) => toggle.setValue(this.plugin.settings.autoStart).onChange(async (value) => {
        this.plugin.settings.autoStart = value;
        await this.plugin.saveSettings();
      })
    );
    new import_obsidian3.Setting(containerEl).setName("Default view location").setDesc(
      "Where to open the OpenCode panel: sidebar opens in the right panel, main opens as a tab in the editor area"
    ).addDropdown(
      (dropdown) => dropdown.addOption("sidebar", "Sidebar").addOption("main", "Main window").setValue(this.plugin.settings.defaultViewLocation).onChange(async (value) => {
        this.plugin.settings.defaultViewLocation = value;
        await this.plugin.saveSettings();
      })
    );
    containerEl.createEl("h3", { text: "Server Status" });
    const statusContainer = containerEl.createDiv({ cls: "opencode-settings-status" });
    this.renderServerStatus(statusContainer);
  }
  async validateAndSetProjectDirectory(value) {
    const trimmed = value.trim();
    if (!trimmed) {
      await this.plugin.updateProjectDirectory("");
      return;
    }
    if (!trimmed.startsWith("/") && !trimmed.startsWith("~") && !trimmed.match(/^[A-Za-z]:\\/)) {
      new import_obsidian3.Notice("Project directory must be an absolute path (or start with ~)");
      return;
    }
    const expanded = expandTilde(trimmed);
    try {
      if (!(0, import_fs.existsSync)(expanded)) {
        new import_obsidian3.Notice("Project directory does not exist");
        return;
      }
      const stat = (0, import_fs.statSync)(expanded);
      if (!stat.isDirectory()) {
        new import_obsidian3.Notice("Project directory path is not a directory");
        return;
      }
    } catch (error) {
      new import_obsidian3.Notice(`Failed to validate path: ${error.message}`);
      return;
    }
    await this.plugin.updateProjectDirectory(expanded);
  }
  renderServerStatus(container) {
    container.empty();
    const state = this.plugin.getProcessState();
    const statusText = {
      stopped: "Stopped",
      starting: "Starting...",
      running: "Running",
      error: "Error"
    };
    const statusClass = {
      stopped: "status-stopped",
      starting: "status-starting",
      running: "status-running",
      error: "status-error"
    };
    const statusEl = container.createDiv({ cls: "opencode-status-line" });
    statusEl.createSpan({ text: "Status: " });
    statusEl.createSpan({
      text: statusText[state],
      cls: `opencode-status-badge ${statusClass[state]}`
    });
    if (state === "running") {
      const urlEl = container.createDiv({ cls: "opencode-status-line" });
      urlEl.createSpan({ text: "URL: " });
      const linkEl = urlEl.createEl("a", {
        text: this.plugin.getServerUrl(),
        href: this.plugin.getServerUrl()
      });
      linkEl.addEventListener("click", (e) => {
        e.preventDefault();
        window.open(this.plugin.getServerUrl(), "_blank");
      });
    }
    const buttonContainer = container.createDiv({ cls: "opencode-settings-buttons" });
    if (state === "stopped" || state === "error") {
      const startButton = buttonContainer.createEl("button", {
        text: "Start Server",
        cls: "mod-cta"
      });
      startButton.addEventListener("click", async () => {
        await this.plugin.startServer();
        this.renderServerStatus(container);
      });
    }
    if (state === "running") {
      const stopButton = buttonContainer.createEl("button", {
        text: "Stop Server"
      });
      stopButton.addEventListener("click", () => {
        this.plugin.stopServer();
        this.renderServerStatus(container);
      });
      const restartButton = buttonContainer.createEl("button", {
        text: "Restart Server",
        cls: "mod-warning"
      });
      restartButton.addEventListener("click", async () => {
        this.plugin.stopServer();
        await this.plugin.startServer();
        this.renderServerStatus(container);
      });
    }
    if (state === "starting") {
      buttonContainer.createSpan({
        text: "Please wait...",
        cls: "opencode-status-waiting"
      });
    }
  }
};

// src/ProcessManager.ts
var import_child_process = require("child_process");
var ProcessManager = class {
  constructor(settings, projectDirectory, onStateChange) {
    this.process = null;
    this.state = "stopped";
    this.lastError = null;
    this.earlyExitCode = null;
    this.settings = settings;
    this.projectDirectory = projectDirectory;
    this.onStateChange = onStateChange;
  }
  updateSettings(settings) {
    this.settings = settings;
  }
  updateProjectDirectory(directory) {
    this.projectDirectory = directory;
  }
  getState() {
    return this.state;
  }
  getLastError() {
    return this.lastError;
  }
  getUrl() {
    const baseUrl = `http://${this.settings.hostname}:${this.settings.port}`;
    const encodedPath = btoa(this.projectDirectory);
    return `${baseUrl}/${encodedPath}`;
  }
  async start() {
    var _a, _b;
    if (this.state === "running" || this.state === "starting") {
      return true;
    }
    this.setState("starting");
    this.lastError = null;
    this.earlyExitCode = null;
    if (!this.projectDirectory) {
      return this.setError("Project directory (vault) not configured");
    }
    if (await this.checkServerHealth()) {
      console.log("[OpenCode] Server already running on port", this.settings.port);
      this.setState("running");
      return true;
    }
    console.log("[OpenCode] Starting server:", {
      opencodePath: this.settings.opencodePath,
      port: this.settings.port,
      hostname: this.settings.hostname,
      cwd: this.projectDirectory,
      projectDirectory: this.projectDirectory
    });
    this.process = (0, import_child_process.spawn)(
      this.settings.opencodePath,
      [
        "serve",
        "--port",
        this.settings.port.toString(),
        "--hostname",
        this.settings.hostname,
        "--cors",
        "app://obsidian.md"
      ],
      {
        cwd: this.projectDirectory,
        env: { ...process.env },
        stdio: ["ignore", "pipe", "pipe"],
        detached: false
      }
    );
    console.log("[OpenCode] Process spawned with PID:", this.process.pid);
    (_a = this.process.stdout) == null ? void 0 : _a.on("data", (data) => {
      console.log("[OpenCode]", data.toString().trim());
    });
    (_b = this.process.stderr) == null ? void 0 : _b.on("data", (data) => {
      console.error("[OpenCode Error]", data.toString().trim());
    });
    this.process.on("exit", (code, signal) => {
      console.log(`[OpenCode] Process exited with code ${code}, signal ${signal}`);
      this.process = null;
      if (this.state === "starting" && code !== null && code !== 0) {
        this.earlyExitCode = code;
      }
      if (this.state === "running") {
        this.setState("stopped");
      }
    });
    this.process.on("error", (err) => {
      console.error("[OpenCode] Failed to start process:", err);
      this.process = null;
      if (err.code === "ENOENT") {
        this.setError(`Executable not found at '${this.settings.opencodePath}'`);
      } else {
        this.setError(`Failed to start: ${err.message}`);
      }
    });
    const ready = await this.waitForServerOrExit(this.settings.startupTimeout);
    if (ready) {
      this.setState("running");
      return true;
    }
    if (this.state === "error") {
      return false;
    }
    this.stop();
    if (this.earlyExitCode !== null) {
      return this.setError(`Process exited unexpectedly (exit code ${this.earlyExitCode})`);
    }
    if (!this.process) {
      return this.setError("Process exited before server became ready");
    }
    return this.setError("Server failed to start within timeout");
  }
  stop() {
    if (!this.process) {
      this.setState("stopped");
      return;
    }
    const proc = this.process;
    console.log("[OpenCode] Stopping process with PID:", proc.pid);
    this.setState("stopped");
    this.process = null;
    proc.kill("SIGTERM");
    setTimeout(() => {
      if (proc.exitCode === null && proc.signalCode === null) {
        console.log("[OpenCode] Process still running, sending SIGKILL");
        proc.kill("SIGKILL");
      }
    }, 2e3);
  }
  setState(state) {
    this.state = state;
    this.onStateChange(state);
  }
  setError(message) {
    this.lastError = message;
    console.error("[OpenCode Error]", message);
    this.setState("error");
    return false;
  }
  async checkServerHealth() {
    try {
      const response = await fetch(`${this.getUrl()}/global/health`, {
        method: "GET",
        signal: AbortSignal.timeout(2e3)
      });
      return response.ok;
    } catch (e) {
      return false;
    }
  }
  async waitForServerOrExit(timeoutMs) {
    const startTime = Date.now();
    const pollInterval = 500;
    while (Date.now() - startTime < timeoutMs) {
      if (!this.process) {
        console.log("[OpenCode] Process exited before server became ready");
        return false;
      }
      if (await this.checkServerHealth()) {
        return true;
      }
      await this.sleep(pollInterval);
    }
    return false;
  }
  sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
};

// src/main.ts
var OpenCodePlugin = class extends import_obsidian4.Plugin {
  constructor() {
    super(...arguments);
    this.settings = DEFAULT_SETTINGS;
    this.stateChangeCallbacks = [];
  }
  async onload() {
    console.log("Loading OpenCode plugin");
    registerOpenCodeIcons();
    await this.loadSettings();
    const projectDirectory = this.getProjectDirectory();
    this.processManager = new ProcessManager(
      this.settings,
      projectDirectory,
      (state) => this.notifyStateChange(state)
    );
    console.log("[OpenCode] Configured with project directory:", projectDirectory);
    this.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
    this.addSettingTab(new OpenCodeSettingTab(this.app, this));
    this.addRibbonIcon(OPENCODE_ICON_NAME, "OpenCode", () => {
      this.activateView();
    });
    this.addCommand({
      id: "toggle-opencode-view",
      name: "Toggle OpenCode panel",
      callback: () => {
        this.toggleView();
      },
      hotkeys: [
        {
          modifiers: ["Mod", "Shift"],
          key: "o"
        }
      ]
    });
    this.addCommand({
      id: "start-opencode-server",
      name: "Start OpenCode server",
      callback: () => {
        this.startServer();
      }
    });
    this.addCommand({
      id: "stop-opencode-server",
      name: "Stop OpenCode server",
      callback: () => {
        this.stopServer();
      }
    });
    if (this.settings.autoStart) {
      this.app.workspace.onLayoutReady(async () => {
        await this.startServer();
      });
    }
    console.log("OpenCode plugin loaded");
  }
  async onunload() {
    this.stopServer();
    this.app.workspace.detachLeavesOfType(OPENCODE_VIEW_TYPE);
  }
  async loadSettings() {
    this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  }
  async saveSettings() {
    await this.saveData(this.settings);
    this.processManager.updateSettings(this.settings);
  }
  // Update project directory and restart server if running
  async updateProjectDirectory(directory) {
    this.settings.projectDirectory = directory;
    await this.saveData(this.settings);
    this.processManager.updateProjectDirectory(this.getProjectDirectory());
    if (this.getProcessState() === "running") {
      this.stopServer();
      await this.startServer();
    }
  }
  // Get existing view leaf if any
  getExistingLeaf() {
    const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
    return leaves.length > 0 ? leaves[0] : null;
  }
  // Activate or create the view
  async activateView() {
    const existingLeaf = this.getExistingLeaf();
    if (existingLeaf) {
      this.app.workspace.revealLeaf(existingLeaf);
      return;
    }
    let leaf = null;
    if (this.settings.defaultViewLocation === "main") {
      leaf = this.app.workspace.getLeaf("tab");
    } else {
      leaf = this.app.workspace.getRightLeaf(false);
    }
    if (leaf) {
      await leaf.setViewState({
        type: OPENCODE_VIEW_TYPE,
        active: true
      });
      this.app.workspace.revealLeaf(leaf);
    }
  }
  // Toggle view visibility
  async toggleView() {
    const existingLeaf = this.getExistingLeaf();
    if (existingLeaf) {
      const isInSidebar = existingLeaf.getRoot() === this.app.workspace.rightSplit;
      if (isInSidebar) {
        const rightSplit = this.app.workspace.rightSplit;
        if (rightSplit && !rightSplit.collapsed) {
          existingLeaf.detach();
        } else {
          this.app.workspace.revealLeaf(existingLeaf);
        }
      } else {
        existingLeaf.detach();
      }
    } else {
      await this.activateView();
    }
  }
  async startServer() {
    const success = await this.processManager.start();
    if (success) {
      new import_obsidian4.Notice("OpenCode server started");
    }
    return success;
  }
  stopServer() {
    this.processManager.stop();
    new import_obsidian4.Notice("OpenCode server stopped");
  }
  getProcessState() {
    var _a, _b;
    return (_b = (_a = this.processManager) == null ? void 0 : _a.getState()) != null ? _b : "stopped";
  }
  getLastError() {
    var _a;
    return (_a = this.processManager.getLastError()) != null ? _a : null;
  }
  getServerUrl() {
    return this.processManager.getUrl();
  }
  onProcessStateChange(callback) {
    this.stateChangeCallbacks.push(callback);
    return () => {
      const index = this.stateChangeCallbacks.indexOf(callback);
      if (index > -1) {
        this.stateChangeCallbacks.splice(index, 1);
      }
    };
  }
  notifyStateChange(state) {
    for (const callback of this.stateChangeCallbacks) {
      callback(state);
    }
  }
  getProjectDirectory() {
    if (this.settings.projectDirectory) {
      console.log("[OpenCode] Using project directory from settings:", this.settings.projectDirectory);
      return this.settings.projectDirectory;
    }
    const adapter = this.app.vault.adapter;
    const vaultPath = adapter.basePath || "";
    if (!vaultPath) {
      console.warn("[OpenCode] Warning: Could not determine vault path");
    }
    console.log("[OpenCode] Using vault path as project directory:", vaultPath);
    return vaultPath;
  }
};
