feat(desktop): add PySide6 shell and canonical tray #98

Merged
lost-rob0t merged 12 commits from feature/desktop-shell into master 2026-08-12 16:55:16 +00:00
lost-rob0t commented 2026-08-12 15:57:00 +00:00 (Migrated from github.com)

Closes #84.

Summary

Adds the first native Zara desktop shell on top of the RuntimeHost boundary from #83.

  • add a pure coarse desktop status reducer over generic runtime events
  • add one canonical QApplication/controller creation path with setQuitOnLastWindowClosed(False)
  • add a capability-derived QSystemTrayIcon with Open Zara, live status, Restart Runtime, Diagnostics, and Quit Zara
  • keep the tray nonfatal: when no tray host is available, Zara opens a reachable status window instead of becoming an invisible background process
  • add a minimal close-to-hide status window with restart/diagnostics hooks; full chat remains #85
  • map tray/window actions to RuntimeHost commands through QtRuntimeBridge rather than reaching into runtime internals
  • make explicit Quit wait for the runtime shutdown receipt before closing the UI; if the runtime is already unavailable, Quit still terminates the desktop shell cleanly
  • add zara-desktop=zara.desktop.app:main
  • reuse one QApplication/controller on repeated create_application() calls so desktop bootstrap does not create duplicate canonical trays
  • update the existing QtRuntimeBridge tests to use QApplication under the offscreen Qt platform, preventing an earlier QCoreApplication from poisoning later widget tests

Current tray scope

This P0 tray intentionally exposes only capabilities that exist now:

Open Zara

Status: <runtime state>

Restart Runtime
Diagnostics

Quit Zara

Voice, chats, Pets, timers, context, etc. are not dead menu items; their owning issues will register/integrate them as those capabilities land.

Lifecycle

zara-desktop
    |
QApplication (quitOnLastWindowClosed = false)
    |
DesktopController
   / \
Tray  StatusWindow
   \ /
QtRuntimeBridge
    |
RuntimeHost

Closing the status window hides it. Explicit Quit sends ShutdownRuntime, waits for the matching command receipt, closes the Qt bridge/tray/window, then quits QApplication. RuntimeHost already handles Quit during startup/restart from #83.

Testing

Adds deterministic coverage for:

  • runtime-event -> desktop-state reduction
  • close-to-hide versus explicit window close
  • tray action and left-click signal wiring
  • tray status/tooltip mapping and nonfatal tray availability probe
  • no-tray fallback keeping Zara reachable
  • one reducer driving tray and window state
  • duplicate restart suppression
  • diagnostics hook
  • explicit quit waiting for runtime shutdown completion
  • explicit quit when runtime is already unavailable
  • one QApplication/controller/canonical tray creation path
  • quitOnLastWindowClosed(False)

The repository's GitHub Actions / nix develop -c bash scripts/test-all.sh gate is authoritative because the user's /home/unseen/Documents/Projects/ checkout is not mounted in this execution environment.

Closes #84. ## Summary Adds the first native Zara desktop shell on top of the RuntimeHost boundary from #83. - add a pure coarse desktop status reducer over generic runtime events - add one canonical `QApplication`/controller creation path with `setQuitOnLastWindowClosed(False)` - add a capability-derived `QSystemTrayIcon` with Open Zara, live status, Restart Runtime, Diagnostics, and Quit Zara - keep the tray nonfatal: when no tray host is available, Zara opens a reachable status window instead of becoming an invisible background process - add a minimal close-to-hide status window with restart/diagnostics hooks; full chat remains #85 - map tray/window actions to RuntimeHost commands through `QtRuntimeBridge` rather than reaching into runtime internals - make explicit Quit wait for the runtime shutdown receipt before closing the UI; if the runtime is already unavailable, Quit still terminates the desktop shell cleanly - add `zara-desktop=zara.desktop.app:main` - reuse one QApplication/controller on repeated `create_application()` calls so desktop bootstrap does not create duplicate canonical trays - update the existing QtRuntimeBridge tests to use `QApplication` under the offscreen Qt platform, preventing an earlier `QCoreApplication` from poisoning later widget tests ## Current tray scope This P0 tray intentionally exposes only capabilities that exist now: ```text Open Zara Status: <runtime state> Restart Runtime Diagnostics Quit Zara ``` Voice, chats, Pets, timers, context, etc. are not dead menu items; their owning issues will register/integrate them as those capabilities land. ## Lifecycle ```text zara-desktop | QApplication (quitOnLastWindowClosed = false) | DesktopController / \ Tray StatusWindow \ / QtRuntimeBridge | RuntimeHost ``` Closing the status window hides it. Explicit Quit sends `ShutdownRuntime`, waits for the matching command receipt, closes the Qt bridge/tray/window, then quits QApplication. RuntimeHost already handles Quit during startup/restart from #83. ## Testing Adds deterministic coverage for: - runtime-event -> desktop-state reduction - close-to-hide versus explicit window close - tray action and left-click signal wiring - tray status/tooltip mapping and nonfatal tray availability probe - no-tray fallback keeping Zara reachable - one reducer driving tray and window state - duplicate restart suppression - diagnostics hook - explicit quit waiting for runtime shutdown completion - explicit quit when runtime is already unavailable - one QApplication/controller/canonical tray creation path - `quitOnLastWindowClosed(False)` The repository's GitHub Actions / `nix develop -c bash scripts/test-all.sh` gate is authoritative because the user's `/home/unseen/Documents/Projects/` checkout is not mounted in this execution environment.
Sign in to join this conversation.
No description provided.