diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index db057a4c41f..6f836dfca8d 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -450,6 +450,27 @@ export const SettingsGeneral: Component = () => { ) }} + + {/* Desktop Section - Desktop only */} + +
+

{language.t("settings.general.section.desktop")}

+ +
+ +
+ settings.browser.setOpenLinksExternally(checked)} + /> +
+
+
+
+
) @@ -463,8 +484,8 @@ interface SettingsRowProps { const SettingsRow: Component = (props) => { return ( -
-
+
+
{props.title} {props.description}
diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx index 19b3846f84e..35cbf29d620 100644 --- a/packages/app/src/context/settings.tsx +++ b/packages/app/src/context/settings.tsx @@ -15,6 +15,10 @@ export interface SoundSettings { errors: string } +export interface BrowserSettings { + openLinksExternally: boolean +} + export interface Settings { general: { autoSave: boolean @@ -33,6 +37,7 @@ export interface Settings { } notifications: NotificationSettings sounds: SoundSettings + browser: BrowserSettings } const defaultSettings: Settings = { @@ -61,6 +66,9 @@ const defaultSettings: Settings = { permissions: "staplebops-02", errors: "nope-03", }, + browser: { + openLinksExternally: true, + }, } const monoFallback = @@ -172,6 +180,14 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont setStore("sounds", "errors", value) }, }, + browser: { + openLinksExternally: createMemo( + () => store.browser?.openLinksExternally ?? defaultSettings.browser.openLinksExternally, + ), + setOpenLinksExternally(value: boolean) { + setStore("browser", "openLinksExternally", value) + }, + }, } }, }) diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 201d63660a3..41c0739f98b 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -513,6 +513,10 @@ export const dict = { "settings.general.section.notifications": "إشعارات النظام", "settings.general.section.updates": "التحديثات", "settings.general.section.sounds": "المؤثرات الصوتية", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "فتح الروابط في متصفح خارجي", + "settings.general.desktop.openLinksExternally.description": + "عند التفعيل، سيتم فتح الروابط في متصفح النظام الافتراضي بدلاً من داخل التطبيق", "settings.general.row.language.title": "اللغة", "settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index b7f2d74857f..6f9ec25e6be 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -517,6 +517,10 @@ export const dict = { "settings.general.section.notifications": "Notificações do sistema", "settings.general.section.updates": "Atualizações", "settings.general.section.sounds": "Efeitos sonoros", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Abrir links no navegador externo", + "settings.general.desktop.openLinksExternally.description": + "Quando ativado, clicar em links os abrirá no navegador padrão do sistema em vez de dentro do app", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 8ea4907c1b6..5e3b95ff5d9 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -517,6 +517,10 @@ export const dict = { "settings.general.section.notifications": "Systemmeddelelser", "settings.general.section.updates": "Opdateringer", "settings.general.section.sounds": "Lydeffekter", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Åbn links i ekstern browser", + "settings.general.desktop.openLinksExternally.description": + "Når aktiveret, åbnes links i din standard systembrowser i stedet for i appen", "settings.general.row.language.title": "Sprog", "settings.general.row.language.description": "Ændr visningssproget for OpenCode", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index a4884a1033d..ceeb419d664 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -561,6 +561,10 @@ export const dict = { "settings.general.section.notifications": "Systembenachrichtigungen", "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Soundeffekte", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Links im externen Browser öffnen", + "settings.general.desktop.openLinksExternally.description": + "Wenn aktiviert, werden Links in Ihrem Standard-Systembrowser geöffnet anstatt innerhalb der App", "settings.general.row.language.title": "Sprache", "settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index b0ffa70f84d..b9164641ffd 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -589,6 +589,10 @@ export const dict = { "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Sound effects", "settings.general.section.display": "Display", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Open links in external browser", + "settings.general.desktop.openLinksExternally.description": + "When enabled, clicking links will open them in your default system browser instead of within the app", "settings.general.row.language.title": "Language", "settings.general.row.language.description": "Change the display language for OpenCode", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 50d9060703e..fabbc755556 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -520,6 +520,10 @@ export const dict = { "settings.general.section.notifications": "Notificaciones del sistema", "settings.general.section.updates": "Actualizaciones", "settings.general.section.sounds": "Efectos de sonido", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Abrir enlaces en navegador externo", + "settings.general.desktop.openLinksExternally.description": + "Al activarse, los enlaces se abrirán en el navegador predeterminado del sistema en lugar de dentro de la app", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 7ad39f34063..6d0e0d03080 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -527,6 +527,10 @@ export const dict = { "settings.general.section.notifications": "Notifications système", "settings.general.section.updates": "Mises à jour", "settings.general.section.sounds": "Effets sonores", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Ouvrir les liens dans un navigateur externe", + "settings.general.desktop.openLinksExternally.description": + "Lorsqu'activé, les liens s'ouvriront dans votre navigateur système par défaut au lieu de l'application", "settings.general.row.language.title": "Langue", "settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index a39bfbaf331..d1a023bdc5e 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -512,6 +512,10 @@ export const dict = { "settings.general.section.notifications": "システム通知", "settings.general.section.updates": "アップデート", "settings.general.section.sounds": "効果音", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "外部ブラウザでリンクを開く", + "settings.general.desktop.openLinksExternally.description": + "有効にすると、リンクをクリックするとアプリ内ではなくシステムの既定ブラウザで開きます", "settings.general.row.language.title": "言語", "settings.general.row.language.description": "OpenCodeの表示言語を変更します", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index b5927b21076..5d0796d71be 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -518,6 +518,10 @@ export const dict = { "settings.general.section.notifications": "시스템 알림", "settings.general.section.updates": "업데이트", "settings.general.section.sounds": "효과음", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "외부 브라우저에서 링크 열기", + "settings.general.desktop.openLinksExternally.description": + "활성화하면 링크를 클릭할 때 앱 내부가 아닌 기본 시스템 브라우저에서 열립니다", "settings.general.row.language.title": "언어", "settings.general.row.language.description": "OpenCode 표시 언어 변경", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 7d8cdd27f3d..a62a91cdd4c 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -520,6 +520,10 @@ export const dict = { "settings.general.section.notifications": "Systemvarsler", "settings.general.section.updates": "Oppdateringer", "settings.general.section.sounds": "Lydeffekter", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Åpne lenker i ekstern nettleser", + "settings.general.desktop.openLinksExternally.description": + "Når aktivert, åpnes lenker i standard systemnettleseren i stedet for i appen", "settings.general.row.language.title": "Språk", "settings.general.row.language.description": "Endre visningsspråket for OpenCode", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 76a47ea26f8..ef748cfaa86 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -519,6 +519,10 @@ export const dict = { "settings.general.section.notifications": "Powiadomienia systemowe", "settings.general.section.updates": "Aktualizacje", "settings.general.section.sounds": "Efekty dźwiękowe", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Otwieraj linki w zewnętrznej przeglądarce", + "settings.general.desktop.openLinksExternally.description": + "Po włączeniu linki będą otwierane w domyślnej przeglądarce systemowej zamiast w aplikacji", "settings.general.row.language.title": "Język", "settings.general.row.language.description": "Zmień język wyświetlania dla OpenCode", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index e83ce37618c..cf019926508 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -522,6 +522,10 @@ export const dict = { "settings.general.section.notifications": "Системные уведомления", "settings.general.section.updates": "Обновления", "settings.general.section.sounds": "Звуковые эффекты", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Открывать ссылки во внешнем браузере", + "settings.general.desktop.openLinksExternally.description": + "При включении ссылки будут открываться в системном браузере по умолчанию, а не внутри приложения", "settings.general.row.language.title": "Язык", "settings.general.row.language.description": "Изменить язык отображения OpenCode", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 2be19d15b17..31248581348 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -521,6 +521,10 @@ export const dict = { "settings.general.section.notifications": "การแจ้งเตือนระบบ", "settings.general.section.updates": "การอัปเดต", "settings.general.section.sounds": "เสียงเอฟเฟกต์", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "เปิดลิงก์ในเบราว์เซอร์ภายนอก", + "settings.general.desktop.openLinksExternally.description": + "เมื่อเปิดใช้งาน การคลิกลิงก์จะเปิดในเบราว์เซอร์เริ่มต้นของระบบแทนที่จะเปิดในแอป", "settings.general.row.language.title": "ภาษา", "settings.general.row.language.description": "เปลี่ยนภาษาที่แสดงสำหรับ OpenCode", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index a48f9e54941..40aee32881d 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -553,6 +553,10 @@ export const dict = { "settings.general.section.notifications": "系统通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "在外部浏览器中打开链接", + "settings.general.desktop.openLinksExternally.description": + "启用后,点击链接将在系统默认浏览器中打开,而不是在应用内打开", "settings.general.row.language.title": "语言", "settings.general.row.language.description": "更改 OpenCode 的显示语言", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 60363fc99ef..a61e3683e03 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -550,6 +550,10 @@ export const dict = { "settings.general.section.notifications": "系統通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "在外部瀏覽器中開啟連結", + "settings.general.desktop.openLinksExternally.description": + "啟用後,點擊連結將在系統預設瀏覽器中開啟,而非在應用程式內開啟", "settings.general.row.language.title": "語言", "settings.general.row.language.description": "變更 OpenCode 的顯示語言", diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index 25e9f825c70..6a4b45ee1d9 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -59,6 +59,24 @@ const listenForDeepLinks = async () => { await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined) } +// Settings key for reading browser preferences +const SETTINGS_KEY = "settings.v3" + +// Read browser settings from store to check if links should open externally +async function shouldOpenLinksExternally(): Promise { + try { + const store = await Store.load("opencode.global.dat") + const settings = await store.get(SETTINGS_KEY) + if (settings && typeof settings === "object" && "browser" in (settings as object)) { + const browser = (settings as { browser?: { openLinksExternally?: boolean } }).browser + return browser?.openLinksExternally !== false // Default to true + } + } catch { + // Ignore errors, default to true + } + return true // Default: open links externally +} + const createPlatform = (password: Accessor): Platform => ({ platform: "desktop", os: (() => { @@ -398,11 +416,26 @@ render(() => { const platform = createPlatform(() => serverPassword()) function handleClick(e: MouseEvent) { - const link = (e.target as HTMLElement).closest("a.external-link") as HTMLAnchorElement | null - if (link?.href) { - e.preventDefault() - platform.openLink(link.href) - } + const link = (e.target as HTMLElement).closest("a") as HTMLAnchorElement | null + if (!link?.href) return + + // Check if it's an external link (http/https) + const isExternal = link.href.startsWith("http://") || link.href.startsWith("https://") + if (!isExternal) return + + // MUST preventDefault immediately (before any async), otherwise browser handles it + e.preventDefault() + const url = link.href + + // Check user preference and handle accordingly + shouldOpenLinksExternally().then((openExternally) => { + if (openExternally) { + platform.openLink(url) + } else { + // Open in app by navigating + window.location.href = url + } + }) } onMount(() => { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index d7f73b4f609..4491edd38a4 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -319,7 +319,7 @@ export namespace SessionPrompt { modelID: lastUser.model.modelID, providerID: lastUser.model.providerID, history: msgs, - }) + }).catch(() => {}) const model = await Provider.getModel(lastUser.model.providerID, lastUser.model.modelID).catch((e) => { if (Provider.ModelNotFoundError.isInstance(e)) {