Skip to content

fix(focus): probe socket liveness so stale daemon leftovers aren't picked - #5

Merged
rz1989s merged 1 commit into
mainfrom
fix/stale-focus-socket-detection
Aug 13, 2026
Merged

fix(focus): probe socket liveness so stale daemon leftovers aren't picked#5
rz1989s merged 1 commit into
mainfrom
fix/stale-focus-socket-detection

Conversation

@rz1989s

@rz1989s rz1989s commented Aug 13, 2026

Copy link
Copy Markdown
Member

Problem

Launching pi in plain Ghostty printed an extension error every time:

Extension ".../cursor/extensions/cursor.ts"
error: connect ECONNREFUSED /Users/rector/.config/herdr/herdr.sock

…while the same launch inside tmux was silent.

Root cause

detect() in both HerdrFocusProvider and CmuxFocusProvider used fs.access (file-exists) to decide whether the multiplexer was running. A crashed/killed daemon leaves its socket file behind on disk, so exists-based detection mistook the stale leftover for a live serverstart() opened a real connection → ECONNREFUSED.

Inside tmux the bug was masked: autoDetect returns at the TMUX_PANE step and never reaches the herdr probe.

Fix

  • lib/focus/socket.ts (new) — probeSocket(path): opens a real connection and closes it. connect resolves only when a listener is accept()-ing; stale/missing/non-socket paths reject immediately. Never throws, 300 ms ceiling.
  • herdr.detect() / cmux.detect() — use probeSocket instead of access. Path resolution (env/marker/candidates) stays existence-based; only liveness moved to the probe — clean separation.
  • herdr.start() — swallows connect failure and degrades to always-focused, matching cmux's existing resilience, so an explicit /cursor provider herdr against a dead socket no longer breaks session_start.

Tests

  • tests/focus/socket.test.ts (new): live / missing / stale-file / regular-file / post-close / timeout.
  • herdr + cmux detect tests converted from writeFileSync stubs to real listening sockets, plus stale-leftover → false cases.
  • index.test.ts: regression guard — stale herdr socket falls through to static.
  • herdr: new start() resilience test (explicit dead socket → no throw, no onChange).

pnpm typecheck ✅ · pnpm test:run133 pass / 0 fail (was 122 / 1 failing — the pre-existing no env → static was already red on machines with a stale herdr.sock).

Semver

Patch (0.2.2 → 0.2.3): bugfix + resilience hardening, no API change.

After merge

Tag v0.2.3 → CI publishes → bump ~/.pi/agent/settings.json pin @0.2.2@0.2.3.

…cked

detect() in both HerdrFocusProvider and CmuxFocusProvider used fs.access
(file-exists) to decide if the multiplexer was running. A crashed/killed
daemon leaves its socket file on disk, so exists-based detection mistook
the stale leftover for a live server — start() then opened a real
connection and threw ECONNREFUSED, which pi surfaced as an extension
error on every launch (e.g. plain Ghostty with a dead ~/.config/herdr/
herdr.sock). Inside tmux the bug was masked because auto-detect returns
at the TMUX_PANE step and never probes herdr.

Fix:
- lib/focus/socket.ts: probeSocket(path) opens a real connection and
  closes it; connect resolves only when a listener is accept()-ing, so
  stale/missing/non-socket paths reject immediately. Never throws,
  300ms ceiling.
- herdr.detect() + cmux.detect() use probeSocket instead of access.
  Path resolution (env/marker/candidates) stays existence-based; only
  liveness moved to the probe — clean separation.
- herdr.start() now swallows connect failure and degrades to
  always-focused, matching cmux's existing resilience, so an explicit
  `/cursor provider herdr` against a dead socket won't break
  session_start either.

Tests: socket.test.ts (live/missing/stale/regular-file/close/timeout);
herdr + cmux detect tests converted from writeFileSync stubs to real
listening sockets, plus stale-leftover → false cases; index.test.ts
gains a regression guard that a stale herdr socket falls through to
static.

Bumps to 0.2.3.
@rz1989s
rz1989s merged commit 8b4dc31 into main Aug 13, 2026
1 check passed
@rz1989s
rz1989s deleted the fix/stale-focus-socket-detection branch August 13, 2026 23:47
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