Repository navigation
Description
Summary
mcpx daemons promises "every daemon on this machine" (internal/cli/manual.go), but daemon discovery in this repo's pkgs/mcpx copy has three defects. All three were found and fixed in dezren39/darwin-nix#369 (PR dezren39/darwin-nix#381); the fix was never ported to this copy. The pre-fix files here are byte-identical to dezren39/nix's pre-fix versions (verified: internal/daemon/paths.go, paths_test.go, server.go, internal/cli/manual.go, internal/settings/consumed_test.go, docs/parity.md; commands.go/root.go differ only by this repo's already-ported #265/#274/#276 fixes, in unrelated hunks).
Defects (verified on main 584d869)
-
Dead daemons are listed forever.
Paths.ListDaemons(internal/daemon/paths.go:229) returns everydaemon*.jsonrecord in the state dir with no liveness check, and nothing ever removes a record whose daemon was killed or crashed (a clean exit removes its own record at server.go:488/1158; a killed one cannot). Reproduced with a binary built from main: a record with a dead PID is listed bymcpx daemonsasRUNNING false, and the record file is still on disk after repeated listings.stop --alliterates the same stale records. -
Daemons with their own state directory are invisible. A daemon started with a custom state dir (
paths.statein config,--paths-state, orMCPX_STATE_DIR) writes its record only there (WriteInfo, paths.go:284).ListDaemonsscans only the caller's own state dir, so a normalmcpx daemons/stop --allnever sees it. Reproduced: a live record placed only in a second state dir is listed from that dir but not from the first. -
A
paths.configentry naming a file is silently ignored. The entries are directories searched for config files; pointing one at a file (a natural reading of the setting) silently loads the default config instead.adoptSettings(internal/cli/root.go:195) never inspects the entries, andinternal/settings/consumed_test.gokeepspaths.configon the unread-allowlist as "circular by construction".
Suggested fix (mirror dezren39/nix PR #381)
Paths.PruneStale(): remove records whose PID is gone (signal-0 liveness, EPERM = alive; pid-less records kept);mcpx daemonsandstop --allprune before listing.- Mirror records:
WriteInfoalso publishes the record into the default state dir (keyed name, best-effort) when the daemon's state dir is custom; newRemoveInfo()removes primary + mirror and replaces the twoos.Remove(s.paths.Info)calls in server.go. Listings search the caller's dir + the default dir, deduped by socket. adoptSettingswarns once when apaths.configentry names a file, naming--config/MCPX_CONFIGas the way to pick a file;paths.configleaves the consumed-test allowlist.- Update the
daemonsentry in internal/cli/manual.go and regenerate docs/parity.md.
Acceptance criteria
- A daemon record with a dead PID no longer appears in
mcpx daemonsoutput and its file is removed; records with a live PID or no PID are untouched. - A daemon started in a custom state dir appears in a default-state-dir
mcpx daemonslisting (andstop --allreaches it), exactly once. - A
paths.configentry naming a file produces one stderr warning naming--config/MCPX_CONFIG; directory entries stay silent. - New daemon tests cover ProcessAlive/PruneStale/mirroring;
go test ./internal/daemon/ ./internal/settings/ ./internal/cli/passes.
Activity