#17330
feat(cli): persist tray preferences and expose autostart controls
There is currently no supported way to disable the system tray icon — and no way to make autostart boot without it — from the GUI or from any persisted configuration. I checked before filing:
- Dashboard (
src/**): zero tray references. No setting, page, or management-API route can see or change the tray. omniroute serve:--tray/--no-trayexist, but they are per-invocation flags; nothing is remembered.omniroute tray hide|show|quit(bin/cli/commands/tray.mjs): all three are stubs that onlyprocess.stderr.writean advice line.hidesays "Send SIGUSR1 to the serve process to toggle the tray" — butSIGUSR1has no handler anywhere in the repo (it occurs only inside that message).omniroute autostart enable: accepts no options and hardcodes the tray into the startup entry:- Windows VBS:
buildWinVbsContent→buildServeExecLine(cliPath, { tray: true })(bin/cli/tray/autostart.mjs:378) - macOS LaunchAgent plist:
<string>--tray</string>(:303,:378) - Linux is inconsistent between its own two paths: systemd passes
{ tray: false }("Foreground serve only",:139) while the XDG desktop entry passes{ tray: true }(:158)
- Windows VBS:
docs/reference/ENVIRONMENT.md: no tray-related variable exists.- Electron desktop app: the tray is always created (
electron/main.js::createTray); the only related persisted preference is the "When Dashboard Closes" behavior.
Why this matters beyond cosmetics
- The tray chain is what pulls in the
--traylauncher machinery: a hidden VBS → detached worker spawnedstdio: "ignore"→ asystray2lazynpm install→ the readiness deadline. That's the whole silent-failure surface from #15464, and on 3.8.52 the worker can still be taskkilled at the deadline when the tray never becomes ready (#17315 — follow-up filed, with two concrete loader bugs). With tray in a user's hands, that entire path is on by design wherever autostart is used. - The tray menu is also where autostart is "toggled" from (
traySystray.mjs:84), but the sameenable()always regenerates the entry with tray — so a CLI user who doesn't want the icon has no supported path to an autostart that serves headless-with-dashboard instead of with a tray. The report in #15464 ("Dropping--trayfrom the generated VBS makes autostart work reliably") is exactly that unsupported path today.
Proposed shape
A single persisted preference, consulted by both serve and every autostart generator:
- CLI
omniroute autostart enable --no-tray/--tray(explicit per-run override of the stored preference)- a documented env var (e.g.
OMNIROUTE_TRAY=0) inENVIRONMENT.md
- Dashboard
- a Settings card with two toggles: system tray icon and start at login — reading/writing the same preference via
/api/*, so CLI and GUI stay in sync - (optional, nice: show the actual runtime state — whether a server/tray process is actually running — instead of only "the startup file exists", which is all
autostart statuschecks today)
- a Settings card with two toggles: system tray icon and start at login — reading/writing the same preference via
- Consistency
- one mechanism for VBS, plist, systemd and XDG (systemd's "Foreground serve only" choice vs XDG's
--traylooks like an accident rather than intent)
- one mechanism for VBS, plist, systemd and XDG (systemd's "Foreground serve only" choice vs XDG's
tray hide- either implement the
SIGUSR1toggle it documents (or havehidecall the management API) or remove the subcommand — right now all three subcommands mislead
- either implement the
The no-tray autostart variant is already fully supported by the code (plain omniroute serve --no-open boots the same server, and it is exactly the Linux systemd mode); only the wiring to choose it is missing, so this should be a small PR once the preference plumbing exists.
Reference: #15464 (the original autostart bug) and #17315 (loader bugs that keep tray-era autostart broken in 3.8.52 — a persisted no-tray preference also sidesteps that failure mode entirely).
Confirmed on the current development branch:
serveaccepts per-invocation tray flags, butautostart enabledoes not accept or persist that choice. The Windows, macOS and XDG generators enable the tray, while the systemd service remains headless. Thetray hidemessage also recommends a SIGUSR1 toggle that is not implemented; Node reserves that signal for the debugger, so that guidance needs correcting.This request is broader than the loader fixes in #17328. We are tracking it in separate increments: persisted CLI/autostart preferences, dashboard controls backed by the same settings, and explicit control of an already-running tray. Headless service operation must remain supported. The current macOS/systemd status checks already inspect OS state in addition to files, so those should be preserved. This issue remains open; no implementation of the full requested scope is claimed.