feat(desktop): add auto-start on login and silent-start with tray icon(#2573)#2774
feat(desktop): add auto-start on login and silent-start with tray icon(#2573)#2774enen323 wants to merge 4 commits into
Conversation
76b6211 to
224668b
Compare
…esengine#2573) Implement OS-level auto-start registration (Windows registry / macOS LaunchAgent / Linux autostart), system tray icon for hidden-window start(Windows Shell_NotifyIconW), and console-window suppression for MCP subprocesses on Windows GUI builds.
…esengine#2573) Implement OS-level auto-start registration (Windows registry / macOS LaunchAgent / Linux autostart), system tray icon for hidden-window start(Windows Shell_NotifyIconW), and console-window suppression for MCP subprocesses on Windows GUI builds.
…asonix into t-issue#2573
SivanCola
left a comment
There was a problem hiding this comment.
Thanks for taking this on — the cross-platform coverage is solid and the overall design is sound. In particular, deriving silent-start from the persisted desktop-settings.json (rather than a launch flag) is the right call, which is why registering the bare os.Executable() path for auto-start is correct. The persistence surface is also safe: HKCU (no elevation), exec.Command with an argv array (no shell injection), and removable via disable. I also confirmed this does not touch any prompt-cache-sensitive surface (tool schema bytes/order, provider serialization, system prompt).
Before merging, please address the following.
Blocking
-
Tray "Quit" doesn't quit the app. In
tray_windows.go, thecmdQuitbranch callsPostQuitMessage(0)(which only exits the tray's own message loop) followed by an emptygo func(){}. The app process keeps running with no window — clicking Quit just removes the tray icon. It should callwailsRuntime.Quit(t.ctx). -
Data race in
desktop_settings.go.setDesktopSettingsreads the package-globalds.AutoStartwithout holdingdsMu(if s.AutoStart != ds.AutoStart), whilegetDesktopSettings/loadDesktopSettingsboth guarddswith the mutex.go test -racewill flag this — please read the previous value inside the lock. -
No tests, and the path-semantics change is untested on the platform it affects. This PR adds zero
_test.gocoverage. TheresolveIn/resolveCustomPathschanges only alter behavior on Windows (where/fooand\fooare now treated as absolute), but the existingTestResolveIncases are all platform-neutral, so Linux CI never exercises the newos.IsPathSeparator(p[0])branch. Please add focused regression tests for: auto-start register/unregister path construction, the desktop-settings persistence round-trip, and the new Windows-rooted path branch. -
Scope creep. The
workspace.go/skill.gofilepath.IsAbsfixes are unrelated to auto-start. They are a defensible Windows path-consistency fix (and Linux behavior is unchanged), but bundling them here makes the PR harder to review and they ship without tests. Please either split them into a dedicated PR, or keep them here with the regression test from (3) plus a short comment explaining the Windows rationale. For the record,resolveInhonors absolute paths by design (the write-confiner, notresolveIn, enforces the workspace boundary), so this is not a new escape — but it does widen what counts as "absolute" on Windows, which is exactly why it deserves an explicit test.
Suggestions (non-blocking)
toggleWindowonly ever shows the window (the comment admits it cannot hide); tracking visibility would make the left-click toggle behave as its name implies.removeIcondeletes the icon withoutNIF_GUID, but it was added with a GUID. On Windows 10+ the delete may not match the registered identity and can leave a stale icon — include the GUID in the deleteNOTIFYICONDATA.- The registered exe path is not quoted/escaped (Windows registry value, macOS plist XML, Linux desktop
Exec=). Low risk since the path comes fromos.Executable(), but quoting/escaping is more robust for paths containing spaces or special characters.
Also, the PR is currently CONFLICTING against main-v2 — please rebase onto the latest origin/main-v2.
Once these are addressed and CI stays green, I'll be happy to merge this into main-v2.
esengine
left a comment
There was a problem hiding this comment.
#2573 is a real ask and the Win32 tray work is better than most hand-rolled attempts (icon parsing, GUID, TaskbarCreated re-add). Blockers:
- Tray Quit never quits the app:
wndProc'scmdQuitpostsPostQuitMessageto the tray loop, and the follow-up goroutine contains only comments —wailsRuntime.Quit(t.ctx)is never called. Quit kills the icon and leaves the app running. - Quote the exe path written to the Run key — unquoted paths with spaces fail to launch.
setDesktopSettingsreadsds.AutoStartwithout holdingdsMu— data race.- Split the unrelated internal/skill + workspace path changes into their own PR; delete the commented-out
NIM_SETVERSIONline. toggleWindowalways shows and never hides (the comment admits it) — fine to defer, but say so in the description.
Both settings defaulting to off is the right call. Rebase onto current main-v2, push, and we'll approve-and-run fork CI.
Implement OS-level auto-start registration (Windows registry / macOS LaunchAgent / Linux autostart), system tray icon for hidden-window start(Windows Shell_NotifyIconW), and console-window suppression for MCP subprocesses on Windows GUI builds.