From 384860d83cfb64b7e6a4ab135889b37b505ebfe6 Mon Sep 17 00:00:00 2001 From: Serhii Vecherenko Date: Sat, 1 Aug 2026 21:23:41 -0700 Subject: [PATCH 1/3] feat(sleep): prevent sleep while remote access is enabled - Add `remoteAccessPreventSleep` shared setting and a toggle in RemoteAccessSettings - Introduce sleepPolicy to centralize sleep-prevention decisions for active threads and remote access - Refresh the power save blocker when the remote controller enables - Update systemd-inhibit reason string to "Poracode is active" - Localize the new setting across all locale catalogs and add/extend tests --- src/main/main.ts | 13 ++++-- src/main/sharedSettingsFile.test.ts | 2 + src/main/sleepInhibitor.test.ts | 8 +--- src/main/sleepInhibitor.ts | 8 +--- src/main/sleepPolicy.test.ts | 43 +++++++++++++++++++ src/main/sleepPolicy.ts | 16 +++++++ src/renderer/locales/de/messages.po | 10 +++++ src/renderer/locales/en/messages.po | 10 +++++ src/renderer/locales/es/messages.po | 10 +++++ src/renderer/locales/fr/messages.po | 10 +++++ src/renderer/locales/ja/messages.po | 10 +++++ src/renderer/locales/ko/messages.po | 10 +++++ src/renderer/locales/pl/messages.po | 10 +++++ src/renderer/locales/pt-BR/messages.po | 10 +++++ src/renderer/locales/ru/messages.po | 10 +++++ src/renderer/locales/tr/messages.po | 10 +++++ src/renderer/locales/uk/messages.po | 10 +++++ src/renderer/locales/vi/messages.po | 10 +++++ src/renderer/locales/zh-CN/messages.po | 10 +++++ src/renderer/state/sharedSettingsStore.ts | 6 +++ .../parts/RemoteAccessSettings.test.tsx | 12 ++++++ .../parts/RemoteAccessSettings.tsx | 16 +++++++ .../parts/settingsSearchIndex.ts | 10 +++++ src/shared/settings.test.ts | 8 ++++ src/shared/settings.ts | 3 ++ 25 files changed, 257 insertions(+), 18 deletions(-) create mode 100644 src/main/sleepPolicy.test.ts create mode 100644 src/main/sleepPolicy.ts diff --git a/src/main/main.ts b/src/main/main.ts index 4f45e0014..00fbcab18 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -32,6 +32,7 @@ import { cleanupOrphanedAttachments, preparePoracodeDataRoot } from "./poracodeD import { createLocalIpcHandlers, showAddFilesDialog } from "./ipc/localHandlers"; import { registerIpcHandlers } from "./ipc/registerHandlers"; import { createSleepInhibitor } from "./sleepInhibitor"; +import { shouldPreventSystemSleep } from "./sleepPolicy"; import { installLocalFileProtocolHandler, registerLocalFileProtocolScheme, @@ -611,10 +612,12 @@ function requirePoracodePaths(): PoracodePaths { } function updatePowerSaveBlocker(): void { - const enabled = poracodePaths - ? readSharedSettingsFile(poracodePaths.settingsPath).preventSleepWhileWorking - : true; - sleepInhibitor.setActive(enabled && workingThreads.size > 0); + if (!poracodePaths) { + sleepInhibitor.setActive(workingThreads.size > 0); + return; + } + const settings = readSharedSettingsFile(poracodePaths.settingsPath); + sleepInhibitor.setActive(shouldPreventSystemSleep(settings, workingThreads.size)); } function handleSupervisorEventForSleep(event: SupervisorEvent): void { @@ -1058,6 +1061,7 @@ if (!hasSingleInstanceLock) { }, getBrowserPanelManager: () => browserPanelManager, notifySharedSettingsChanged: (settings) => { + updatePowerSaveBlocker(); mainWindow?.webContents.send(IPC_EVENT_CHANNELS.sharedSettingsChanged, settings); }, notifyRemoteAccessPairingChanged: (info) => { @@ -1211,6 +1215,7 @@ if (!hasSingleInstanceLock) { // The remote controller performs one bounded warm-up when enabled. // Recurring Git refreshes remain demand-driven by connected clients. + updatePowerSaveBlocker(); void controller.startIfEnabled(); initialMainWindow.once("ready-to-show", () => { diff --git a/src/main/sharedSettingsFile.test.ts b/src/main/sharedSettingsFile.test.ts index 144a02c83..3dea639bd 100644 --- a/src/main/sharedSettingsFile.test.ts +++ b/src/main/sharedSettingsFile.test.ts @@ -129,6 +129,7 @@ describe("sharedSettingsFile", () => { guiChatFontSize: 13, terminalPanelFontSize: 12, preventSleepWhileWorking: true, + remoteAccessPreventSleep: true, launchAtStartup: true, startMinimized: true, closeToTray: true, @@ -256,6 +257,7 @@ describe("sharedSettingsFile", () => { guiChatFontSize: 13, terminalPanelFontSize: 12, preventSleepWhileWorking: true, + remoteAccessPreventSleep: true, launchAtStartup: true, startMinimized: true, closeToTray: true, diff --git a/src/main/sleepInhibitor.test.ts b/src/main/sleepInhibitor.test.ts index 1560375ba..0d6ea4ce6 100644 --- a/src/main/sleepInhibitor.test.ts +++ b/src/main/sleepInhibitor.test.ts @@ -126,13 +126,7 @@ describe("createSleepInhibitor", () => { expect(spawnFn).toHaveBeenCalledTimes(1); expect(spawnFn).toHaveBeenCalledWith( "systemd-inhibit", - [ - "--what=sleep:idle", - "--who=Poracode", - "--why=Agent thread is working", - "--mode=block", - "cat", - ], + ["--what=sleep:idle", "--who=Poracode", "--why=Poracode is active", "--mode=block", "cat"], expect.objectContaining({ detached: false }), ); }); diff --git a/src/main/sleepInhibitor.ts b/src/main/sleepInhibitor.ts index 9e643cbbb..d1a2888a2 100644 --- a/src/main/sleepInhibitor.ts +++ b/src/main/sleepInhibitor.ts @@ -90,13 +90,7 @@ class SystemdInhibitor implements Inhibitor { try { child = this.spawnFn( "systemd-inhibit", - [ - "--what=sleep:idle", - "--who=Poracode", - "--why=Agent thread is working", - "--mode=block", - "cat", - ], + ["--what=sleep:idle", "--who=Poracode", "--why=Poracode is active", "--mode=block", "cat"], { stdio: ["pipe", "ignore", "ignore"], detached: false }, ); } catch (error) { diff --git a/src/main/sleepPolicy.test.ts b/src/main/sleepPolicy.test.ts new file mode 100644 index 000000000..fc18e7850 --- /dev/null +++ b/src/main/sleepPolicy.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from "vitest"; +import { shouldPreventSystemSleep } from "./sleepPolicy"; + +describe("shouldPreventSystemSleep", () => { + it("keeps the system awake for a working thread when enabled", () => { + expect( + shouldPreventSystemSleep( + { + preventSleepWhileWorking: true, + remoteAccessPreventSleep: false, + remoteAccessEnabled: false, + }, + 1, + ), + ).toBe(true); + }); + + it("keeps the system awake for enabled remote access independently of thread activity", () => { + expect( + shouldPreventSystemSleep( + { + preventSleepWhileWorking: false, + remoteAccessPreventSleep: true, + remoteAccessEnabled: true, + }, + 0, + ), + ).toBe(true); + }); + + it("allows sleep when each active reason is opted out", () => { + expect( + shouldPreventSystemSleep( + { + preventSleepWhileWorking: false, + remoteAccessPreventSleep: false, + remoteAccessEnabled: true, + }, + 1, + ), + ).toBe(false); + }); +}); diff --git a/src/main/sleepPolicy.ts b/src/main/sleepPolicy.ts new file mode 100644 index 000000000..4a67fc3c5 --- /dev/null +++ b/src/main/sleepPolicy.ts @@ -0,0 +1,16 @@ +import type { SharedSettings } from "@/shared/settings"; + +type SleepPolicySettings = Pick< + SharedSettings, + "preventSleepWhileWorking" | "remoteAccessPreventSleep" | "remoteAccessEnabled" +>; + +export function shouldPreventSystemSleep( + settings: SleepPolicySettings, + workingThreadCount: number, +): boolean { + const threadRequiresAwake = settings.preventSleepWhileWorking && workingThreadCount > 0; + const remoteAccessRequiresAwake = + settings.remoteAccessPreventSleep && settings.remoteAccessEnabled; + return threadRequiresAwake || remoteAccessRequiresAwake; +} diff --git a/src/renderer/locales/de/messages.po b/src/renderer/locales/de/messages.po index 2ece26a1f..e98510aad 100644 --- a/src/renderer/locales/de/messages.po +++ b/src/renderer/locales/de/messages.po @@ -5601,6 +5601,11 @@ msgstr "Poracode beim Start im Infobereich der Taskleiste belassen." msgid "Keep the system awake while any thread is actively working." msgstr "Halten Sie das System wach, während ein Thread aktiv arbeitet." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Das System aktiv halten, solange der Fernzugriff aktiviert ist." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Weiter warten" @@ -8090,6 +8095,11 @@ msgstr "Voreinstellungen" msgid "Press shortcut…" msgstr "Tastenkürzel drücken…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Ruhezustand bei Fernzugriff verhindern" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/en/messages.po b/src/renderer/locales/en/messages.po index 661737a0f..d656830b7 100644 --- a/src/renderer/locales/en/messages.po +++ b/src/renderer/locales/en/messages.po @@ -5601,6 +5601,11 @@ msgstr "Keep Poracode in the system tray when it launches at startup." msgid "Keep the system awake while any thread is actively working." msgstr "Keep the system awake while any thread is actively working." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Keep the system awake while remote access is enabled." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Keep waiting" @@ -8090,6 +8095,11 @@ msgstr "Presets" msgid "Press shortcut…" msgstr "Press shortcut…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Prevent sleep during remote access" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/es/messages.po b/src/renderer/locales/es/messages.po index 66f912b95..eda3451ba 100644 --- a/src/renderer/locales/es/messages.po +++ b/src/renderer/locales/es/messages.po @@ -5601,6 +5601,11 @@ msgstr "Mantener Poracode en la bandeja del sistema cuando se inicie automática msgid "Keep the system awake while any thread is actively working." msgstr "Mantener el sistema activo mientras cualquier hilo esté trabajando." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Mantén el sistema activo mientras el acceso remoto esté habilitado." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Seguir esperando" @@ -8090,6 +8095,11 @@ msgstr "Preajustes" msgid "Press shortcut…" msgstr "Pulsa el atajo…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Impedir la suspensión durante el acceso remoto" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/fr/messages.po b/src/renderer/locales/fr/messages.po index b4c500dd9..9aa8e7d8e 100644 --- a/src/renderer/locales/fr/messages.po +++ b/src/renderer/locales/fr/messages.po @@ -5601,6 +5601,11 @@ msgstr "Garder Poracode dans la zone de notification lors de son lancement au d msgid "Keep the system awake while any thread is actively working." msgstr "Gardez le système éveillé pendant qu'un thread fonctionne activement." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Garder le système éveillé tant que l’accès à distance est activé." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Continuer à attendre" @@ -8089,6 +8094,11 @@ msgstr "Préréglages" msgid "Press shortcut…" msgstr "Appuyez sur le raccourci…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Empêcher la mise en veille pendant l’accès à distance" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/ja/messages.po b/src/renderer/locales/ja/messages.po index 13810d739..fcf0062fe 100644 --- a/src/renderer/locales/ja/messages.po +++ b/src/renderer/locales/ja/messages.po @@ -5600,6 +5600,11 @@ msgstr "スタートアップ時は Poracode をシステムトレイに格納 msgid "Keep the system awake while any thread is actively working." msgstr "スレッドがアクティブに動作している間は、システムを起動したままにします。" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "リモートアクセスが有効な間、システムをスリープさせません。" + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "待機を続ける" @@ -8088,6 +8093,11 @@ msgstr "プリセット" msgid "Press shortcut…" msgstr "ショートカットを押してください…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "リモートアクセス中のスリープを防止" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/ko/messages.po b/src/renderer/locales/ko/messages.po index 7c3ecdbcc..e9b763bb0 100644 --- a/src/renderer/locales/ko/messages.po +++ b/src/renderer/locales/ko/messages.po @@ -5601,6 +5601,11 @@ msgstr "시작 시 Poracode를 시스템 트레이에 둡니다." msgid "Keep the system awake while any thread is actively working." msgstr "스레드가 활발하게 작동하는 동안 시스템을 활성 상태로 유지합니다." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "원격 액세스가 활성화된 동안 시스템이 절전 모드로 전환되지 않도록 합니다." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "계속 기다리기" @@ -8090,6 +8095,11 @@ msgstr "프리셋" msgid "Press shortcut…" msgstr "단축키를 누르세요…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "원격 액세스 중 절전 모드 방지" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/pl/messages.po b/src/renderer/locales/pl/messages.po index 5776ed636..69bc0f3c6 100644 --- a/src/renderer/locales/pl/messages.po +++ b/src/renderer/locales/pl/messages.po @@ -5601,6 +5601,11 @@ msgstr "Po uruchomieniu przy starcie pozostaw Poracode w zasobniku systemowym." msgid "Keep the system awake while any thread is actively working." msgstr "Utrzymuj system w stanie czuwania, gdy dowolny wątek aktywnie działa." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Utrzymuj system w stanie aktywnym, gdy dostęp zdalny jest włączony." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Czekaj dalej" @@ -8090,6 +8095,11 @@ msgstr "Ustawienia predefiniowane" msgid "Press shortcut…" msgstr "Naciśnij skrót…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Zapobiegaj uśpieniu podczas dostępu zdalnego" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/pt-BR/messages.po b/src/renderer/locales/pt-BR/messages.po index 1eaa880e5..a7d1126cb 100644 --- a/src/renderer/locales/pt-BR/messages.po +++ b/src/renderer/locales/pt-BR/messages.po @@ -5601,6 +5601,11 @@ msgstr "Manter o Poracode na bandeja do sistema quando ele for iniciado com o Wi msgid "Keep the system awake while any thread is actively working." msgstr "Mantém o sistema ativo enquanto qualquer thread estiver trabalhando ativamente." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Mantenha o sistema ativo enquanto o acesso remoto estiver habilitado." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Continuar aguardando" @@ -8090,6 +8095,11 @@ msgstr "Predefinições" msgid "Press shortcut…" msgstr "Pressione o atalho…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Impedir suspensão durante o acesso remoto" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/ru/messages.po b/src/renderer/locales/ru/messages.po index e78d038dc..0dcfe0ede 100644 --- a/src/renderer/locales/ru/messages.po +++ b/src/renderer/locales/ru/messages.po @@ -5601,6 +5601,11 @@ msgstr "При запуске вместе с системой оставлят msgid "Keep the system awake while any thread is actively working." msgstr "Не давать системе засыпать, пока хотя бы один тред активно работает." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Не переводить систему в спящий режим, пока включён удалённый доступ." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Продолжить ожидание" @@ -8090,6 +8095,11 @@ msgstr "Пресеты" msgid "Press shortcut…" msgstr "Нажмите сочетание клавиш…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Запрещать спящий режим при удалённом доступе" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/tr/messages.po b/src/renderer/locales/tr/messages.po index 6e10fe077..8c492c14b 100644 --- a/src/renderer/locales/tr/messages.po +++ b/src/renderer/locales/tr/messages.po @@ -5601,6 +5601,11 @@ msgstr "Başlangıçta açıldığında Poracode'u sistem tepsisinde tutun." msgid "Keep the system awake while any thread is actively working." msgstr "Herhangi bir konu aktif olarak çalışırken sistemi uyanık tutun." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Uzaktan erişim etkinken sistemi uyanık tutun." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Beklemeye devam et" @@ -8090,6 +8095,11 @@ msgstr "Hazır ayarlar" msgid "Press shortcut…" msgstr "Kısayola basın…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Uzaktan erişim sırasında uyku modunu engelle" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/uk/messages.po b/src/renderer/locales/uk/messages.po index d46a2201b..547693d50 100644 --- a/src/renderer/locales/uk/messages.po +++ b/src/renderer/locales/uk/messages.po @@ -5601,6 +5601,11 @@ msgstr "Під час запуску разом із системою залиш msgid "Keep the system awake while any thread is actively working." msgstr "Не давати системі засинати, поки будь-який тред активно працює." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Не переводити систему в режим сну, доки ввімкнено віддалений доступ." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Продовжити очікування" @@ -8090,6 +8095,11 @@ msgstr "Пресети" msgid "Press shortcut…" msgstr "Натисніть комбінацію клавіш…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Запобігати сну під час віддаленого доступу" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/vi/messages.po b/src/renderer/locales/vi/messages.po index 569dd4750..f59dcde15 100644 --- a/src/renderer/locales/vi/messages.po +++ b/src/renderer/locales/vi/messages.po @@ -5601,6 +5601,11 @@ msgstr "Giữ Poracode trong khay hệ thống khi ứng dụng khởi chạy c msgid "Keep the system awake while any thread is actively working." msgstr "Giữ cho hệ thống luôn hoạt động trong khi bất kỳ luồng nào đang hoạt động tích cực." +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "Giữ hệ thống luôn hoạt động khi truy cập từ xa được bật." + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "Tiếp tục chờ" @@ -8090,6 +8095,11 @@ msgstr "Cấu hình sẵn" msgid "Press shortcut…" msgstr "Nhấn phím tắt…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "Ngăn chế độ ngủ khi truy cập từ xa" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/locales/zh-CN/messages.po b/src/renderer/locales/zh-CN/messages.po index 3c3210a11..b63b3f3ac 100644 --- a/src/renderer/locales/zh-CN/messages.po +++ b/src/renderer/locales/zh-CN/messages.po @@ -5601,6 +5601,11 @@ msgstr "开机启动时将 Poracode 保持在系统托盘中。" msgid "Keep the system awake while any thread is actively working." msgstr "当任何线程正在工作时保持系统唤醒状态(不休眠)。" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Keep the system awake while remote access is enabled." +msgstr "启用远程访问时保持系统唤醒。" + #: src/renderer/components/startup/StartupRecoveryScreen.tsx msgid "Keep waiting" msgstr "继续等待" @@ -8089,6 +8094,11 @@ msgstr "预设" msgid "Press shortcut…" msgstr "请按快捷键…" +#: src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +#: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +msgid "Prevent sleep during remote access" +msgstr "防止远程访问期间休眠" + #: src/renderer/views/SettingsOverlay/parts/GeneralSettings.tsx #: src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts msgid "Prevent sleep while working" diff --git a/src/renderer/state/sharedSettingsStore.ts b/src/renderer/state/sharedSettingsStore.ts index e6771c3b4..d0b564349 100644 --- a/src/renderer/state/sharedSettingsStore.ts +++ b/src/renderer/state/sharedSettingsStore.ts @@ -80,6 +80,7 @@ interface SharedSettingsState extends SharedSettings { setGuiChatFontSize: (value: number) => void; setTerminalPanelFontSize: (value: number) => void; setPreventSleepWhileWorking: (value: boolean) => void; + setRemoteAccessPreventSleep: (value: boolean) => void; setLaunchAtStartup: (value: boolean) => void; setStartMinimized: (value: boolean) => void; setCloseToTray: (value: boolean) => void; @@ -438,6 +439,10 @@ export const useSharedSettings = create()((set, get) => ({ set({ preventSleepWhileWorking }); persistSettings(selectSharedSettings(get())); }, + setRemoteAccessPreventSleep: (remoteAccessPreventSleep) => { + set({ remoteAccessPreventSleep }); + persistSettings(selectSharedSettings(get())); + }, setLaunchAtStartup: (launchAtStartup) => { if (get().launchAtStartup === launchAtStartup) return; set({ launchAtStartup }); @@ -874,6 +879,7 @@ function selectSharedSettings(state: SharedSettingsState): SharedSettingsInput { guiChatFontSize: state.guiChatFontSize, terminalPanelFontSize: state.terminalPanelFontSize, preventSleepWhileWorking: state.preventSleepWhileWorking, + remoteAccessPreventSleep: state.remoteAccessPreventSleep, launchAtStartup: state.launchAtStartup, startMinimized: state.startMinimized, closeToTray: state.closeToTray, diff --git a/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.test.tsx b/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.test.tsx index 162c01358..f818b5874 100644 --- a/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.test.tsx +++ b/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.test.tsx @@ -18,6 +18,8 @@ const { bridgeMock, pairingChangedState, sharedSettingsState, toDataURLMock } = listener: null as ((info: RemoteAccessPairingInfo) => void) | null, }, sharedSettingsState: { + remoteAccessPreventSleep: true, + setRemoteAccessPreventSleep: vi.fn<(enabled: boolean) => void>(), remoteAccessTailscaleHttps: true, remoteAccessAdvertisedUrl: "", remotePushEnabled: true, @@ -86,6 +88,16 @@ describe("RemoteAccessSettings", () => { toDataURLMock.mockResolvedValue("data:image/png;base64,test"); }); + it("allows preventing sleep during remote access independently", () => { + render(); + + const toggle = screen.getByRole("switch", { name: "Prevent sleep during remote access" }); + expect(toggle).toBeChecked(); + fireEvent.click(toggle); + + expect(sharedSettingsState.setRemoteAccessPreventSleep).toHaveBeenCalledWith(false); + }); + it("switches the displayed endpoint and QR code from Tailscale to local", async () => { render(); diff --git a/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx b/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx index 1a56b06a3..ee2217d6e 100644 --- a/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx +++ b/src/renderer/views/SettingsOverlay/parts/RemoteAccessSettings.tsx @@ -709,6 +709,10 @@ function RemotePushSection() { export function RemoteAccessSettings() { const { t } = useLingui(); + const remoteAccessPreventSleep = useSharedSettings((state) => state.remoteAccessPreventSleep); + const setRemoteAccessPreventSleep = useSharedSettings( + (state) => state.setRemoteAccessPreventSleep, + ); const [state, setState] = useState({ info: null, error: null, @@ -857,6 +861,18 @@ export function RemoteAccessSettings() { ) : null } > + Keep the system awake while remote access is enabled.} + > + + + {isLoading ? (
diff --git a/src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts b/src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts index e0b9f68ee..d05d5583e 100644 --- a/src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts +++ b/src/renderer/views/SettingsOverlay/parts/settingsSearchIndex.ts @@ -137,6 +137,16 @@ export const SETTINGS_SEARCH_INDEX: readonly SettingsSearchEntry[] = [ desktopOnly: true, }, + // Remote Access + { + section: "remoteAccess", + anchor: "remoteAccess.preventSleep", + title: msg`Prevent sleep during remote access`, + description: msg`Keep the system awake while remote access is enabled.`, + keywords: "sleep awake wake idle power server connection", + desktopOnly: true, + }, + // Audio { section: "audio", diff --git a/src/shared/settings.test.ts b/src/shared/settings.test.ts index 45bb97969..d901765c4 100644 --- a/src/shared/settings.test.ts +++ b/src/shared/settings.test.ts @@ -8,6 +8,14 @@ describe("shared settings defaults", () => { expect(defaultSharedSettings.notificationFilter).toBe("all"); }); + it("prevents sleep during remote access by default and preserves opt-outs", () => { + expect(defaultSharedSettings.remoteAccessPreventSleep).toBe(true); + expect(normalizeSharedSettings({}).remoteAccessPreventSleep).toBe(true); + expect( + normalizeSharedSettings({ remoteAccessPreventSleep: false }).remoteAccessPreventSleep, + ).toBe(false); + }); + it("enables Crossagents as the standing MCP default and preserves opt-outs", () => { expect(defaultSharedSettings.enabledMcpServers.crossagents).toBe(true); expect(normalizeSharedSettings({}).enabledMcpServers.crossagents).toBe(true); diff --git a/src/shared/settings.ts b/src/shared/settings.ts index be934910d..4cf00a011 100644 --- a/src/shared/settings.ts +++ b/src/shared/settings.ts @@ -294,6 +294,8 @@ export const sharedSettingsSchema = z.object({ terminalPanelFontSize: z.number().int().min(8).max(20), /** Prevent OS sleep while any thread is actively working. */ preventSleepWhileWorking: z.boolean(), + /** Prevent OS sleep while the desktop remote access server is enabled. */ + remoteAccessPreventSleep: z.boolean(), /** Register Poracode to launch automatically when the user signs in to Windows. */ launchAtStartup: z.boolean(), /** Keep the main window hidden when Poracode is launched automatically at sign-in. */ @@ -588,6 +590,7 @@ export const defaultSharedSettings: SharedSettings = { guiChatFontSize: 13, terminalPanelFontSize: 12, preventSleepWhileWorking: true, + remoteAccessPreventSleep: true, launchAtStartup: true, startMinimized: true, closeToTray: true, From e67357c22b060e6590d40653a2d092e0872f9ecb Mon Sep 17 00:00:00 2001 From: Serhii Vecherenko Date: Sat, 1 Aug 2026 21:35:45 -0700 Subject: [PATCH 2/3] chore: format dev terminal store --- src/renderer/state/devTerminalStore.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/state/devTerminalStore.ts b/src/renderer/state/devTerminalStore.ts index 9252f0ee2..ce7c98229 100644 --- a/src/renderer/state/devTerminalStore.ts +++ b/src/renderer/state/devTerminalStore.ts @@ -110,7 +110,12 @@ export const useDevTerminalStore = create focusRequestId: state.focusRequestId + 1, })), closePanel: () => - set({ isOpen: false, explicitlyOpened: false, activeProjectId: null, activeWorktreePath: null }), + set({ + isOpen: false, + explicitlyOpened: false, + activeProjectId: null, + activeWorktreePath: null, + }), setActiveProject: (projectId) => { const tabs = get().tabs.filter((t) => t.projectId === projectId); From 3ba4165722ae83abdfb1203f1bf2ab5bd701a28e Mon Sep 17 00:00:00 2001 From: Serhii Vecherenko Date: Sat, 1 Aug 2026 22:16:40 -0700 Subject: [PATCH 3/3] test: await async ACP registry content --- .../SettingsOverlay/parts/AcpRegistrySettings.test.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/views/SettingsOverlay/parts/AcpRegistrySettings.test.tsx b/src/renderer/views/SettingsOverlay/parts/AcpRegistrySettings.test.tsx index d26c10dd6..b52e27f8b 100644 --- a/src/renderer/views/SettingsOverlay/parts/AcpRegistrySettings.test.tsx +++ b/src/renderer/views/SettingsOverlay/parts/AcpRegistrySettings.test.tsx @@ -559,9 +559,9 @@ describe("AcpRegistrySettings", () => { render(); await screen.findByRole("heading", { name: "Agent Registry" }); - const grokCard = screen - .getByText(/First-class Grok Build CLI integration/u) - .closest(".rounded-lg"); + const grokCard = (await screen.findByText(/First-class Grok Build CLI integration/u)).closest( + ".rounded-lg", + ); expect(grokCard).toBeTruthy(); expect(within(grokCard as HTMLElement).queryByText(/Windows is not supported/u)).toBeNull();