From 26154cc21eb8ca1928cad8a7bad9ed509c4a6a6b Mon Sep 17 00:00:00 2001 From: Mateusz Tymek Date: Sun, 1 Feb 2026 20:23:38 +0100 Subject: [PATCH] Remove compiled version of the plugin --- .gitignore | 5 +- main.js | 1217 ---------------------------------------------------- 2 files changed, 3 insertions(+), 1219 deletions(-) delete mode 100644 main.js diff --git a/.gitignore b/.gitignore index c2d3004..e12fee6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -node_modules -data.json +/node_modules +/data.json +/main.js diff --git a/main.js b/main.js deleted file mode 100644 index 2b65a9f..0000000 --- a/main.js +++ /dev/null @@ -1,1217 +0,0 @@ -/* -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_obsidian5 = require("obsidian"); - -// src/types.ts -var DEFAULT_SETTINGS = { - port: 14096, - hostname: "127.0.0.1", - autoStart: false, - opencodePath: "opencode", - projectDirectory: "", - startupTimeout: 15e3, - defaultViewLocation: "sidebar", - injectWorkspaceContext: true, - maxNotesInContext: 20, - maxSelectionLength: 2e3 -}; -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 = ` - - -`; -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) { - const iframeUrl = this.iframeEl.src; - if (iframeUrl.includes("/session/")) { - this.plugin.setCachedIframeUrl(iframeUrl); - } - 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() { - var _a; - 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" - }); - const iframeUrl = (_a = this.plugin.getStoredIframeUrl()) != null ? _a : this.plugin.getServerUrl(); - console.log("[OpenCode] Loading iframe with URL:", iframeUrl); - this.iframeEl = iframeContainer.createEl("iframe", { - cls: "opencode-iframe", - attr: { - src: iframeUrl, - frameborder: "0", - allow: "clipboard-read; clipboard-write" - } - }); - this.iframeEl.addEventListener("error", () => { - console.error("Failed to load OpenCode iframe"); - }); - this.iframeEl.addEventListener("focus", () => { - this.plugin.refreshContextForView(this); - }); - this.iframeEl.addEventListener("pointerdown", () => { - this.plugin.refreshContextForView(this); - }); - void this.plugin.ensureSessionUrl(this); - } - getIframeUrl() { - var _a, _b; - return (_b = (_a = this.iframeEl) == null ? void 0 : _a.src) != null ? _b : null; - } - setIframeUrl(url) { - if (this.iframeEl && this.iframeEl.src !== url) { - this.iframeEl.src = url; - } - } - 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: "Workspace Context" }); - new import_obsidian3.Setting(containerEl).setName("Inject workspace context").setDesc( - "Includes open note paths and selected text in OpenCode when the view is focused" - ).addToggle( - (toggle) => toggle.setValue(this.plugin.settings.injectWorkspaceContext).onChange(async (value) => { - this.plugin.settings.injectWorkspaceContext = value; - await this.plugin.saveSettings(); - }) - ); - new import_obsidian3.Setting(containerEl).setName("Max notes in context").setDesc("Limit how many open notes are included").addSlider( - (slider) => slider.setLimits(1, 50, 1).setValue(this.plugin.settings.maxNotesInContext).setDynamicTooltip().onChange(async (value) => { - this.plugin.settings.maxNotesInContext = value; - await this.plugin.saveSettings(); - }) - ); - new import_obsidian3.Setting(containerEl).setName("Max selection length").setDesc("Truncate selected text to avoid oversized context").addSlider( - (slider) => slider.setLimits(500, 5e3, 100).setValue(this.plugin.settings.maxSelectionLength).setDynamicTooltip().onChange(async (value) => { - this.plugin.settings.maxSelectionLength = 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 encodedPath = btoa(this.projectDirectory); - return `http://${this.settings.hostname}:${this.settings.port}/${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, NODE_USE_SYSTEM_CA: "1" }, - 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/OpenCodeClient.ts -var OpenCodeClient = class { - constructor(apiBaseUrl, uiBaseUrl, projectDirectory) { - this.trackedSessionId = null; - this.lastPart = null; - this.apiBaseUrl = this.normalizeBaseUrl(apiBaseUrl); - this.uiBaseUrl = this.normalizeBaseUrl(uiBaseUrl); - this.projectDirectory = projectDirectory; - } - updateBaseUrl(apiBaseUrl, uiBaseUrl, projectDirectory) { - const nextApiUrl = this.normalizeBaseUrl(apiBaseUrl); - const nextUiUrl = this.normalizeBaseUrl(uiBaseUrl); - if (nextApiUrl !== this.apiBaseUrl || nextUiUrl !== this.uiBaseUrl || projectDirectory !== this.projectDirectory) { - this.apiBaseUrl = nextApiUrl; - this.uiBaseUrl = nextUiUrl; - this.projectDirectory = projectDirectory; - this.resetTracking(); - } - } - resetTracking() { - this.trackedSessionId = null; - this.lastPart = null; - } - getSessionUrl(sessionId) { - return `${this.uiBaseUrl}/session/${sessionId}`; - } - resolveSessionId(iframeUrl) { - var _a; - const match = iframeUrl.match(/\/session\/([^/?#]+)/); - return (_a = match == null ? void 0 : match[1]) != null ? _a : null; - } - async createSession() { - var _a; - const result = await this.request("POST", "/session", { - title: "Obsidian" - }); - const session = this.unwrap(result); - return (_a = session == null ? void 0 : session.id) != null ? _a : null; - } - async updateContext(params) { - var _a, _b, _c; - const { sessionId, contextText } = params; - if (this.trackedSessionId && this.trackedSessionId !== sessionId) { - this.resetTracking(); - } - this.trackedSessionId = sessionId; - if (!contextText) { - await this.ignorePreviousPart(); - return; - } - if (this.lastPart) { - const updated = await this.updatePart(this.lastPart, { text: contextText }); - if (updated) { - return; - } - await this.ignorePreviousPart(); - } - const message = await this.sendPrompt(sessionId, contextText); - if ((_a = message == null ? void 0 : message.info) == null ? void 0 : _a.id) { - this.lastPart = (_c = (_b = message.parts) == null ? void 0 : _b[0]) != null ? _c : null; - } - } - async sendPrompt(sessionId, contextText) { - const result = await this.request( - "POST", - `/session/${sessionId}/message`, - { - noReply: true, - parts: [{ type: "text", text: contextText }] - } - ); - console.log("[OpenCode] Injected context message"); - console.log(contextText); - const message = this.unwrap(result); - if (!message) { - console.error("[OpenCode] Failed to inject context message"); - } - return message; - } - async updatePart(part, updates) { - const result = await this.request( - "PATCH", - `/session/${part.sessionID}/message/${part.messageID}/part/${part.id}`, - { - ...part, - ...updates - } - ); - const updated = this.unwrap(result); - if (updated) { - this.lastPart = updated; - return true; - } - return false; - } - async ignorePreviousPart() { - if (!this.lastPart) { - return false; - } - const ignored = await this.updatePart(this.lastPart, { ignored: true }); - if (!ignored) { - return false; - } - this.lastPart = null; - return true; - } - async request(method, path, body) { - try { - const url = `${this.apiBaseUrl}${path}`; - const response = await fetch(url, { - method, - headers: { - "Content-Type": "application/json", - "x-opencode-directory": this.projectDirectory - }, - body: body ? JSON.stringify(body) : void 0 - }); - if (!response.ok) { - console.error("[OpenCode] API request failed", { - path, - status: response.status - }); - return null; - } - const json = await response.json().catch(() => null); - return json; - } catch (error) { - console.error("[OpenCode] API request error", error); - return null; - } - } - unwrap(result) { - if (!result) { - return null; - } - if (typeof result === "object") { - const payload = result; - if (payload.data) { - return payload.data; - } - if (payload.message) { - return payload.message; - } - } - return result; - } - normalizeBaseUrl(baseUrl) { - return baseUrl.replace(/\/+$/, ""); - } -}; - -// src/WorkspaceContext.ts -var import_obsidian4 = require("obsidian"); -var WorkspaceContext = class { - constructor(app) { - this.lastSelection = null; - this.lastMarkdownView = null; - this.app = app; - } - trackViewSelection(view) { - var _a, _b, _c; - if (view) { - this.lastMarkdownView = view; - } - const sourcePath = (_a = view == null ? void 0 : view.file) == null ? void 0 : _a.path; - const selection = (_c = (_b = view == null ? void 0 : view.editor) == null ? void 0 : _b.getSelection()) != null ? _c : ""; - if (sourcePath && selection.trim()) { - this.lastSelection = { - text: selection, - sourcePath - }; - } - } - gatherContext(maxNotes, maxSelectionLength) { - var _a, _b, _c, _d, _e; - const leaves = this.app.workspace.getLeavesOfType("markdown"); - const paths = /* @__PURE__ */ new Set(); - for (const leaf of leaves) { - const view2 = leaf.view; - const path = (_a = view2.file) == null ? void 0 : _a.path; - if (path) { - paths.add(path); - } - } - const openNotePaths = Array.from(paths).slice(0, Math.max(0, maxNotes)); - const view = (_b = this.app.workspace.getActiveViewOfType(import_obsidian4.MarkdownView)) != null ? _b : this.lastMarkdownView; - this.trackViewSelection(view); - const sourcePath = (_c = view == null ? void 0 : view.file) == null ? void 0 : _c.path; - const selection = (_e = (_d = view == null ? void 0 : view.editor) == null ? void 0 : _d.getSelection()) != null ? _e : ""; - let selectionContext = null; - if (sourcePath && selection.trim()) { - selectionContext = { - text: selection, - sourcePath - }; - this.lastSelection = selectionContext; - } else if (this.lastSelection) { - selectionContext = this.lastSelection; - } - if (selectionContext && selectionContext.text.length > maxSelectionLength) { - selectionContext = { - ...selectionContext, - text: selectionContext.text.slice(0, maxSelectionLength) + "... [truncated]" - }; - } - let contextText = null; - if (openNotePaths.length > 0 || selectionContext) { - const lines = [""]; - if (openNotePaths.length > 0) { - lines.push("Currently open notes in Obsidian:"); - for (const path of openNotePaths) { - lines.push(`- ${path}`); - } - } - if (selectionContext) { - lines.push(""); - lines.push(`Selected text (from ${selectionContext.sourcePath}):`); - lines.push('"""'); - lines.push(selectionContext.text); - lines.push('"""'); - } - lines.push(""); - contextText = lines.join("\n"); - } - return { - openNotePaths, - selection: selectionContext, - contextText - }; - } -}; - -// src/main.ts -var OpenCodePlugin = class extends import_obsidian5.Plugin { - constructor() { - super(...arguments); - this.settings = DEFAULT_SETTINGS; - this.stateChangeCallbacks = []; - this.cachedIframeUrl = null; - this.lastBaseUrl = null; - this.contextEventRefs = []; - this.contextRefreshTimer = null; - } - 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) - ); - this.openCodeClient = new OpenCodeClient(this.getApiBaseUrl(), this.getServerUrl(), projectDirectory); - this.workspaceContext = new WorkspaceContext(this.app); - this.lastBaseUrl = this.getServerUrl(); - 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(); - }); - } - this.updateContextListeners(); - this.onProcessStateChange((state) => { - if (state === "running") { - void this.handleServerRunning(); - } - }); - 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); - this.refreshClientState(); - this.updateContextListeners(); - } - // 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()); - this.refreshClientState(); - if (this.getProcessState() === "running") { - this.stopServer(); - await this.startServer(); - } - } - getExistingLeaf() { - const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE); - return leaves.length > 0 ? leaves[0] : null; - } - 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); - } - } - 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_obsidian5.Notice("OpenCode server started"); - } - return success; - } - stopServer() { - this.processManager.stop(); - new import_obsidian5.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(); - } - getApiBaseUrl() { - return `http://${this.settings.hostname}:${this.settings.port}`; - } - getStoredIframeUrl() { - return this.cachedIframeUrl; - } - setCachedIframeUrl(url) { - this.cachedIframeUrl = url; - } - async ensureSessionUrl(view) { - var _a; - if (this.getProcessState() !== "running") { - return; - } - const existingUrl = (_a = this.cachedIframeUrl) != null ? _a : view.getIframeUrl(); - if (existingUrl && this.openCodeClient.resolveSessionId(existingUrl)) { - this.cachedIframeUrl = existingUrl; - return; - } - const sessionId = await this.openCodeClient.createSession(); - if (!sessionId) { - return; - } - const sessionUrl = this.openCodeClient.getSessionUrl(sessionId); - this.cachedIframeUrl = sessionUrl; - view.setIframeUrl(sessionUrl); - if (this.app.workspace.activeLeaf === view.leaf) { - await this.updateOpenCodeContext(view.leaf); - } - } - refreshContextForView(view) { - if (!this.settings.injectWorkspaceContext) { - return; - } - void this.updateOpenCodeContext(view.leaf); - } - 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); - } - } - refreshClientState() { - const nextUiBaseUrl = this.getServerUrl(); - const nextApiBaseUrl = this.getApiBaseUrl(); - const projectDirectory = this.getProjectDirectory(); - this.openCodeClient.updateBaseUrl(nextApiBaseUrl, nextUiBaseUrl, projectDirectory); - if (this.lastBaseUrl && this.lastBaseUrl !== nextUiBaseUrl) { - this.cachedIframeUrl = null; - } - this.lastBaseUrl = nextUiBaseUrl; - } - updateContextListeners() { - if (!this.settings.injectWorkspaceContext) { - this.clearContextListeners(); - return; - } - if (this.contextEventRefs.length > 0) { - return; - } - const activeLeafRef = this.app.workspace.on("active-leaf-change", (leaf) => { - if ((leaf == null ? void 0 : leaf.view) instanceof import_obsidian5.MarkdownView) { - this.workspaceContext.trackViewSelection(leaf.view); - } - this.scheduleContextRefresh(0); - }); - const fileOpenRef = this.app.workspace.on("file-open", () => { - this.scheduleContextRefresh(); - }); - const fileCloseRef = this.app.workspace.on("file-close", () => { - this.scheduleContextRefresh(); - }); - const layoutChangeRef = this.app.workspace.on("layout-change", () => { - this.scheduleContextRefresh(); - }); - const editorChangeRef = this.app.workspace.on("editor-change", (_editor, view) => { - if (view instanceof import_obsidian5.MarkdownView) { - this.workspaceContext.trackViewSelection(view); - } - this.scheduleContextRefresh(500); - }); - const selectionChangeRef = this.app.workspace.on( - "editor-selection-change", - (_editor, view) => { - if (view instanceof import_obsidian5.MarkdownView) { - this.workspaceContext.trackViewSelection(view); - } - this.scheduleContextRefresh(200); - } - ); - this.contextEventRefs = [ - activeLeafRef, - fileOpenRef, - fileCloseRef, - layoutChangeRef, - editorChangeRef, - selectionChangeRef - ]; - this.contextEventRefs.forEach((ref) => this.registerEvent(ref)); - } - clearContextListeners() { - for (const ref of this.contextEventRefs) { - this.app.workspace.offref(ref); - } - this.contextEventRefs = []; - if (this.contextRefreshTimer !== null) { - window.clearTimeout(this.contextRefreshTimer); - this.contextRefreshTimer = null; - } - } - scheduleContextRefresh(delayMs = 300) { - const leaf = this.getOpenCodeLeafForRefresh(); - if (!leaf) { - return; - } - if (this.contextRefreshTimer !== null) { - window.clearTimeout(this.contextRefreshTimer); - } - this.contextRefreshTimer = window.setTimeout(() => { - this.contextRefreshTimer = null; - void this.updateOpenCodeContext(leaf); - }, delayMs); - } - getOpenCodeLeafForRefresh() { - const activeLeaf = this.app.workspace.activeLeaf; - if ((activeLeaf == null ? void 0 : activeLeaf.view.getViewType()) === OPENCODE_VIEW_TYPE) { - return activeLeaf; - } - return this.getVisibleSidebarOpenCodeLeaf(); - } - getVisibleSidebarOpenCodeLeaf() { - const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE); - if (leaves.length === 0) { - return null; - } - const rightSplit = this.app.workspace.rightSplit; - if (!rightSplit || rightSplit.collapsed) { - return null; - } - const leaf = leaves[0]; - return leaf.getRoot() === rightSplit ? leaf : null; - } - async handleServerRunning() { - const activeLeaf = this.app.workspace.activeLeaf; - if ((activeLeaf == null ? void 0 : activeLeaf.view.getViewType()) === OPENCODE_VIEW_TYPE) { - await this.updateOpenCodeContext(activeLeaf); - } - } - async updateOpenCodeContext(leaf) { - var _a; - if (!this.settings.injectWorkspaceContext) { - return; - } - if (this.getProcessState() !== "running") { - return; - } - const view = leaf.view instanceof OpenCodeView ? leaf.view : null; - const iframeUrl = (_a = this.cachedIframeUrl) != null ? _a : view == null ? void 0 : view.getIframeUrl(); - if (!iframeUrl) { - return; - } - const sessionId = this.openCodeClient.resolveSessionId(iframeUrl); - if (!sessionId) { - return; - } - this.cachedIframeUrl = iframeUrl; - const { contextText } = this.workspaceContext.gatherContext( - this.settings.maxNotesInContext, - this.settings.maxSelectionLength - ); - await this.openCodeClient.updateContext({ - sessionId, - contextText - }); - } - 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; - } -};