AprilNEA / AprilNEA/OpenLogi

Windows: a running older agent is never replaced, stranding the GUI on "waiting for the agent"

Open
#673 1 comment 0 reactions 0 assignees View on GitHub
platform: windows type: bug
Dominant language
Rust
Stars
21k
Forks
675
Avg merge
2d 5h
Merged PRs (30d)
172

Description

On Windows a newer agent cannot take over from an older one holding
`agent.lock`, so the GUI waits forever for a replacement that never arrives.

This is the same shape as #621 / #644 — a leftover process holding a lock it
cannot speak the current protocol through — except those were the Actions Ring
overlay and were fixed by #645. The agent has the same gap on Windows, and
nothing closes it there.

## What happens

An installed OpenLogi was running (`%LOCALAPPDATA%\Programs\OpenLogi`, IPC
protocol 17) while a newer build started from another directory (protocol 18):

```
WARN openlogi_gui::ipc_client: agent IPC protocol is older —
waiting for the agent to be replaced agent=17 gui=18
INFO openlogi_gui::ipc_client: agent not running — launched it
path=...\openlogi-agent.exe
INFO openlogi_agent: another openlogi-agent is already running — exiting
path=...\.config\openlogi\agent.lock
```

The GUI's spawn retry starts the new agent, the new agent loses the singleton
lock and exits, and the loop repeats. The only way out is killing the old agent
by hand.

## Why

`takeover.rs` exists for exactly this, but its Windows arm is a deliberate no-op
(`crates/openlogi-agent/src/takeover.rs:147`):

```rust
/// No Windows release has ever shipped (or auto-started) the agent, so there
/// is no pre-watcher population to migrate; from the first shipped build
/// onward, `self_restart` exits on update and the GUI's spawn retry starts
/// the new binary.
#[cfg(windows)]
fn replace_stale() -> Option {
None
}
```

The premise no longer holds: Windows releases have shipped and are installed in
the wild. The Unix arm already does the right thing — connect as an IPC client,
ask the lock holder for its `protocol_version` (method 0, wire-stable across
versions), and replace it only if it is provably older.

## Scope

`self_restart` still covers the ordinary update path, where the installed binary
is replaced in place. This gap is specifically about a *running* agent older
than the one trying to start. Two ways in:

- Running a development or portable build alongside an installed one (how I hit
it — two different install locations, so `self_restart` never applies).
- Any future `PROTOCOL_VERSION` bump reaching a machine whose old agent is still
alive at the time.

## Possible fix

Port the Unix `replace_stale` handshake to Windows. The IPC client half is
already cross-platform; only "terminate the holder" is Unix-specific (`SIGTERM`
via `sysinfo::Process::kill`), and `tray_windows.rs::quit` already terminates
processes on Windows through the same `sysinfo` API — so the primitive exists.

The `cfg!(debug_assertions)` guard in `try_replace_stale` should stay as it is:
a dev build must never displace the user's production agent.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in crates/openlogi-agent/src/takeover.rs at the Windows replace_stale arm and compare it with the Unix implementation and try_replace_stale. Review tray_windows.rs::quit for the existing Windows process-termination primitive. Done means an older running agent can be replaced only when its protocol is older, while the debug-build guard remains unchanged and the GUI no longer loops waiting for a replacement.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop, distributed-systems, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.