fix(cli): 1.31.2 — daemon paths no longer follow per-session CLAUDEMESH_CONFIG_DIR
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

Real production bug observed in 1.31.0 / 1.31.1: every CLI verb from
inside a claudemesh launch-spawned session printed

  [claudemesh] warn service-managed daemon not responding within 8000ms

even when the launchd-managed daemon was healthy and answering
direct UDS probes in 10ms.

Root cause: claudemesh launch exports CLAUDEMESH_CONFIG_DIR to a
per-session tmpdir so joined-mesh state and the IPC session token
stay isolated. DAEMON_PATHS read from the same env, so inside a
launched session the CLI looked for daemon.sock at
/var/folders/.../claudemesh-XXXX/daemon/daemon.sock — which never
exists. The CLI declared the daemon down, fell into the service-
managed wait branch, and timed out.

The daemon is a per-machine singleton serving every session; its
files live at ~/.claudemesh/daemon/ regardless of overlays. Pin
DAEMON_PATHS.DAEMON_DIR to that location. New CLAUDEMESH_DAEMON_DIR
override is preserved for tests and multi-daemon dev setups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-04 14:28:10 +01:00
parent 15b7920b2a
commit 088a4efaa3
3 changed files with 55 additions and 3 deletions

View File

@@ -1,9 +1,30 @@
import { homedir } from "node:os";
import { join } from "node:path";
import { PATHS } from "~/constants/paths.js";
/**
* Daemon paths intentionally do NOT honor `CLAUDEMESH_CONFIG_DIR`.
*
* `claudemesh launch` sets `CLAUDEMESH_CONFIG_DIR` to a per-session
* tmpdir so that joined-mesh state, last-used selections, and the
* IPC session token stay isolated from the host's shared config.
* The daemon, however, is a single per-machine process serving every
* launched session — its socket, pid file, on-disk outbox, and SQLite
* stores all live under `~/.claudemesh/daemon/`. Letting them inherit
* the per-session tmpdir would point each CLI invocation inside a
* launched session at a daemon socket that doesn't exist, force the
* cold path, and surface as "service-managed daemon not responding
* within 8000ms" (1.31.0 regression observed in real install).
*
* `CLAUDEMESH_DAEMON_DIR` exists as an explicit override for tests
* and for the rare case of running multiple daemon instances side by
* side (e.g. integration tests). Production callers should never set
* it.
*/
const DAEMON_DIR_ROOT =
process.env.CLAUDEMESH_DAEMON_DIR || join(homedir(), ".claudemesh", "daemon");
export const DAEMON_PATHS = {
get DAEMON_DIR() { return join(PATHS.CONFIG_DIR, "daemon"); },
get DAEMON_DIR() { return DAEMON_DIR_ROOT; },
get PID_FILE() { return join(this.DAEMON_DIR, "daemon.pid"); },
get SOCK_FILE() { return join(this.DAEMON_DIR, "daemon.sock"); },
get TOKEN_FILE() { return join(this.DAEMON_DIR, "local-token"); },