diff --git a/packages/electron/main.mjs b/packages/electron/main.mjs index abfd9e52..963168b3 100644 --- a/packages/electron/main.mjs +++ b/packages/electron/main.mjs @@ -2414,7 +2414,7 @@ const buildMacMenu = () => { { label: app.name, submenu: [ - { role: 'about' }, + { label: 'About OpenChamber', click: () => dispatchAction('about') }, { label: 'Check for Updates', click: () => dispatchCheckForUpdates(), @@ -2461,10 +2461,12 @@ const buildMacMenu = () => { { label: 'View', submenu: [ - { label: 'Git', accelerator: 'Cmd+G', click: () => dispatchAction('open-git-tab') }, - { label: 'Diff', accelerator: 'Cmd+E', click: () => dispatchAction('open-diff-tab') }, - { label: 'Files', click: () => dispatchAction('open-files-tab') }, - { label: 'Terminal', accelerator: 'Cmd+T', click: () => dispatchAction('open-terminal-tab') }, + { label: 'Toggle Right Sidebar', accelerator: 'Cmd+B', click: () => dispatchAction('toggle-right-sidebar') }, + { label: 'Open Git Sidebar', accelerator: 'Cmd+Shift+G', click: () => dispatchAction('open-right-sidebar-git') }, + { label: 'Open Files Sidebar', accelerator: 'Cmd+Shift+F', click: () => dispatchAction('open-right-sidebar-files') }, + { type: 'separator' }, + { label: 'Toggle Terminal Dock', accelerator: 'Cmd+J', click: () => dispatchAction('toggle-terminal') }, + { label: 'Toggle Terminal Expanded', accelerator: 'Cmd+Shift+J', click: () => dispatchAction('toggle-terminal-expanded') }, { type: 'separator' }, { label: 'Light Theme', click: () => dispatchAction('theme-light') }, { label: 'Dark Theme', click: () => dispatchAction('theme-dark') }, diff --git a/packages/ui/src/components/ui/AboutDialog.tsx b/packages/ui/src/components/ui/AboutDialog.tsx index f1a67226..a58cda8c 100644 --- a/packages/ui/src/components/ui/AboutDialog.tsx +++ b/packages/ui/src/components/ui/AboutDialog.tsx @@ -21,6 +21,7 @@ export const AboutDialog: React.FC = ({ onOpenChange, }) => { const { t } = useI18n(); + const showDiagnostics = import.meta.env.DEV; const [version, setVersion] = React.useState(null); const [openCodeVersion, setOpenCodeVersion] = React.useState(null); const [isCopyingDiagnostics, setIsCopyingDiagnostics] = React.useState(false); @@ -29,6 +30,7 @@ export const AboutDialog: React.FC = ({ const [isPreparingDiagnostics, setIsPreparingDiagnostics] = React.useState(false); const handleCopyDiagnostics = React.useCallback(async () => { + if (!showDiagnostics) return; if (isCopyingDiagnostics) return; setIsCopyingDiagnostics(true); setCopiedDiagnostics(false); @@ -55,7 +57,7 @@ export const AboutDialog: React.FC = ({ } finally { setIsCopyingDiagnostics(false); } - }, [diagnosticsReport, isCopyingDiagnostics, t]); + }, [diagnosticsReport, isCopyingDiagnostics, showDiagnostics, t]); React.useEffect(() => { if (!open) return; @@ -107,7 +109,7 @@ export const AboutDialog: React.FC = ({ }, [open]); React.useEffect(() => { - if (!open) { + if (!open || !showDiagnostics) { setDiagnosticsReport(null); setIsPreparingDiagnostics(false); return; @@ -133,7 +135,7 @@ export const AboutDialog: React.FC = ({ return () => { cancelled = true; }; - }, [open]); + }, [open, showDiagnostics]); const displayVersion = version; @@ -155,54 +157,58 @@ export const AboutDialog: React.FC = ({ -
- -

- {t('aboutDialog.diagnosticsDescription')} -

-
+ {showDiagnostics && ( +
+ +

+ {t('aboutDialog.diagnosticsDescription')} +

+
+ )} -
+ diff --git a/packages/ui/src/hooks/useMenuActions.ts b/packages/ui/src/hooks/useMenuActions.ts index 6db3ac60..9ba3a921 100644 --- a/packages/ui/src/hooks/useMenuActions.ts +++ b/packages/ui/src/hooks/useMenuActions.ts @@ -72,10 +72,11 @@ type MenuAction = | 'new-session' | 'new-worktree-session' | 'change-workspace' - | 'open-git-tab' - | 'open-diff-tab' - | 'open-files-tab' - | 'open-terminal-tab' + | 'toggle-right-sidebar' + | 'open-right-sidebar-git' + | 'open-right-sidebar-files' + | 'toggle-terminal' + | 'toggle-terminal-expanded' | 'copy' | 'theme-light' | 'theme-dark' @@ -97,6 +98,11 @@ export const useMenuActions = ( const setActiveMainTab = useUIStore((s) => s.setActiveMainTab); const setSettingsDialogOpen = useUIStore((s) => s.setSettingsDialogOpen); const setAboutDialogOpen = useUIStore((s) => s.setAboutDialogOpen); + const toggleRightSidebar = useUIStore((s) => s.toggleRightSidebar); + const setRightSidebarOpen = useUIStore((s) => s.setRightSidebarOpen); + const setRightSidebarTab = useUIStore((s) => s.setRightSidebarTab); + const toggleBottomTerminal = useUIStore((s) => s.toggleBottomTerminal); + const setBottomTerminalExpanded = useUIStore((s) => s.setBottomTerminalExpanded); const checkForUpdates = useUpdateStore((state) => state.checkForUpdates); const { setThemeMode } = useThemeSystem(); const checkUpdatesInFlightRef = React.useRef(false); @@ -165,29 +171,27 @@ export const useMenuActions = ( handleChangeWorkspace(); break; - case 'open-git-tab': { - const { activeMainTab } = useUIStore.getState(); - setActiveMainTab(activeMainTab === 'git' ? 'chat' : 'git'); + case 'toggle-right-sidebar': + toggleRightSidebar(); break; - } - case 'open-diff-tab': { - const { activeMainTab } = useUIStore.getState(); - setActiveMainTab(activeMainTab === 'diff' ? 'chat' : 'diff'); + case 'open-right-sidebar-git': + setRightSidebarOpen(true); + setRightSidebarTab('git'); break; - } - case 'open-files-tab': { - const { activeMainTab } = useUIStore.getState(); - setActiveMainTab(activeMainTab === 'files' ? 'chat' : 'files'); + case 'open-right-sidebar-files': + setRightSidebarOpen(true); + setRightSidebarTab('files'); break; - } - case 'open-terminal-tab': { - const { activeMainTab } = useUIStore.getState(); - setActiveMainTab(activeMainTab === 'terminal' ? 'chat' : 'terminal'); + case 'toggle-terminal': + toggleBottomTerminal(); + break; + + case 'toggle-terminal-expanded': + setBottomTerminalExpanded(!useUIStore.getState().isBottomTerminalExpanded); break; - } case 'copy': { const copyEvent = new Event('openchamber:copy', { cancelable: true }); @@ -239,9 +243,14 @@ export const useMenuActions = ( setSessionSwitcherOpen, setCommandPaletteOpen, setSettingsDialogOpen, + setBottomTerminalExpanded, + setRightSidebarOpen, + setRightSidebarTab, setThemeMode, + toggleBottomTerminal, toggleCommandPalette, toggleHelpDialog, + toggleRightSidebar, toggleSidebar, ] ); diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index f85abbfb..6cd51cba 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -2208,16 +2208,16 @@ export const dict = { 'updateDialog.status.updating': 'Updating...', 'updateDialog.error.updateFailed': 'Update failed', 'updateDialog.error.takingLonger': 'Update is taking longer than expected. Wait a bit and refresh, or run: openchamber update', - 'opencodeUpdate.toast.available.title': 'OpenCode update available', - 'opencodeUpdate.toast.available.description': 'Version {version} is ready to install.', + 'opencodeUpdate.toast.available.title': 'OpenCode update', + 'opencodeUpdate.toast.available.description': 'Version {version} available.', 'opencodeUpdate.toast.actions.update': 'Update', 'opencodeUpdate.toast.actions.dismiss': 'Dismiss', 'opencodeUpdate.toast.actions.reload': 'Reload OpenCode', 'opencodeUpdate.toast.upgrading.title': 'Updating OpenCode...', 'opencodeUpdate.toast.upgrading.description': 'Keep OpenChamber open.', 'opencodeUpdate.toast.updated.title': 'OpenCode updated', - 'opencodeUpdate.toast.updated.description': 'Reload OpenCode to start using the updated version.', - 'opencodeUpdate.toast.updated.descriptionWithVersion': 'Version {version} is installed. Reload OpenCode to use it.', + 'opencodeUpdate.toast.updated.description': 'Update installed.', + 'opencodeUpdate.toast.updated.descriptionWithVersion': 'Version {version} installed.', 'opencodeUpdate.toast.failed.title': 'Could not update OpenCode', 'opencodeUpdate.toast.failed.description': 'The OpenCode upgrade failed.', 'opencodeUpdate.toast.reload.message': 'Restarting OpenCode...', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index a0269d6d..583da0c2 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -2174,16 +2174,16 @@ export const dict: Record = { "updateDialog.status.updating": "Actualizando...", "updateDialog.error.updateFailed": "No se pudo actualizar", "updateDialog.error.takingLonger": "La actualización está tardando más de lo esperado. Espera un poco y refresca, o ejecuta: openchamber update", - "opencodeUpdate.toast.available.title": "Actualización de OpenCode disponible", - "opencodeUpdate.toast.available.description": "La versión {version} está lista para instalar.", + "opencodeUpdate.toast.available.title": "Actualización de OpenCode", + "opencodeUpdate.toast.available.description": "Versión {version} disponible.", "opencodeUpdate.toast.actions.update": "Actualizar", "opencodeUpdate.toast.actions.dismiss": "Descartar", "opencodeUpdate.toast.actions.reload": "Recargar OpenCode", "opencodeUpdate.toast.upgrading.title": "Actualizando OpenCode...", "opencodeUpdate.toast.upgrading.description": "Mantén OpenChamber abierto.", "opencodeUpdate.toast.updated.title": "OpenCode actualizado", - "opencodeUpdate.toast.updated.description": "Recarga OpenCode para empezar a usar la versión actualizada.", - "opencodeUpdate.toast.updated.descriptionWithVersion": "La versión {version} está instalada. Recarga OpenCode para usarla.", + "opencodeUpdate.toast.updated.description": "Actualización instalada.", + "opencodeUpdate.toast.updated.descriptionWithVersion": "Versión {version} instalada.", "opencodeUpdate.toast.failed.title": "No se pudo actualizar OpenCode", "opencodeUpdate.toast.failed.description": "La actualización de OpenCode falló.", "opencodeUpdate.toast.reload.message": "Reiniciando OpenCode...", diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index f8ef57f6..fb2bf00b 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -2208,16 +2208,16 @@ export const dict: Record = { 'updateDialog.status.updating': '업데이트 중…', 'updateDialog.error.updateFailed': '업데이트 실패', 'updateDialog.error.takingLonger': '업데이트가 예상보다 오래 걸립니다. 잠시 기다린 뒤 새로고침하거나 `openchamber update`를 실행하세요.', - 'opencodeUpdate.toast.available.title': 'OpenCode 업데이트 사용 가능', - 'opencodeUpdate.toast.available.description': '버전 {version}을 설치할 수 있습니다.', + 'opencodeUpdate.toast.available.title': 'OpenCode 업데이트', + 'opencodeUpdate.toast.available.description': '버전 {version} 사용 가능.', 'opencodeUpdate.toast.actions.update': '업데이트', 'opencodeUpdate.toast.actions.dismiss': '닫기', 'opencodeUpdate.toast.actions.reload': 'OpenCode 다시 로드', 'opencodeUpdate.toast.upgrading.title': 'OpenCode 업데이트 중...', 'opencodeUpdate.toast.upgrading.description': 'OpenChamber를 열어 두세요.', 'opencodeUpdate.toast.updated.title': 'OpenCode 업데이트 완료', - 'opencodeUpdate.toast.updated.description': '업데이트된 버전을 사용하려면 OpenCode를 다시 로드하세요.', - 'opencodeUpdate.toast.updated.descriptionWithVersion': '버전 {version}이 설치되었습니다. 사용하려면 OpenCode를 다시 로드하세요.', + 'opencodeUpdate.toast.updated.description': '업데이트가 설치되었습니다.', + 'opencodeUpdate.toast.updated.descriptionWithVersion': '버전 {version}이 설치되었습니다.', 'opencodeUpdate.toast.failed.title': 'OpenCode를 업데이트할 수 없음', 'opencodeUpdate.toast.failed.description': 'OpenCode 업그레이드에 실패했습니다.', 'opencodeUpdate.toast.reload.message': 'OpenCode 다시 시작 중...', diff --git a/packages/ui/src/lib/i18n/messages/pl.ts b/packages/ui/src/lib/i18n/messages/pl.ts index f2aa3233..e204fa86 100644 --- a/packages/ui/src/lib/i18n/messages/pl.ts +++ b/packages/ui/src/lib/i18n/messages/pl.ts @@ -2189,16 +2189,16 @@ export const dict: Record = { 'updateDialog.status.serverRestarting': 'Ponowne uruchamianie serwera...', 'updateDialog.status.updating': 'Aktualizowanie...', 'updateDialog.status.waitingForServer': 'Oczekiwanie na serwer...', - 'opencodeUpdate.toast.available.title': 'Dostępna aktualizacja OpenCode', - 'opencodeUpdate.toast.available.description': 'Wersja {version} jest gotowa do instalacji.', + 'opencodeUpdate.toast.available.title': 'Aktualizacja OpenCode', + 'opencodeUpdate.toast.available.description': 'Wersja {version} dostępna.', 'opencodeUpdate.toast.actions.update': 'Aktualizuj', 'opencodeUpdate.toast.actions.dismiss': 'Odrzuć', 'opencodeUpdate.toast.actions.reload': 'Przeładuj OpenCode', 'opencodeUpdate.toast.upgrading.title': 'Aktualizowanie OpenCode...', 'opencodeUpdate.toast.upgrading.description': 'Pozostaw OpenChamber otwarte.', 'opencodeUpdate.toast.updated.title': 'OpenCode zaktualizowany', - 'opencodeUpdate.toast.updated.description': 'Przeładuj OpenCode, aby zacząć używać zaktualizowanej wersji.', - 'opencodeUpdate.toast.updated.descriptionWithVersion': 'Wersja {version} jest zainstalowana. Przeładuj OpenCode, aby jej użyć.', + 'opencodeUpdate.toast.updated.description': 'Aktualizacja zainstalowana.', + 'opencodeUpdate.toast.updated.descriptionWithVersion': 'Wersja {version} zainstalowana.', 'opencodeUpdate.toast.failed.title': 'Nie udało się zaktualizować OpenCode', 'opencodeUpdate.toast.failed.description': 'Aktualizacja OpenCode nie powiodła się.', 'opencodeUpdate.toast.reload.message': 'Ponowne uruchamianie OpenCode...', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index 05e75d04..6274d841 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -2174,16 +2174,16 @@ export const dict: Record = { "updateDialog.status.updating": "Atualizando...", "updateDialog.error.updateFailed": "Não foi possível atualizar", "updateDialog.error.takingLonger": "A atualização está demorando mais do que o esperado. Aguarde um pouco e atualize, ou execute: openchamber update", - "opencodeUpdate.toast.available.title": "Atualização do OpenCode disponível", - "opencodeUpdate.toast.available.description": "A versão {version} está pronta para instalar.", + "opencodeUpdate.toast.available.title": "Atualização do OpenCode", + "opencodeUpdate.toast.available.description": "Versão {version} disponível.", "opencodeUpdate.toast.actions.update": "Atualizar", "opencodeUpdate.toast.actions.dismiss": "Dispensar", "opencodeUpdate.toast.actions.reload": "Recarregar OpenCode", "opencodeUpdate.toast.upgrading.title": "Atualizando OpenCode...", "opencodeUpdate.toast.upgrading.description": "Mantenha o OpenChamber aberto.", "opencodeUpdate.toast.updated.title": "OpenCode atualizado", - "opencodeUpdate.toast.updated.description": "Recarregue o OpenCode para começar a usar a versão atualizada.", - "opencodeUpdate.toast.updated.descriptionWithVersion": "A versão {version} está instalada. Recarregue o OpenCode para usá-la.", + "opencodeUpdate.toast.updated.description": "Atualização instalada.", + "opencodeUpdate.toast.updated.descriptionWithVersion": "Versão {version} instalada.", "opencodeUpdate.toast.failed.title": "Não foi possível atualizar o OpenCode", "opencodeUpdate.toast.failed.description": "A atualização do OpenCode falhou.", "opencodeUpdate.toast.reload.message": "Reiniciando OpenCode...", diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index d3292661..7dd35ad2 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -2174,16 +2174,16 @@ export const dict: Record = { "updateDialog.status.updating": "Оновлення...", "updateDialog.error.updateFailed": "Помилка оновлення", "updateDialog.error.takingLonger": "Оновлення триває довше, ніж очікувалося. Зачекайте трохи та оновіть або запустіть: openchamber update", - "opencodeUpdate.toast.available.title": "Доступне оновлення OpenCode", - "opencodeUpdate.toast.available.description": "Версія {version} готова до встановлення.", + "opencodeUpdate.toast.available.title": "Оновлення OpenCode", + "opencodeUpdate.toast.available.description": "Версія {version} доступна.", "opencodeUpdate.toast.actions.update": "Оновити", "opencodeUpdate.toast.actions.dismiss": "Сховати", "opencodeUpdate.toast.actions.reload": "Перезавантажити OpenCode", "opencodeUpdate.toast.upgrading.title": "Оновлення OpenCode...", "opencodeUpdate.toast.upgrading.description": "Залиште OpenChamber відкритим.", "opencodeUpdate.toast.updated.title": "OpenCode оновлено", - "opencodeUpdate.toast.updated.description": "Перезавантажте OpenCode, щоб почати використовувати оновлену версію.", - "opencodeUpdate.toast.updated.descriptionWithVersion": "Версію {version} встановлено. Перезавантажте OpenCode, щоб її використовувати.", + "opencodeUpdate.toast.updated.description": "Оновлення встановлено.", + "opencodeUpdate.toast.updated.descriptionWithVersion": "Версію {version} встановлено.", "opencodeUpdate.toast.failed.title": "Не вдалося оновити OpenCode", "opencodeUpdate.toast.failed.description": "Оновлення OpenCode не вдалося.", "opencodeUpdate.toast.reload.message": "Перезапуск OpenCode...", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 721cb7b7..8c58ebbb 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -2174,16 +2174,16 @@ export const dict: Record = { 'updateDialog.status.updating': '更新中...', 'updateDialog.error.updateFailed': '更新失败', 'updateDialog.error.takingLonger': '更新耗时超出预期。请稍等后刷新,或运行:openchamber update', - 'opencodeUpdate.toast.available.title': 'OpenCode 有可用更新', - 'opencodeUpdate.toast.available.description': '版本 {version} 已可安装。', + 'opencodeUpdate.toast.available.title': 'OpenCode 更新', + 'opencodeUpdate.toast.available.description': '版本 {version} 可用。', 'opencodeUpdate.toast.actions.update': '更新', 'opencodeUpdate.toast.actions.dismiss': '忽略', 'opencodeUpdate.toast.actions.reload': '重载 OpenCode', 'opencodeUpdate.toast.upgrading.title': '正在更新 OpenCode...', 'opencodeUpdate.toast.upgrading.description': '请保持 OpenChamber 打开。', 'opencodeUpdate.toast.updated.title': 'OpenCode 已更新', - 'opencodeUpdate.toast.updated.description': '重载 OpenCode 以开始使用更新后的版本。', - 'opencodeUpdate.toast.updated.descriptionWithVersion': '版本 {version} 已安装。重载 OpenCode 后即可使用。', + 'opencodeUpdate.toast.updated.description': '更新已安装。', + 'opencodeUpdate.toast.updated.descriptionWithVersion': '版本 {version} 已安装。', 'opencodeUpdate.toast.failed.title': '无法更新 OpenCode', 'opencodeUpdate.toast.failed.description': 'OpenCode 升级失败。', 'opencodeUpdate.toast.reload.message': '正在重启 OpenCode...', diff --git a/packages/web/server/lib/opencode/DOCUMENTATION.md b/packages/web/server/lib/opencode/DOCUMENTATION.md index fd74239a..c68d0fda 100644 --- a/packages/web/server/lib/opencode/DOCUMENTATION.md +++ b/packages/web/server/lib/opencode/DOCUMENTATION.md @@ -73,6 +73,8 @@ This module provides OpenCode server integration utilities for the web server ru - `GET /api/config/settings` - `PUT /api/config/settings` - `GET /api/config/opencode-resolution` + - `POST /api/opencode/upgrade` (proxies OpenCode upgrade, then restarts managed OpenCode so the new binary is active) + - `GET /api/opencode/upgrade-status` - `POST /api/opencode/directory` - `GET /api/provider/:providerId/source` - `DELETE /api/provider/:providerId/auth` diff --git a/packages/web/server/lib/opencode/routes.js b/packages/web/server/lib/opencode/routes.js index 24b8bb13..151977a4 100644 --- a/packages/web/server/lib/opencode/routes.js +++ b/packages/web/server/lib/opencode/routes.js @@ -155,7 +155,20 @@ export const registerOpenCodeRoutes = (app, dependencies) => { error: payload?.error || response.statusText || 'Failed to upgrade OpenCode', }); } - return res.json(payload ?? { success: true }); + + try { + await refreshOpenCodeAfterConfigChange('OpenCode upgrade'); + } catch (restartError) { + return res.status(500).json({ + success: false, + upgraded: true, + error: restartError instanceof Error + ? `OpenCode upgraded, but restart failed: ${restartError.message}` + : 'OpenCode upgraded, but restart failed', + }); + } + + return res.json({ ...(payload ?? { success: true }), restarted: true }); } catch (error) { console.error('Failed to upgrade OpenCode:', error); return res.status(500).json({