Skip to content

feat(daemon): auto-respawn via per-project watchdog (#116) - #119

Merged
ardelperal merged 1 commit into
mainfrom
fix/daemon-auto-respawn-rebase
Jul 13, 2026
Merged

feat(daemon): auto-respawn via per-project watchdog (#116)#119
ardelperal merged 1 commit into
mainfrom
fix/daemon-auto-respawn-rebase

Conversation

@ardelperal

Copy link
Copy Markdown
Owner

Summary

The shared MCP daemon auto-respawns when killed while the proxy is still up. After \Stop-Process -Id \ (or any other death cause) the proxy per-project daemon watchdog detects the dead daemon via its .codegraph-vba/daemon.pid\ lockfile and respawns it within 30s — file edits are picked up automatically instead of needing a manual \codegraph-vba sync.

What is in

  • \src/mcp/daemon-watchdog.ts\ (new) — \DaemonWatchdog\ class. Constructor takes an injectable \spawnFn\ so tests can stub the detached spawn without ESM-fragile \�i.mock('child_process')\ patches. \hasLiveDaemon\ reads the lockfile via \decodeLockInfo\ (the lockfile is the authoritative pointer; \listDaemons\ filters dead entries from its return value, so it cannot be used to detect a dead daemon).
  • \src/mcp/index.ts\ — \MCPServer\ (proxy mode) instantiates a watchdog per project root, starts it, and tears it down on \stop. Watchdog intervals are unrefed so they never keep the proxy alive.

Acceptance


  • px vitest run tests/daemon-watchdog.test.ts\ — 9/9 passed

  • px vitest run tests/daemon-registry.test.ts\ — 6/6 (no regression)

  • px tsc --noEmit\ clean
  • \git diff main...HEAD -- src/db/schema.sql\ empty
  • Conventional commit, no Co-Authored-By
  • CHANGELOG entry under [Unreleased] → Fixes\

Reopens the work from #118 after a rebase to resolve the CHANGELOG conflict with #117. Closes #116.

When the shared MCP daemon is killed (Stop-Process, kill -9, crash) while the proxy host is still running, the incremental file-watcher was lost until the user manually ran 'codegraph-vba sync'. This change adds a per-project daemon liveness watchdog inside the proxy that polls the daemon's .codegraph-vba/daemon.pid lockfile every 30s and respawns the daemon (via the same detached-spawn recipe the launcher uses) when the pid points at a dead process.

Architecture:

- src/mcp/daemon-watchdog.ts (new): DaemonWatchdog class. Constructor takes an injectable spawnFn so tests can stub the detached spawn without ESM-fragile vi.mock('child_process') patches. hasLiveDaemon(root) reads the lockfile via decodeLockInfo (the lockfile is the authoritative pointer; listDaemons filters dead entries from its return value, so it cannot be used to detect a dead daemon -- that was the trap in v1).

- src/mcp/index.ts: MCPServer (proxy mode) instantiates a watchdog per project root, starts it, and tears it down on stop(). Watchdog intervals are unref-ed so they never keep the proxy alive.

Why a watchdog (vs. spawn-on-demand at MCP request time): the issue's repro is Stop-Process -Id <pid> while the MCP keeps serving -- file edits are missed until the user manually runs 'codegraph-vba sync'. The watchdog closes that gap in <30s.

Tests (15/15 green across the daemon tests):

- __tests__/daemon-watchdog.test.ts (9 tests): covers hasLiveDaemon for the 3 lockfile states, checkAndRespawn (live=no-op, dead=respawn, no-.codegraph=no-op), tick -> respawn integration (single + double), start/stop behavior.

- __tests__/daemon-registry.test.ts: unchanged, still 6/6.

Closes #116.
@ardelperal
ardelperal merged commit 329b551 into main Jul 13, 2026
5 checks passed
@ardelperal
ardelperal deleted the fix/daemon-auto-respawn-rebase branch July 13, 2026 16:37
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.

Daemon does not auto-respawn after Stop-Process — leaves project without incremental file-watcher

1 participant