fix(cli): 1.31.2 — daemon paths no longer follow per-session CLAUDEMESH_CONFIG_DIR
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:
@@ -1,5 +1,36 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.31.2 (2026-05-04) — daemon paths no longer follow per-session CLAUDEMESH_CONFIG_DIR
|
||||||
|
|
||||||
|
**Production bug observed in real installs:** every CLI verb invoked 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 responding to
|
||||||
|
direct probes in ~10 ms.
|
||||||
|
|
||||||
|
Root cause: `claudemesh launch` exports `CLAUDEMESH_CONFIG_DIR` to a
|
||||||
|
per-session tmpdir so that joined-mesh state and the session IPC
|
||||||
|
token stay isolated from the host's shared config. `DAEMON_PATHS`
|
||||||
|
read its base directory from the same env var, so inside a launched
|
||||||
|
session the CLI looked for `daemon.sock` at e.g.
|
||||||
|
`/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 belong at `~/.claudemesh/daemon/` regardless of any per-session
|
||||||
|
overlay. Fix: pin `DAEMON_PATHS.DAEMON_DIR` to `~/.claudemesh/daemon/`
|
||||||
|
and ignore `CLAUDEMESH_CONFIG_DIR`. A new `CLAUDEMESH_DAEMON_DIR`
|
||||||
|
override is preserved for tests / multi-daemon dev setups; production
|
||||||
|
callers should never set it.
|
||||||
|
|
||||||
|
After this fix, all CLI verbs from within a launched session take the
|
||||||
|
warm-path (~10 ms IPC) again instead of the cold path (~600-1200 ms).
|
||||||
|
|
||||||
## 1.31.1 (2026-05-04) — hotfix: reaper stops blocking the daemon event loop
|
## 1.31.1 (2026-05-04) — hotfix: reaper stops blocking the daemon event loop
|
||||||
|
|
||||||
1.31.0 shipped a session reaper that called `execFileSync("ps")`
|
1.31.0 shipped a session reaper that called `execFileSync("ps")`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudemesh-cli",
|
"name": "claudemesh-cli",
|
||||||
"version": "1.31.1",
|
"version": "1.31.2",
|
||||||
"description": "Peer mesh for Claude Code sessions — CLI + MCP server.",
|
"description": "Peer mesh for Claude Code sessions — CLI + MCP server.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"claude-code",
|
"claude-code",
|
||||||
|
|||||||
@@ -1,9 +1,30 @@
|
|||||||
|
import { homedir } from "node:os";
|
||||||
import { join } from "node:path";
|
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 = {
|
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 PID_FILE() { return join(this.DAEMON_DIR, "daemon.pid"); },
|
||||||
get SOCK_FILE() { return join(this.DAEMON_DIR, "daemon.sock"); },
|
get SOCK_FILE() { return join(this.DAEMON_DIR, "daemon.sock"); },
|
||||||
get TOKEN_FILE() { return join(this.DAEMON_DIR, "local-token"); },
|
get TOKEN_FILE() { return join(this.DAEMON_DIR, "local-token"); },
|
||||||
|
|||||||
Reference in New Issue
Block a user