5 Commits

Author SHA1 Message Date
Colby Mchenry dbb3d63cb1 fix(mcp): wait for a stopping daemon, and for the proxy's fallback engine (#2311) (#2316)
* 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>
2026-10-03 05:05:29 +00:00
Colby Mchenry 1926ec39a2 fix(index): coordinate rebuilds with running MCP daemons (#1325) (#2051)
* 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>
2026-09-27 15:26:49 +00:00
Christopher Beaulieu 1e46123758 fix(daemon): preserve live legacy locks (#1834) (#1850)
Co-authored-by: Colby Mchenry <me@colbymchenry.com>
2026-09-15 16:36:00 +00:00
Daniil 81e1f4a92f fix: harden daemon and large-index recovery paths (#1562)
* fix: harden indexing recovery and daemon liveness

* test: cover daemon and recovery review gaps

* test: pin that a failure marker never blocks a later successful parse (#1557 retry-discard guard)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Colby McHenry <me@colbymchenry.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 12:53:49 -05:00
Colby Mchenry 0f825649a1 feat(cli): codegraph stop / list to manage background daemons (#861)
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.
2026-06-13 12:59:41 -05:00