feat(desktop): Linux AppImage releases and desktop feature parity (#2398)
* feat(electron): add Linux AppImage releases * ci: cache Linux OpenCode CLI artifacts * fix(ci): await Linux release inventory check * fix(electron): add frameless window controls on Linux desktop Linux AppImages were created without native WM decorations and without in-app controls, leaving users unable to close the window with a mouse. Treat Linux like Windows: frameless BrowserWindow plus the existing WindowsWindowControls header buttons and app-menu entry. macOS keeps hidden title bar with traffic lights unchanged. Shared usesFramelessElectronChrome() helper drives main window, mini chat, header insets, and titlebar controls. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Linux desktop feature parity: Open in, background start, tray, multi-window (#2392) * feat(electron): Linux parity for Open in, background start, and tray Enable Linux desktop feature parity with macOS/Windows: open projects in the default file manager and discovered apps, XDG autostart with --background launches, system tray (including minimize-to-tray), and tray sync from the renderer. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * fix(electron): allow packaged UI protocol navigations on Linux Prevent openchamber-ui:// navigations from being handed to shell.openExternal, which fails on Linux and blocked desktop UI flows. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * fix(ui): surface Linux tray settings in settings search Include isLinux in settings search runtime context so minimize-to-tray is discoverable on Linux desktop, matching Windows search behavior. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * fix(electron): stop Linux AppImage Waiting-for-OpenCode flicker Sync updated boot-outcome init scripts to all BrowserWindows after desktop_hosts_set, and prefer state.initScript on dom-ready so chooser reloads inject local/ok instead of a stale not-configured outcome. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * fix(desktop): restore Linux AppImage updater feed and error UX (#2396) Treat missing latest-linux*.yml (404) as no update available instead of a hard failure, and stop swallowing updater capability/download errors in the desktop bridge so About/sidebar can show actionable messages. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * docs: credit Linux AppImage contributors in changelog Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> --------- Co-authored-by: jibanez-staticduo <staticduo@gmail.com> Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Cursor Agent
Serhii Dziupin
jibanez-staticduo
parent
ddbb3c1db0
commit
18b58bdb6b
@@ -274,6 +274,10 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
return isDesktopShell() && typeof window !== 'undefined'
|
||||
&& (window as unknown as { __OPENCHAMBER_PLATFORM__?: string }).__OPENCHAMBER_PLATFORM__ === 'win32';
|
||||
}, []);
|
||||
const isLinux = React.useMemo(() => {
|
||||
return isDesktopShell() && typeof window !== 'undefined'
|
||||
&& (window as unknown as { __OPENCHAMBER_PLATFORM__?: string }).__OPENCHAMBER_PLATFORM__ === 'linux';
|
||||
}, []);
|
||||
|
||||
// keep platform check available for future window chrome tweaks
|
||||
|
||||
@@ -417,12 +421,12 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
const settingsSearchResults = React.useMemo(() => {
|
||||
return buildSettingsSearchResults({
|
||||
query: settingsSearchQuery,
|
||||
runtimeCtx: { ...runtimeCtx, isDesktopLocalOrigin, isMac, isWindows },
|
||||
runtimeCtx: { ...runtimeCtx, isDesktopLocalOrigin, isMac, isWindows, isLinux },
|
||||
visiblePageSlugs,
|
||||
t,
|
||||
getPageTitle,
|
||||
});
|
||||
}, [getPageTitle, isDesktopLocalOrigin, isMac, isWindows, runtimeCtx, settingsSearchQuery, t, visiblePageSlugs]);
|
||||
}, [getPageTitle, isDesktopLocalOrigin, isMac, isWindows, isLinux, runtimeCtx, settingsSearchQuery, t, visiblePageSlugs]);
|
||||
|
||||
const prepareSettingsSearchTarget = React.useCallback((result: SettingsSearchResult): string => {
|
||||
if (result.id.startsWith('agents.')) {
|
||||
|
||||
@@ -104,7 +104,7 @@ type DesktopBridgeGlobal = {
|
||||
const isTrayPlatform = (): boolean => {
|
||||
if (typeof window === 'undefined') return false;
|
||||
const platform = (window as unknown as { __OPENCHAMBER_PLATFORM__?: string }).__OPENCHAMBER_PLATFORM__;
|
||||
return platform === 'darwin' || platform === 'win32';
|
||||
return platform === 'darwin' || platform === 'win32' || platform === 'linux';
|
||||
};
|
||||
|
||||
const isTrayEnabled = (): boolean =>
|
||||
|
||||
@@ -661,6 +661,9 @@ export const checkForDesktopUpdates = async (): Promise<UpdateInfo | null> => {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Propagate updater capability / feed errors so the UI can show actionable
|
||||
// messages (missing AppImage, read-only path, network failure). Missing
|
||||
// latest-linux*.yml is already normalized to available:false in main.
|
||||
const info = await invokeDesktop<UpdateInfo>('desktop_check_for_updates');
|
||||
return info as UpdateInfo;
|
||||
};
|
||||
|
||||
@@ -954,7 +954,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': 'Requires an app restart. When off, OpenChamber does not create the menu bar item or run its session, approval, and usage updates.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': 'Minimize and close OpenChamber to the system tray',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': 'Minimize and close to the system tray',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Keeps OpenChamber running in the Windows system tray when the main window is minimized or closed.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Keeps OpenChamber running in the system tray when the main window is minimized or closed.',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'Keep computer awake while OpenChamber is running',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'Keep computer awake while OpenChamber is running',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': 'Prevents system sleep so phones can keep reaching this app. The screen can still turn off.',
|
||||
|
||||
@@ -921,7 +921,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.desktopNetwork.field.macMenuBarDescription": "Requiere reiniciar la aplicación. Al desactivarlo, OpenChamber no crea el elemento de la barra de menús ni ejecuta sus actualizaciones de sesiones, aprobaciones y uso.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayAria": "Minimizar y cerrar OpenChamber a la bandeja del sistema",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTray": "Minimizar y cerrar a la bandeja del sistema",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Mantiene OpenChamber en ejecución en la bandeja del sistema de Windows cuando la ventana principal se minimiza o se cierra.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Mantiene OpenChamber en ejecución en la bandeja del sistema cuando la ventana principal se minimiza o se cierra.",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeAria": "Mantener el ordenador activo mientras OpenChamber está en ejecución",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwake": "Mantener el ordenador activo mientras OpenChamber está en ejecución",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeDescription": "Para que los teléfonos puedan seguir abriendo esta app. La pantalla aún puede apagarse.",
|
||||
|
||||
@@ -842,7 +842,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': 'Nécessite un redémarrage de l\'application. Lorsque cette option est désactivée, OpenChamber ne crée pas l\'élément de barre des menus et n\'exécute pas ses mises à jour de sessions, d\'approbations et d\'utilisation.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': 'Réduire et fermer OpenChamber dans la zone de notification',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': 'Réduire et fermer dans la zone de notification',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Garde OpenChamber actif dans la zone de notification Windows lorsque la fenêtre principale est réduite ou fermée.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Garde OpenChamber actif dans la zone de notification lorsque la fenêtre principale est réduite ou fermée.',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'Garder l\'ordinateur éveillé pendant qu\'OpenChamber fonctionne',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'Garder l\'ordinateur éveillé pendant qu\'OpenChamber fonctionne',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': 'Pour que les téléphones puissent continuer à ouvrir cette application. L\'écran peut toujours s\'éteindre.',
|
||||
|
||||
@@ -954,7 +954,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': 'アプリの再起動が必要です。オフにすると、OpenChamber はメニューバー項目を作成せず、セッション、承認、使用量の更新も実行しません。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': 'OpenChamber をシステムトレイへ最小化または閉じる',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': 'システムトレイへ最小化または閉じる',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'メインウィンドウを最小化または閉じたときも、OpenChamber を Windows のシステムトレイで実行し続けます。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'メインウィンドウを最小化または閉じたときも、OpenChamber をシステムトレイで実行し続けます。',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'OpenChamber の実行中はコンピューターのスリープを防止',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'OpenChamber の実行中はコンピューターのスリープを防止',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': 'スマートフォンがこのアプリを開き続けられるようにします。ディスプレイはオフにできます。',
|
||||
|
||||
@@ -921,7 +921,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': '앱을 다시 시작해야 합니다. 끄면 OpenChamber가 메뉴 막대 항목을 만들지 않으며 세션, 승인 및 사용량 업데이트도 실행하지 않습니다.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': 'OpenChamber를 시스템 트레이로 최소화하거나 닫기',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': '시스템 트레이로 최소화하고 닫기',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '메인 창을 최소화하거나 닫아도 OpenChamber가 Windows 시스템 트레이에서 계속 실행됩니다.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '메인 창을 최소화하거나 닫아도 OpenChamber가 시스템 트레이에서 계속 실행됩니다.',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'OpenChamber가 실행되는 동안 컴퓨터 절전 방지',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'OpenChamber가 실행되는 동안 컴퓨터 절전 방지',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': '휴대폰이 이 앱을 계속 열 수 있도록 합니다. 디스플레이는 꺼질 수 있습니다.',
|
||||
|
||||
@@ -761,7 +761,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': 'Wymaga ponownego uruchomienia aplikacji. Po wyłączeniu OpenChamber nie tworzy elementu paska menu ani nie uruchamia aktualizacji sesji, zatwierdzeń i użycia.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': 'Minimalizuj i zamykaj OpenChamber do zasobnika systemowego',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': 'Minimalizuj i zamykaj do zasobnika systemowego',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Utrzymuje OpenChamber w zasobniku systemowym Windows, gdy główne okno jest zminimalizowane lub zamknięte.',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': 'Utrzymuje OpenChamber w zasobniku systemowym, gdy główne okno jest zminimalizowane lub zamknięte.',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'Utrzymuj komputer aktywny, gdy OpenChamber jest uruchomiony',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'Utrzymuj komputer aktywny, gdy OpenChamber jest uruchomiony',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': 'Aby telefony nadal mogły otwierać tę aplikację. Ekran nadal może się wyłączyć.',
|
||||
|
||||
@@ -921,7 +921,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.desktopNetwork.field.macMenuBarDescription": "Exige reiniciar o aplicativo. Quando desativado, o OpenChamber não cria o item da barra de menus nem executa as atualizações de sessões, aprovações e uso.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayAria": "Minimizar e fechar o OpenChamber na bandeja do sistema",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTray": "Minimizar e fechar na bandeja do sistema",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Mantém o OpenChamber em execução na bandeja do sistema do Windows quando a janela principal é minimizada ou fechada.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Mantém o OpenChamber em execução na bandeja do sistema quando a janela principal é minimizada ou fechada.",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeAria": "Manter o computador ativo enquanto o OpenChamber estiver em execução",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwake": "Manter o computador ativo enquanto o OpenChamber estiver em execução",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeDescription": "Para que telefones continuem abrindo este app. A tela ainda pode desligar.",
|
||||
|
||||
@@ -921,7 +921,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.desktopNetwork.field.macMenuBarDescription": "Потребує перезапуску застосунку. Якщо вимкнено, OpenChamber не створює елемент смуги меню та не запускає пов’язані оновлення сесій, запитів на підтвердження й використання.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayAria": "Згортати й закривати OpenChamber у системний трей",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTray": "Згортати й закривати в системний трей",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Залишає OpenChamber запущеним у системному треї Windows, коли головне вікно згорнуто або закрито.",
|
||||
"settings.openchamber.desktopNetwork.field.minimizeToTrayDescription": "Залишає OpenChamber запущеним у системному треї, коли головне вікно згорнуто або закрито.",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeAria": "Не давати комп’ютеру засинати, поки OpenChamber запущено",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwake": "Не давати комп’ютеру засинати, поки OpenChamber запущено",
|
||||
"settings.openchamber.desktopNetwork.field.keepAwakeDescription": "Щоб телефон і далі міг відкривати застосунок. Екран усе одно може вимикатися.",
|
||||
|
||||
@@ -921,7 +921,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': '需要重启应用。关闭后,OpenChamber 不会创建菜单栏项目,也不会运行相关的会话、审批和用量更新。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': '将 OpenChamber 最小化和关闭到系统托盘',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': '最小化和关闭到系统托盘',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '主窗口最小化或关闭时,让 OpenChamber 继续在 Windows 系统托盘中运行。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '主窗口最小化或关闭时,让 OpenChamber 继续在系统托盘中运行。',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'OpenChamber 运行时保持电脑唤醒',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'OpenChamber 运行时保持电脑唤醒',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': '让手机可以继续打开此应用。屏幕仍可关闭。',
|
||||
|
||||
@@ -1933,7 +1933,7 @@
|
||||
'settings.openchamber.desktopNetwork.field.macMenuBarDescription': '需要重新啟動應用程式。關閉後,OpenChamber 不會建立選單列項目,也不會執行相關的工作階段、核准與用量更新。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayAria': '將 OpenChamber 最小化和關閉到系統匣',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTray': '最小化和關閉到系統匣',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '主視窗最小化或關閉時,讓 OpenChamber 繼續在 Windows 系統匣中執行。',
|
||||
'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription': '主視窗最小化或關閉時,讓 OpenChamber 繼續在系統匣中執行。',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeAria': 'OpenChamber 執行時保持電腦喚醒',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwake': 'OpenChamber 執行時保持電腦喚醒',
|
||||
'settings.openchamber.desktopNetwork.field.keepAwakeDescription': '讓手機可以持續開啟此應用程式。螢幕仍可關閉。',
|
||||
|
||||
@@ -35,10 +35,18 @@ export const DEFAULT_OPEN_IN_APP_ID = 'finder';
|
||||
export const OPEN_IN_ALWAYS_AVAILABLE_APP_IDS = new Set(['finder', 'terminal']);
|
||||
|
||||
export const getPlatformOpenInApp = (app: OpenInApp): OpenInApp => {
|
||||
if (typeof window !== 'undefined' && window.__OPENCHAMBER_PLATFORM__ === 'win32') {
|
||||
if (app.id === 'finder') {
|
||||
if (typeof window === 'undefined') {
|
||||
return app;
|
||||
}
|
||||
|
||||
const platform = window.__OPENCHAMBER_PLATFORM__;
|
||||
if (app.id === 'finder') {
|
||||
if (platform === 'win32') {
|
||||
return { ...app, label: 'Explorer', appName: 'File Explorer' };
|
||||
}
|
||||
if (platform === 'linux') {
|
||||
return { ...app, label: 'File Manager' };
|
||||
}
|
||||
}
|
||||
return app;
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ interface SettingsSearchAvailabilityContext extends SettingsRuntimeContext {
|
||||
isMac: boolean;
|
||||
// Windows desktop shell — for controls that only render on win32.
|
||||
isWindows: boolean;
|
||||
// Linux desktop shell — for controls that only render on linux.
|
||||
isLinux: boolean;
|
||||
}
|
||||
|
||||
const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
|
||||
@@ -385,7 +387,7 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
|
||||
page: 'general',
|
||||
titleKey: 'settings.openchamber.desktopNetwork.field.launchAtLogin',
|
||||
descriptionKey: 'settings.openchamber.desktopNetwork.field.launchAtLoginDescription',
|
||||
keywords: ['desktop', 'startup', 'login'],
|
||||
keywords: ['desktop', 'startup', 'login', 'launch', 'background', 'autostart'],
|
||||
isAvailable: (ctx) => ctx.isDesktopLocalOrigin,
|
||||
},
|
||||
{
|
||||
@@ -409,8 +411,8 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
|
||||
page: 'general',
|
||||
titleKey: 'settings.openchamber.desktopNetwork.field.minimizeToTray',
|
||||
descriptionKey: 'settings.openchamber.desktopNetwork.field.minimizeToTrayDescription',
|
||||
keywords: ['desktop', 'tray', 'system tray', 'minimize', 'close', 'background', 'windows'],
|
||||
isAvailable: (ctx) => ctx.isDesktopLocalOrigin && ctx.isWindows,
|
||||
keywords: ['desktop', 'tray', 'system tray', 'minimize', 'close', 'background', 'windows', 'linux'],
|
||||
isAvailable: (ctx) => ctx.isDesktopLocalOrigin && (ctx.isWindows || ctx.isLinux),
|
||||
},
|
||||
{
|
||||
id: 'sessions.desktop-keep-awake',
|
||||
|
||||
Reference in New Issue
Block a user