* fix(mcp): wait for a stopping daemon, and for the proxy's fallback engine (#2311)
Now that QueryPool.destroy() waits up to 15 s for a query worker still
starting up (#2307), two callers gave up too early:
- stopDaemonAt() gave a daemon 3 s after SIGTERM, then re-probed its
identity and reported it still running once the daemon had closed its
socket, so a daemon waiting on a starting worker made `codegraph index`
abort. A daemon that has closed its socket but still holds its lock is
now given 17 s more to exit; nothing is signalled during that wait.
- The proxy's in-process fallback called engine.stop() and exited on the
next line. It now exits once its engine, and any engine still being
retired after a handback to the daemon, has stopped, with a 20 s
backstop. Once shutdown starts it ignores client input and starts no
new engine.
Extracted from bompus/codegraph@cc87ec34da,
a fork merge commit that cannot be cherry-picked whole; only these four
files are taken, unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): a stopping daemon is waited for whether it closed its socket or released its lock (#2311)
Builds on the previous commit:
- stopDaemonAt: one rule after the first 3 s. If the daemon's identity can
be re-proven (same lock, socket answers), escalate to SIGKILL as before.
Otherwise, whether it has stopped answering its socket or already let go
of its lock, it is partway through its own shutdown: signal nothing more
and wait, bounded, for the PID to exit. The previous commit reported a
daemon that had released its lock but not yet exited as still running,
a race at the end of every slow shutdown. The cleanup that follows
compares the lock with the one signalled, so a successor's is kept. On
Windows, where SIGTERM is TerminateProcess, the same wait covers a
termination still settling.
- The grace is WORKER_START_SETTLE_MS + 2 s and the proxy's backstop
WORKER_START_SETTLE_MS + 5 s, so they move with the settle wait they
cover. stopDaemonAt takes `shutdownGraceMs` so a test can bound it.
- The proxy says so on stderr when its backstop fires.
Tests: the daemon fixture's setup and cleanup are shared, and the fixture
process is always killed on cleanup (a failing run used to leak it). New:
a daemon that released its lock mid-shutdown is waited for; a daemon that
never finishes stopping is still reported after the grace and never
SIGKILLed; the proxy waits for an engine being retired at shutdown; and
client input arriving once shutdown has begun starts no engine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Aaron Queen <bompus@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: safely stop daemon before reindex
* fix(index): coordinate rebuilds with running MCP daemons (#1325)
Stop verified project daemons and confirm termination before recreating SQLite.
Fence daemon and proxy reopening throughout rebuilds while preserving foreign and newer locks.
Add Windows lifecycle coverage and cross-platform shutdown regressions.
Co-authored-by: Harry B ✦ <drewavesx0@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): fence project opens during index rebuilds after rebase
Carry the #1325 rebuild fence through the upstream explicit-project lifecycle, read-only engine opens, synchronous initialization retries, and direct writer acquisition. Preserve shared project leases, read-only fallback behavior, freshness handling, and direct-mode query pools.
Cover watched, unwatched, and read-only engines blocking during a foreign rebuild and recovering after the fence is released.
* fix(mcp): answer a running index rebuild as guidance, not a tool error (#1325)
A projectPath call during `codegraph index` hit assertNoRebuild's plain Error
and returned isError; it is an expected, temporary condition, so it now uses a
RebuildInProgressError that the tool handler answers success-shaped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Harry B ✦ <drewavesx0@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Adds first-class daemon control (the #845 pain point: no clean way to stop a
runaway daemon). `codegraph stop [path]` stops the current/given project's
daemon (SIGTERM -> SIGKILL fallback, sweeps artifacts); `stop --all` stops every
daemon; `list`/`ps` shows running daemons (--json for scripts).
Discovery via a small self-healing registry: each daemon records its root under
~/.codegraph/daemons/ on start, removes it on graceful shutdown; readers prune
dead pids. Cross-platform by construction (files + process.kill). Validated live
on macOS, Linux (docker), and Windows (VM): registry unit 6/6 and real-daemon
stop/list 6/6 on each.