Add Windows Electron desktop support (#1093)

* fix: make upstream sync actions target the selected remote

Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators.

* feat: add Windows Electron desktop foundation

* fix(electron): stabilize Windows desktop packaging

* fix(electron): stabilize Windows desktop chrome

Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions.

* fix(electron): stabilize Windows dev startup

* fix(electron): clarify desktop artifact names

* fix(electron): harden Windows desktop release and launch

* fix(electron): address Windows release review

* fix(electron): point updater and release links to org repo

* Fix Windows settings persistence fallback

* Fix Windows Electron dev startup

* Add Windows Electron window controls

* Fix Windows Electron install and opencode launch

* fix: resolve git status for repositories without upstream

Fixes repository detection stuck on Checking repository
Handles git status when no upstream is configured
Adds regression coverage for git status loading

* Add Windows app menu button

* fix: preserve file editor line endings

* ci: add desktop release smoke workflow

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Dave Otero
2026-05-26 18:13:59 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent cc7969ac00
commit becd240168
59 changed files with 2260 additions and 246 deletions
+8
View File
@@ -118,11 +118,19 @@ export interface GitRebaseInProgress {
onto: string;
}
export interface GitRemoteComparison {
remote: string;
branch: string;
ahead: number;
behind: number;
}
export interface GitStatus {
current: string;
tracking: string | null;
ahead: number;
behind: number;
upstreamComparison?: GitRemoteComparison | null;
files: GitStatusFile[];
isClean: boolean;
diffStats?: Record<string, { insertions: number; deletions: number }>;
+11 -1
View File
@@ -505,6 +505,9 @@ export const dict = {
'gitView.header.noProfiles': 'No profiles available to apply.',
'gitView.header.removeRemoteAria': 'Remove Remote aria label',
'gitView.header.removeRemoteTitle': 'Remove Remote Title',
'gitView.header.upstreamSynced': 'synced',
'gitView.header.upstreamTooltip': 'Compared with {target}.',
'gitView.header.upstreamTooltipTracking': 'Compared with {target}. Primary sync badges still reflect {tracking}.',
'gitView.history.binary': 'Binary',
'gitView.history.binaryNoDiff': 'Binary file — no diff available',
'gitView.history.commitsPlaceholder': 'Commits Placeholder',
@@ -762,7 +765,7 @@ export const dict = {
'gitView.toast.mergedIntoBranch': 'Merged {branch} into {currentBranch}',
'gitView.toast.pulledFilesPlural': 'Pulled {count} files from {name}',
'gitView.toast.pulledFilesSingle': 'Pulled {count} file from {name}',
'gitView.toast.pushedToUpstream': 'Pushed to upstream',
'gitView.toast.pushedToUpstream': 'Pushed to {name}',
'gitView.toast.commitOrStashBeforeSync': 'Commit or stash your changes before syncing',
'gitView.toast.alreadyUpToDate': 'Already up to date',
'gitView.toast.syncedPulledPluralAndPushed': 'Pulled {count} files from {name} and pushed to upstream',
@@ -1259,6 +1262,8 @@ export const dict = {
'helpDialog.proTips.themeCycling': 'Theme cycling remembers your preference across sessions',
'header.actions.rightSidebarWithShortcut': 'Right sidebar ({shortcut})',
'header.actions.toggleRightSidebarAria': 'Toggle right sidebar',
'header.actions.openAppMenu': 'OpenChamber menu',
'header.actions.openAppMenuAria': 'Open OpenChamber menu',
'header.actions.openSessionsWithShortcut': 'Open sessions ({shortcut})',
'header.actions.openSessionsAria': 'Open sessions',
'header.actions.closeSessionsAria': 'Close sessions',
@@ -2085,6 +2090,11 @@ export const dict = {
'header.actions.newMiniChatAria': 'Open a new Mini Chat window',
'header.actions.openSessionMiniChat': 'Open Session in Mini Chat',
'header.actions.openSessionMiniChatAria': 'Open current session in Mini Chat',
'header.windowControls.groupAria': 'Window controls',
'header.windowControls.minimize': 'Minimize window',
'header.windowControls.maximize': 'Maximize window',
'header.windowControls.restore': 'Restore window',
'header.windowControls.close': 'Close window',
'errorBoundary.title': 'Something went wrong',
'errorBoundary.description': 'The application encountered an unexpected error. This has been logged for debugging.',
'errorBoundary.state.unknownError': 'Unknown error',
+11 -1
View File
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
"gitView.header.noProfiles": "No hay perfiles disponibles para aplicar.",
"gitView.header.removeRemoteAria": "Eliminar remoto",
"gitView.header.removeRemoteTitle": "Eliminar remoto",
"gitView.header.upstreamSynced": "sincronizado",
"gitView.header.upstreamTooltip": "Comparado con {target}.",
"gitView.header.upstreamTooltipTracking": "Comparado con {target}. Los indicadores principales de sincronización aún reflejan {tracking}.",
"gitView.history.binary": "Binario",
"gitView.history.binaryNoDiff": "Archivo binario — no hay diff disponible",
"gitView.history.commitsPlaceholder": "Buscar commits...",
@@ -763,7 +766,7 @@ export const dict: Record<I18nKey, string> = {
"gitView.toast.mergedIntoBranch": "Merge de {branch} en {currentBranch}",
"gitView.toast.pulledFilesPlural": "Se trajeron {count} archivos de {name}",
"gitView.toast.pulledFilesSingle": "Se trajo {count} archivo de {name}",
"gitView.toast.pushedToUpstream": "Enviado al upstream",
"gitView.toast.pushedToUpstream": "Enviado a {name}",
"gitView.toast.commitOrStashBeforeSync": "Haz commit o stash de tus cambios antes de sincronizar",
"gitView.toast.alreadyUpToDate": "Ya está actualizado",
"gitView.toast.syncedPulledPluralAndPushed": "Se trajeron {count} archivos de {name} y se envió al upstream",
@@ -1225,6 +1228,8 @@ export const dict: Record<I18nKey, string> = {
"helpDialog.proTips.themeCycling": "El ciclo de tema recuerda tu preferencia entre sesiones",
"header.actions.rightSidebarWithShortcut": "Barra lateral derecha ({shortcut})",
"header.actions.toggleRightSidebarAria": "Mostrar u ocultar barra lateral derecha",
"header.actions.openAppMenu": "Menú de OpenChamber",
"header.actions.openAppMenuAria": "Abrir menú de OpenChamber",
"header.actions.openSessionsWithShortcut": "Abrir sesiones ({shortcut})",
"header.actions.openSessionsAria": "Abrir sesiones",
"header.actions.closeSessionsAria": "Cerrar sesiones",
@@ -2051,6 +2056,11 @@ export const dict: Record<I18nKey, string> = {
"header.actions.newMiniChatAria": "Abrir una nueva ventana Mini Chat",
"header.actions.openSessionMiniChat": "Abrir sesión en Mini Chat",
"header.actions.openSessionMiniChatAria": "Abrir la sesión actual en Mini Chat",
"header.windowControls.groupAria": "Controles de ventana",
"header.windowControls.minimize": "Minimizar ventana",
"header.windowControls.maximize": "Maximizar ventana",
"header.windowControls.restore": "Restaurar ventana",
"header.windowControls.close": "Cerrar ventana",
"errorBoundary.title": "Algo salió mal",
"errorBoundary.description": "La aplicación encontró un error inesperado. Esto se ha registrado para depuración.",
"errorBoundary.state.unknownError": "Error desconocido",
+11 -1
View File
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
'gitView.header.noProfiles': '적용할 프로필 없음',
'gitView.header.removeRemoteAria': '리모트 제거',
'gitView.header.removeRemoteTitle': '리모트 제거',
'gitView.header.upstreamSynced': '동기화됨',
'gitView.header.upstreamTooltip': '{target}와 비교됨.',
'gitView.header.upstreamTooltipTracking': '{target}와 비교됨. 기본 동기화 배지는 계속 {tracking}을 반영합니다.',
'gitView.history.binary': '바이너리',
'gitView.history.binaryNoDiff': '바이너리 파일 — diff 없음',
'gitView.history.commitsPlaceholder': '커밋 검색',
@@ -763,7 +766,7 @@ export const dict: Record<I18nKey, string> = {
'gitView.toast.mergedIntoBranch': '{branch}을(를) {currentBranch}에 병합했습니다',
'gitView.toast.pulledFilesPlural': '{name}에서 파일 {count}개를 풀했습니다',
'gitView.toast.pulledFilesSingle': '{name}에서 파일 {count}개를 풀했습니다',
'gitView.toast.pushedToUpstream': '업스트림에 푸시했습니다',
'gitView.toast.pushedToUpstream': '{name}에 푸시했습니다',
'gitView.toast.commitOrStashBeforeSync': '동기화하기 전에 변경 사항을 커밋하거나 stash하세요',
'gitView.toast.alreadyUpToDate': '이미 최신 상태입니다',
'gitView.toast.syncedPulledPluralAndPushed': '{name}에서 파일 {count}개를 풀하고 업스트림에 푸시했습니다',
@@ -1261,6 +1264,8 @@ export const dict: Record<I18nKey, string> = {
'helpDialog.proTips.themeCycling': '테마 순환은 세션 간에도 선호 설정을 기억합니다',
'header.actions.rightSidebarWithShortcut': '오른쪽 사이드바 ({shortcut})',
'header.actions.toggleRightSidebarAria': '오른쪽 사이드바 토글',
'header.actions.openAppMenu': 'OpenChamber 메뉴',
'header.actions.openAppMenuAria': 'OpenChamber 메뉴 열기',
'header.actions.openSessionsWithShortcut': '세션 ({shortcut}) 열기',
'header.actions.openSessionsAria': '세션 열기',
'header.actions.closeSessionsAria': '세션 닫기',
@@ -2085,6 +2090,11 @@ export const dict: Record<I18nKey, string> = {
'header.actions.newMiniChatAria': '새 Mini Chat 창 열기',
'header.actions.openSessionMiniChat': 'Mini Chat에서 세션 열기',
'header.actions.openSessionMiniChatAria': '현재 세션을 Mini Chat에서 열기',
'header.windowControls.groupAria': '창 컨트롤',
'header.windowControls.minimize': '창 최소화',
'header.windowControls.maximize': '창 최대화',
'header.windowControls.restore': '창 복원',
'header.windowControls.close': '창 닫기',
'errorBoundary.title': '문제가 발생했습니다',
'errorBoundary.description': '애플리케이션에서 예상치 못한 오류가 발생했습니다. 디버깅을 위해 기록되었습니다.',
'errorBoundary.state.unknownError': '알 수 없음 오류',
+10
View File
@@ -601,6 +601,11 @@ export const dict: Record<I18nKey, string> = {
'header.actions.newMiniChatAria': 'Otwórz nowe okno Mini Chat',
'header.actions.openSessionMiniChat': 'Otwórz sesję w Mini Chat',
'header.actions.openSessionMiniChatAria': 'Otwórz bieżącą sesję w Mini Chat',
'header.windowControls.groupAria': 'Elementy sterujące oknem',
'header.windowControls.minimize': 'Minimalizuj okno',
'header.windowControls.maximize': 'Maksymalizuj okno',
'header.windowControls.restore': 'Przywróć okno',
'header.windowControls.close': 'Zamknij okno',
'errorBoundary.title': 'Coś poszło nie tak',
'errorBoundary.description': 'Aplikacja napotkała nieoczekiwany błąd. Zostało to zalogowane do celów debugowania.',
'errorBoundary.state.unknownError': 'Nieznany błąd',
@@ -1488,6 +1493,9 @@ export const dict: Record<I18nKey, string> = {
'gitView.header.noProfiles': 'No profiles available to apply.',
'gitView.header.removeRemoteAria': 'Remove Remote aria label',
'gitView.header.removeRemoteTitle': 'Remove Remote Title',
'gitView.header.upstreamSynced': 'zsynchronizowano',
'gitView.header.upstreamTooltip': 'Porównano z {target}.',
'gitView.header.upstreamTooltipTracking': 'Porównano z {target}. Główne wskaźniki synchronizacji nadal odzwierciedlają {tracking}.',
'gitView.history.binary': 'Binary',
'gitView.history.binaryNoDiff': 'Binary file — no diff available',
'gitView.history.commitsPlaceholder': 'Commits Placeholder',
@@ -1729,6 +1737,8 @@ export const dict: Record<I18nKey, string> = {
'header.actions.newSessionWithShortcut': 'Nowa sesja ({shortcut})',
'header.actions.openPlanAria': 'Otwórz plan',
'header.actions.openSessionsAria': 'Otwórz sesje',
'header.actions.openAppMenu': 'Menu OpenChamber',
'header.actions.openAppMenuAria': 'Otwórz menu OpenChamber',
'header.actions.openSessionsWithShortcut': 'Otwórz sesje ({shortcut})',
'header.actions.planWithShortcut': 'Plan ({shortcut})',
'header.actions.rightSidebarWithShortcut': 'Prawy panel boczny ({shortcut})',
+11 -1
View File
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
"gitView.header.noProfiles": "Não há perfiles disponíveis para aplicar.",
"gitView.header.removeRemoteAria": "Excluir remoto",
"gitView.header.removeRemoteTitle": "Excluir remoto",
"gitView.header.upstreamSynced": "sincronizado",
"gitView.header.upstreamTooltip": "Comparado com {target}.",
"gitView.header.upstreamTooltipTracking": "Comparado com {target}. Os indicadores principais de sincronização ainda refletem {tracking}.",
"gitView.history.binary": "Binario",
"gitView.history.binaryNoDiff": "Arquivo binário — diff não disponível",
"gitView.history.commitsPlaceholder": "Buscar commits...",
@@ -763,7 +766,7 @@ export const dict: Record<I18nKey, string> = {
"gitView.toast.mergedIntoBranch": "Merge de {branch} em {currentBranch}",
"gitView.toast.pulledFilesPlural": "Se trajeron {count} arquivos de {name}",
"gitView.toast.pulledFilesSingle": "Se trajo {count} arquivo de {name}",
"gitView.toast.pushedToUpstream": "Enviado ao upstream",
"gitView.toast.pushedToUpstream": "Enviado para {name}",
"gitView.toast.commitOrStashBeforeSync": "Faça commit ou stash das alterações antes de sincronizar",
"gitView.toast.alreadyUpToDate": "Já está atualizado",
"gitView.toast.syncedPulledPluralAndPushed": "Foram trazidos {count} arquivos de {name} e enviados ao upstream",
@@ -1225,6 +1228,8 @@ export const dict: Record<I18nKey, string> = {
"helpDialog.proTips.themeCycling": "A alternância de tema lembra sua preferência entre sessões",
"header.actions.rightSidebarWithShortcut": "Barra lateral direita ({shortcut})",
"header.actions.toggleRightSidebarAria": "Mostrar ou ocultar barra lateral direita",
"header.actions.openAppMenu": "Menu do OpenChamber",
"header.actions.openAppMenuAria": "Abrir menu do OpenChamber",
"header.actions.openSessionsWithShortcut": "Abrir sessões ({shortcut})",
"header.actions.openSessionsAria": "Abrir sessões",
"header.actions.closeSessionsAria": "Fechar sessões",
@@ -2051,6 +2056,11 @@ export const dict: Record<I18nKey, string> = {
"header.actions.newMiniChatAria": "Abrir uma nova janela Mini Chat",
"header.actions.openSessionMiniChat": "Abrir sessão no Mini Chat",
"header.actions.openSessionMiniChatAria": "Abrir a sessão atual no Mini Chat",
"header.windowControls.groupAria": "Controles da janela",
"header.windowControls.minimize": "Minimizar janela",
"header.windowControls.maximize": "Maximizar janela",
"header.windowControls.restore": "Restaurar janela",
"header.windowControls.close": "Fechar janela",
"errorBoundary.title": "Algo deu errado",
"errorBoundary.description": "O aplicativo encontrou um erro inesperado. Isso foi registrado para depuração.",
"errorBoundary.state.unknownError": "Erro desconhecido",
+11 -1
View File
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
"gitView.header.noProfiles": "Немає доступних профілів для застосування.",
"gitView.header.removeRemoteAria": "Видалити remote",
"gitView.header.removeRemoteTitle": "Видалити remote",
"gitView.header.upstreamSynced": "синхронізовано",
"gitView.header.upstreamTooltip": "Порівняно з {target}.",
"gitView.header.upstreamTooltipTracking": "Порівняно з {target}. Основні індикатори синхронізації все ще відображають {tracking}.",
"gitView.history.binary": "Бінарний",
"gitView.history.binaryNoDiff": "Бінарний файл — diff недоступний",
"gitView.history.commitsPlaceholder": "Пошук комітів",
@@ -763,7 +766,7 @@ export const dict: Record<I18nKey, string> = {
"gitView.toast.mergedIntoBranch": "Злито {branch} в {currentBranch}",
"gitView.toast.pulledFilesPlural": "Отримано файлів: {count} з {name}",
"gitView.toast.pulledFilesSingle": "Отримано файл: {count} з {name}",
"gitView.toast.pushedToUpstream": "Надіслано в upstream",
"gitView.toast.pushedToUpstream": "Надіслано в {name}",
"gitView.toast.commitOrStashBeforeSync": "Закомітьте або сховайте зміни перед синхронізацією",
"gitView.toast.alreadyUpToDate": "Вже актуально",
"gitView.toast.syncedPulledPluralAndPushed": "Отримано файлів: {count} з {name} і надіслано в upstream",
@@ -1225,6 +1228,8 @@ export const dict: Record<I18nKey, string> = {
"helpDialog.proTips.themeCycling": "Перемикання теми запам’ятовує ваші переваги протягом сесій",
"header.actions.rightSidebarWithShortcut": "Права бічна панель ({shortcut})",
"header.actions.toggleRightSidebarAria": "Перемкнути праву бічну панель",
"header.actions.openAppMenu": "Меню OpenChamber",
"header.actions.openAppMenuAria": "Відкрити меню OpenChamber",
"header.actions.openSessionsWithShortcut": "Відкрити сесії ({shortcut})",
"header.actions.openSessionsAria": "Відкрити сесії",
"header.actions.closeSessionsAria": "Закрити сесії",
@@ -2051,6 +2056,11 @@ export const dict: Record<I18nKey, string> = {
"header.actions.newMiniChatAria": "Відкрити нове вікно Mini Chat",
"header.actions.openSessionMiniChat": "Відкрити сесію в Mini Chat",
"header.actions.openSessionMiniChatAria": "Відкрити поточну сесію в Mini Chat",
"header.windowControls.groupAria": "Елементи керування вікном",
"header.windowControls.minimize": "Згорнути вікно",
"header.windowControls.maximize": "Розгорнути вікно",
"header.windowControls.restore": "Відновити вікно",
"header.windowControls.close": "Закрити вікно",
"errorBoundary.title": "Щось пішло не так",
"errorBoundary.description": "У програмі сталася неочікувана помилка. Це було зареєстровано для налагодження.",
"errorBoundary.state.unknownError": "Невідома помилка",
+11 -1
View File
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
'gitView.header.noProfiles': '没有可应用的配置。',
'gitView.header.removeRemoteAria': '移除远程 {name}',
'gitView.header.removeRemoteTitle': '移除 {name}',
'gitView.header.upstreamSynced': '已同步',
'gitView.header.upstreamTooltip': '与 {target} 对比。',
'gitView.header.upstreamTooltipTracking': '与 {target} 对比。主要同步徽标仍然反映 {tracking}。',
'gitView.history.binary': '二进制',
'gitView.history.binaryNoDiff': '二进制文件,无法显示差异',
'gitView.history.commitsPlaceholder': '提交数',
@@ -763,7 +766,7 @@ export const dict: Record<I18nKey, string> = {
'gitView.toast.mergedIntoBranch': '已将 {branch} 合并到 {currentBranch}',
'gitView.toast.pulledFilesPlural': '已从 {name} 拉取 {count} 个文件',
'gitView.toast.pulledFilesSingle': '已从 {name} 拉取 {count} 个文件',
'gitView.toast.pushedToUpstream': '已推送到上游',
'gitView.toast.pushedToUpstream': '已推送到 {name}',
'gitView.toast.commitOrStashBeforeSync': '同步前请先提交或储藏你的更改',
'gitView.toast.alreadyUpToDate': '已是最新状态',
'gitView.toast.syncedPulledPluralAndPushed': '已从 {name} 拉取 {count} 个文件并推送到上游',
@@ -1225,6 +1228,8 @@ export const dict: Record<I18nKey, string> = {
'helpDialog.proTips.themeCycling': '主题循环会记住你在各会话中的偏好',
'header.actions.rightSidebarWithShortcut': '右侧边栏({shortcut}',
'header.actions.toggleRightSidebarAria': '切换右侧边栏',
'header.actions.openAppMenu': 'OpenChamber 菜单',
'header.actions.openAppMenuAria': '打开 OpenChamber 菜单',
'header.actions.openSessionsWithShortcut': '打开会话({shortcut}',
'header.actions.openSessionsAria': '打开会话',
'header.actions.closeSessionsAria': '关闭会话',
@@ -2051,6 +2056,11 @@ export const dict: Record<I18nKey, string> = {
'header.actions.newMiniChatAria': '打开新的 Mini Chat 窗口',
'header.actions.openSessionMiniChat': '在 Mini Chat 中打开会话',
'header.actions.openSessionMiniChatAria': '在 Mini Chat 中打开当前会话',
'header.windowControls.groupAria': '窗口控件',
'header.windowControls.minimize': '最小化窗口',
'header.windowControls.maximize': '最大化窗口',
'header.windowControls.restore': '还原窗口',
'header.windowControls.close': '关闭窗口',
'errorBoundary.title': '发生错误',
'errorBoundary.description': '应用遇到意外错误,已记录用于调试。',
'errorBoundary.state.unknownError': '未知错误',
@@ -506,6 +506,9 @@ export const dict: Record<I18nKey, string> = {
'gitView.header.noProfiles': '沒有可套用的設定。',
'gitView.header.removeRemoteAria': '移除遠端 {name}',
'gitView.header.removeRemoteTitle': '移除 {name}',
'gitView.header.upstreamSynced': '已同步',
'gitView.header.upstreamTooltip': '與 {target} 比較。',
'gitView.header.upstreamTooltipTracking': '與 {target} 比較。主要同步徽章仍反映 {tracking}。',
'gitView.history.binary': '二進位',
'gitView.history.binaryNoDiff': '二進位檔案 — 無可用 diff',
'gitView.history.commitsPlaceholder': '提交數',
@@ -1223,6 +1226,8 @@ export const dict: Record<I18nKey, string> = {
'helpDialog.proTips.themeCycling': '主題循環會記住你在各會話中的偏好',
'header.actions.rightSidebarWithShortcut': '右側邊欄({shortcut}',
'header.actions.toggleRightSidebarAria': '切換右側邊欄',
'header.actions.openAppMenu': 'OpenChamber 選單',
'header.actions.openAppMenuAria': '開啟 OpenChamber 選單',
'header.actions.openSessionsWithShortcut': '開啟會話({shortcut}',
'header.actions.openSessionsAria': '開啟會話',
'header.actions.closeSessionsAria': '關閉會話',
@@ -2049,6 +2054,11 @@ export const dict: Record<I18nKey, string> = {
'header.actions.newMiniChatAria': '開啟新的 Mini Chat 視窗',
'header.actions.openSessionMiniChat': '在 Mini Chat 中開啟會話',
'header.actions.openSessionMiniChatAria': '在 Mini Chat 中開啟目前會話',
'header.windowControls.groupAria': '視窗控制項',
'header.windowControls.minimize': '最小化視窗',
'header.windowControls.maximize': '最大化視窗',
'header.windowControls.restore': '還原視窗',
'header.windowControls.close': '關閉視窗',
'errorBoundary.title': '發生錯誤',
'errorBoundary.description': '應用程式遇到意外錯誤,已記錄用於偵錯。',
'errorBoundary.state.unknownError': '未知錯誤',
+12 -2
View File
@@ -34,13 +34,23 @@ export const DEFAULT_OPEN_IN_APP_ID = 'finder';
export const OPEN_IN_ALWAYS_AVAILABLE_APP_IDS = new Set(['finder', 'terminal']);
export const OPEN_DIRECTORY_APP_IDS = new Set(['finder', 'terminal', 'iterm2', 'ghostty']);
export const getPlatformOpenInApp = (app: OpenInApp): OpenInApp => {
if (typeof window !== 'undefined' && window.__OPENCHAMBER_PLATFORM__ === 'win32') {
if (app.id === 'finder') {
return { ...app, label: 'Explorer', appName: 'File Explorer' };
}
}
return app;
};
export const getOpenInAppById = (id: string | null | undefined): OpenInApp | null => {
if (!id) {
return null;
}
return OPEN_IN_APPS.find((app) => app.id === id) ?? null;
const app = OPEN_IN_APPS.find((candidate) => candidate.id === id) ?? null;
return app ? getPlatformOpenInApp(app) : null;
};
export const getDefaultOpenInApp = (): OpenInApp => {
return getOpenInAppById(DEFAULT_OPEN_IN_APP_ID) ?? OPEN_IN_APPS[0];
return getOpenInAppById(DEFAULT_OPEN_IN_APP_ID) ?? getPlatformOpenInApp(OPEN_IN_APPS[0]);
};