summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop-electron/src/preload
diff options
context:
space:
mode:
authorBrendan Allan <[email protected]>2026-03-04 15:12:34 +0800
committerGitHub <[email protected]>2026-03-04 15:12:34 +0800
commit5cf235fa6cf7b4c890c68f8ff68a96fcae992abf (patch)
tree25fdfd8ce95ad048fb097822995dcf060e8d6d8b /packages/desktop-electron/src/preload
parente4f0825c56300286ec0aa82b1006e4006a17e1e1 (diff)
downloadopencode-5cf235fa6cf7b4c890c68f8ff68a96fcae992abf.tar.gz
opencode-5cf235fa6cf7b4c890c68f8ff68a96fcae992abf.zip
desktop: add electron version (#15663)
Diffstat (limited to 'packages/desktop-electron/src/preload')
-rw-r--r--packages/desktop-electron/src/preload/index.ts66
-rw-r--r--packages/desktop-electron/src/preload/types.ts64
2 files changed, 130 insertions, 0 deletions
diff --git a/packages/desktop-electron/src/preload/index.ts b/packages/desktop-electron/src/preload/index.ts
new file mode 100644
index 000000000..a6520ab42
--- /dev/null
+++ b/packages/desktop-electron/src/preload/index.ts
@@ -0,0 +1,66 @@
+import { contextBridge, ipcRenderer } from "electron"
+import type { ElectronAPI, InitStep, SqliteMigrationProgress } from "./types"
+
+const api: ElectronAPI = {
+ killSidecar: () => ipcRenderer.invoke("kill-sidecar"),
+ installCli: () => ipcRenderer.invoke("install-cli"),
+ awaitInitialization: (onStep) => {
+ const handler = (_: unknown, step: InitStep) => onStep(step)
+ ipcRenderer.on("init-step", handler)
+ return ipcRenderer.invoke("await-initialization").finally(() => {
+ ipcRenderer.removeListener("init-step", handler)
+ })
+ },
+ getDefaultServerUrl: () => ipcRenderer.invoke("get-default-server-url"),
+ setDefaultServerUrl: (url) => ipcRenderer.invoke("set-default-server-url", url),
+ getWslConfig: () => ipcRenderer.invoke("get-wsl-config"),
+ setWslConfig: (config) => ipcRenderer.invoke("set-wsl-config", config),
+ getDisplayBackend: () => ipcRenderer.invoke("get-display-backend"),
+ setDisplayBackend: (backend) => ipcRenderer.invoke("set-display-backend", backend),
+ parseMarkdownCommand: (markdown) => ipcRenderer.invoke("parse-markdown", markdown),
+ checkAppExists: (appName) => ipcRenderer.invoke("check-app-exists", appName),
+ wslPath: (path, mode) => ipcRenderer.invoke("wsl-path", path, mode),
+ resolveAppPath: (appName) => ipcRenderer.invoke("resolve-app-path", appName),
+ storeGet: (name, key) => ipcRenderer.invoke("store-get", name, key),
+ storeSet: (name, key, value) => ipcRenderer.invoke("store-set", name, key, value),
+ storeDelete: (name, key) => ipcRenderer.invoke("store-delete", name, key),
+ storeClear: (name) => ipcRenderer.invoke("store-clear", name),
+ storeKeys: (name) => ipcRenderer.invoke("store-keys", name),
+ storeLength: (name) => ipcRenderer.invoke("store-length", name),
+
+ onSqliteMigrationProgress: (cb) => {
+ const handler = (_: unknown, progress: SqliteMigrationProgress) => cb(progress)
+ ipcRenderer.on("sqlite-migration-progress", handler)
+ return () => ipcRenderer.removeListener("sqlite-migration-progress", handler)
+ },
+ onMenuCommand: (cb) => {
+ const handler = (_: unknown, id: string) => cb(id)
+ ipcRenderer.on("menu-command", handler)
+ return () => ipcRenderer.removeListener("menu-command", handler)
+ },
+ onDeepLink: (cb) => {
+ const handler = (_: unknown, urls: string[]) => cb(urls)
+ ipcRenderer.on("deep-link", handler)
+ return () => ipcRenderer.removeListener("deep-link", handler)
+ },
+
+ openDirectoryPicker: (opts) => ipcRenderer.invoke("open-directory-picker", opts),
+ openFilePicker: (opts) => ipcRenderer.invoke("open-file-picker", opts),
+ saveFilePicker: (opts) => ipcRenderer.invoke("save-file-picker", opts),
+ openLink: (url) => ipcRenderer.send("open-link", url),
+ openPath: (path, app) => ipcRenderer.invoke("open-path", path, app),
+ readClipboardImage: () => ipcRenderer.invoke("read-clipboard-image"),
+ showNotification: (title, body) => ipcRenderer.send("show-notification", title, body),
+ getWindowFocused: () => ipcRenderer.invoke("get-window-focused"),
+ setWindowFocus: () => ipcRenderer.invoke("set-window-focus"),
+ showWindow: () => ipcRenderer.invoke("show-window"),
+ relaunch: () => ipcRenderer.send("relaunch"),
+ getZoomFactor: () => ipcRenderer.invoke("get-zoom-factor"),
+ setZoomFactor: (factor) => ipcRenderer.invoke("set-zoom-factor", factor),
+ loadingWindowComplete: () => ipcRenderer.send("loading-window-complete"),
+ runUpdater: (alertOnFail) => ipcRenderer.invoke("run-updater", alertOnFail),
+ checkUpdate: () => ipcRenderer.invoke("check-update"),
+ installUpdate: () => ipcRenderer.invoke("install-update"),
+}
+
+contextBridge.exposeInMainWorld("api", api)
diff --git a/packages/desktop-electron/src/preload/types.ts b/packages/desktop-electron/src/preload/types.ts
new file mode 100644
index 000000000..af5410f5f
--- /dev/null
+++ b/packages/desktop-electron/src/preload/types.ts
@@ -0,0 +1,64 @@
+export type InitStep = { phase: "server_waiting" } | { phase: "sqlite_waiting" } | { phase: "done" }
+
+export type ServerReadyData = {
+ url: string
+ password: string | null
+}
+
+export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" }
+
+export type WslConfig = { enabled: boolean }
+
+export type LinuxDisplayBackend = "wayland" | "auto"
+
+export type ElectronAPI = {
+ killSidecar: () => Promise<void>
+ installCli: () => Promise<string>
+ awaitInitialization: (onStep: (step: InitStep) => void) => Promise<ServerReadyData>
+ getDefaultServerUrl: () => Promise<string | null>
+ setDefaultServerUrl: (url: string | null) => Promise<void>
+ getWslConfig: () => Promise<WslConfig>
+ setWslConfig: (config: WslConfig) => Promise<void>
+ getDisplayBackend: () => Promise<LinuxDisplayBackend | null>
+ setDisplayBackend: (backend: LinuxDisplayBackend | null) => Promise<void>
+ parseMarkdownCommand: (markdown: string) => Promise<string>
+ checkAppExists: (appName: string) => Promise<boolean>
+ wslPath: (path: string, mode: "windows" | "linux" | null) => Promise<string>
+ resolveAppPath: (appName: string) => Promise<string | null>
+ storeGet: (name: string, key: string) => Promise<string | null>
+ storeSet: (name: string, key: string, value: string) => Promise<void>
+ storeDelete: (name: string, key: string) => Promise<void>
+ storeClear: (name: string) => Promise<void>
+ storeKeys: (name: string) => Promise<string[]>
+ storeLength: (name: string) => Promise<number>
+
+ onSqliteMigrationProgress: (cb: (progress: SqliteMigrationProgress) => void) => () => void
+ onMenuCommand: (cb: (id: string) => void) => () => void
+ onDeepLink: (cb: (urls: string[]) => void) => () => void
+
+ openDirectoryPicker: (opts?: {
+ multiple?: boolean
+ title?: string
+ defaultPath?: string
+ }) => Promise<string | string[] | null>
+ openFilePicker: (opts?: {
+ multiple?: boolean
+ title?: string
+ defaultPath?: string
+ }) => Promise<string | string[] | null>
+ saveFilePicker: (opts?: { title?: string; defaultPath?: string }) => Promise<string | null>
+ openLink: (url: string) => void
+ openPath: (path: string, app?: string) => Promise<void>
+ readClipboardImage: () => Promise<{ buffer: ArrayBuffer; width: number; height: number } | null>
+ showNotification: (title: string, body?: string) => void
+ getWindowFocused: () => Promise<boolean>
+ setWindowFocus: () => Promise<void>
+ showWindow: () => Promise<void>
+ relaunch: () => void
+ getZoomFactor: () => Promise<number>
+ setZoomFactor: (factor: number) => Promise<void>
+ loadingWindowComplete: () => void
+ runUpdater: (alertOnFail: boolean) => Promise<void>
+ checkUpdate: () => Promise<{ updateAvailable: boolean; version?: string }>
+ installUpdate: () => Promise<void>
+}