Skip to content

feat(sleep-guard): keep the host device awake while IDBots is working - #13

Open
WuFenG-Hub wants to merge 2 commits into
metaid-developers:mainfrom
WuFenG-Hub:feat/sleep-guard
Open

feat(sleep-guard): keep the host device awake while IDBots is working#13
WuFenG-Hub wants to merge 2 commits into
metaid-developers:mainfrom
WuFenG-Hub:feat/sleep-guard

Conversation

@WuFenG-Hub

Copy link
Copy Markdown

What

Keep the host device awake while IDBots is actively working, so OS sleep never
interrupts running harness work (bot/cowork sessions, scheduled tasks, nightly
dreams). The main process engages Electron's powerSaveBlocker
(prevent-app-suspension) only while at least one work source is active,
and releases it as soon as everything is idle — the OS sleep policy is
untouched outside actual work.

Changes

  • src/main/sleepGuard.ts (new) — pure, dependency-injected guard: policy
    (evaluateSleepGuardWork) + idempotent stateful SleepGuard class. No direct
    electron import, fully unit-testable.
  • src/main/main.ts — wiring: singleton getSleepGuard(), recomputeSleepGuard()
    over the live work sources (cowork sessions via getActiveSessionIds(),
    scheduled tasks via new Scheduler.getActiveTaskIds(), dreams via
    getDreamingBotIds()), instant triggers on cowork session start/stop and
    runner complete/error, a 20s periodic safety refresh (self-heal), IPC
    powerGuard:status handle + powerGuard:changed broadcast, and release on
    app cleanup.
  • src/main/preload.ts + src/renderer/types/electron.d.tspowerGuard
    API surface for the harness frontend.
  • src/renderer/components/SleepGuardBadge.tsx (new) + Sidebar.tsx — amber
    "防休眠中" badge shown while the guard is engaged, hidden when idle, tooltip
    lists the active sources.
  • tests/sleepGuard.test.mjs (new) — 8 unit tests, all pass (fake blocker,
    pure DI, no Electron stub needed).
  • scripts/sleep-guard-real-host-check.cjs (new) — real-Electron closed-loop
    check driving the compiled module with the real powerSaveBlocker.

Also fixes a pre-existing lint blocker on main: a stale unused
eslint-disable-next-line react-hooks/exhaustive-deps in
MetaBotEditTabs.tsx that failed npm run lint (0-warnings gate).

Verification (all actually run, not code-assertion only)

  • npm run lint — 0 errors, 0 warnings
  • npm run compile:electron + npm run build — pass
  • node --test tests/sleepGuard.test.mjs — 8/8 pass
  • Real-host closed loop (node_modules/.bin/electron scripts/sleep-guard-real-host-check.cjs on macOS):
    • 7/7 checks pass, both directions (idle → engage → idle → re-engage → dispose)
    • While engaged, pmset -g assertions shows the OS-level
      PreventUserIdleSystemSleep assertion — system-level evidence, not an
      in-process self-report
    • After release, the assertion is gone

Notes / honest scope

  • Work sources implemented: cowork, scheduledTask, dream. A dedicated
    groupTask source (orchestration daemon) has no ready API on main
    (only a raw DB query in cognitiveOrchestrator); orchestration turns mostly
    run inside cowork sessions, which are already covered. An agentGame source
    is not applicable: that module does not exist on the main baseline. The
    20s refresh self-heals anything event-driven updates miss.
  • Full app-level UI walk (launching the app and watching the badge during a
    live session) was not performed in this pass; the closed-loop script drives
    the same code path against the real runtime, and the badge is a thin
    renderer subscription to the verified IPC surface.

WuFenG added 2 commits August 12, 2026 13:39
Prevents OS sleep from interrupting running harness work. The main process
engages Electron's powerSaveBlocker (prevent-app-suspension) only while at
least one work source is active — cowork sessions, running scheduled tasks,
nightly dreams — and releases it as soon as everything is idle.

- src/main/sleepGuard.ts: pure DI policy + stateful guard (unit-testable)
- main.ts wiring: singleton, 20s self-healing refresh, instant triggers on
  session start/stop and runner complete/error, IPC powerGuard:status and
  powerGuard:changed broadcast, dispose on cleanup
- preload + electron.d.ts: powerGuard API for the harness frontend
- Sidebar SleepGuardBadge: shown while engaged, hidden when idle
- tests/sleepGuard.test.mjs: 8/8 pass (fake blocker, pure DI)
- scripts/sleep-guard-real-host-check.cjs: real-Electron closed loop, 7/7
  pass incl. macOS pmset assertion PreventUserIdleSystemSleep (both directions)

Also removes a stale unused eslint-disable directive in MetaBotEditTabs.tsx
that broke npm run lint on the main baseline (lint-blocker fix).
- keep powerGuard:status IPC handler alongside upstream store:changed broadcast
- keep startSleepGuardRefresh() in window ready-to-show; upstream moved tray/scheduler
  init into didInitAppOnce single-run block
- keep both Sidebar imports (SleepGuardBadge + upstream BackgroundTasksBadge)
- drop redundant eslint-disable in opcatInscribe.ts (upstream baseline lint blocker)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant