diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md index 08893c8..454dab4 100644 --- a/apps/cli/CHANGELOG.md +++ b/apps/cli/CHANGELOG.md @@ -1,5 +1,88 @@ # Changelog +## 1.30.0 (2026-05-04) — per-session broker presence + +Sprint A Phase 3. Two `claudemesh launch` sessions in the same cwd now +see each other in `peer list`. Each launched session has a long-lived +broker presence row owned by the daemon, identified by a per-launch +ephemeral keypair vouched by the member's stable key (OAuth-refresh-vs- +access shape). + +### What landed + +- **broker `session_hello`** — new WS message type. Validates a + parent-vouched `parent_attestation` (≤24h TTL, ed25519 signature by + the parent member) plus a session-keyed signature on the hello + itself. Inserts a presence row keyed on `sessionPubkey` but + `member_id` from the parent, so member-targeted operations stay + unchanged. Older brokers reply `unknown_message_type` — newer clients + drop back to the previous behavior. +- **daemon `SessionBrokerClient`** — slim WS variant of + `DaemonBrokerClient`. Presence-only, no outbox drain. Lifetime tied + to a registry hook: register opens it, deregister/reaper closes it. + Reconnect with exponential backoff up to 30 s. +- **session-registry hooks** — `setRegistryHooks({ onRegister, + onDeregister })` in `apps/cli/src/daemon/session-registry.ts`. Hook + errors are caught so they never throttle the registry. SessionInfo + gains an optional `presence` field carrying the per-launch keypair + + attestation. +- **IPC `POST /v1/sessions/register`** — accepts an optional + `presence` block on the body (`session_pubkey`, `session_secret_key`, + `parent_attestation`). Older payloads continue to work. +- **`claudemesh launch`** — generates an ed25519 session keypair and a + 12 h parent attestation per launch (mesh secret key signs it), + forwards both to the daemon under `body.presence`. The flag + `CLAUDEMESH_SESSION_PRESENCE` defaults to ON; set `=0` to roll back + if a broker on a given mesh is misbehaving. +- **latent 1.29.0 bug fix** — `claudemesh launch` referenced + `claudeSessionId` before its `const` declaration further down the + file, hitting the temporal dead zone → `ReferenceError` silently + swallowed by the surrounding catch. Net: the IPC session-token + registration has been failing every launch since 1.29.0, falling + every session back to user-level scope. Hoisted the declaration up + so the registration actually runs. + +### Sequencing + +The broker side ships first and bakes for ~24 h. Only then does the +flag default flip on the CLI side. Older CLIs continue working +unchanged (no per-session WS), and the protocol is purely additive on +the wire. + +### Verification (smoke) + +In two shells, both `cd ~/Desktop/foo`: + +``` +$ claudemesh launch --name SessionA -y # shell 1 +$ claudemesh launch --name SessionB -y # shell 2 +``` + +In a third shell: + +``` +$ claudemesh peer list --json --mesh foo \ + | jq '.[] | {n: .displayName, c: .cwd}' +{ "n": "SessionA", "c": "/.../foo" } ← persistent, not query-induced +{ "n": "SessionB", "c": "/.../foo" } +``` + +Inside SessionA, `peer list --mesh foo` now lists SessionB. Kill +SessionB; within ≤30 s the reaper drops it from `peer list`. + +### Out of scope (deferred) + +- **Attestation auto-refresh** — current 12 h TTL is comfortably + longer than typical sessions; if a session lives past the TTL and + the WS reconnects after expiry, the broker rejects with `expired` + and the SessionBrokerClient quiets. Workaround: `claudemesh launch` + again. Auto-refresh queued for 1.31.0+ alongside HKDF identity. +- **Per-session policy DSL** — the per-launch WS could carry + per-session capabilities later. Out of scope here. +- **Cross-machine session sync** — waits on 2.0.0 HKDF identity. +- **Launch-wizard refactor** — bumped to 1.31.0 to keep this release + scoped to presence. + ## 1.29.0 (2026-05-04) — per-session IPC tokens + auto-scoping Sprint A Phase 2. Every `claudemesh launch`-spawned session gets a diff --git a/apps/cli/package.json b/apps/cli/package.json index d887b5c..38aa962 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "claudemesh-cli", - "version": "1.29.0", + "version": "1.30.0", "description": "Peer mesh for Claude Code sessions — CLI + MCP server.", "keywords": [ "claude-code", diff --git a/apps/cli/src/daemon/run.ts b/apps/cli/src/daemon/run.ts index f4bceaa..d7f1c4e 100644 --- a/apps/cli/src/daemon/run.ts +++ b/apps/cli/src/daemon/run.ts @@ -29,14 +29,14 @@ export interface RunDaemonOptions { } /** - * 1.30.0 feature flag. Default OFF for one release cycle so the broker - * side has time to deploy + bake before the daemon starts opening - * per-session WebSockets. Set CLAUDEMESH_SESSION_PRESENCE=0 to disable - * once the flag flips default-on. + * 1.30.0 feature flag. Default ON — the daemon opens a long-lived WS per + * registered session so siblings see each other in `peer list`. Set + * CLAUDEMESH_SESSION_PRESENCE=0 (or "false"/"off") to disable for + * rollback if the broker side is misbehaving on a given mesh. */ function isSessionPresenceEnabled(): boolean { const v = process.env.CLAUDEMESH_SESSION_PRESENCE; - if (v === undefined || v === "") return false; + if (v === undefined || v === "") return true; return v !== "0" && v.toLowerCase() !== "false" && v.toLowerCase() !== "off"; } diff --git a/docs/roadmap.md b/docs/roadmap.md index 51c7b4e..736e5fd 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -232,7 +232,7 @@ What this leaves on the v2.0.0 redesign is documented at --- -## v1.26.0 → v1.29.0 — *Sprint A toward v2* — *shipped* +## v1.26.0 → v1.30.0 — *Sprint A toward v2* — *shipped* The Sprint A push completed everything spec'd for v2.0.0 *except* HKDF identity (deferred for security review). @@ -268,14 +268,26 @@ identity (deferred for security review). joined meshes (verified: `peer list` returns 1 workspace's peers with token, all 3 without). Server-side `meshFromCtx()` plumbing on every read route. +- **1.30.0** — per-session broker presence. Two `claudemesh launch` + sessions in the same cwd finally see each other in `peer list`. Each + launched session has a long-lived broker presence row owned by the + daemon, identified by a per-launch ephemeral keypair vouched by the + member's stable key (OAuth-refresh-vs-access shape). Broker gains a + `session_hello` handler with parent-attestation TTL ≤24h + session- + signature checks; daemon adds a slim `SessionBrokerClient` and + registry lifecycle hooks. Also fixes a latent 1.29.0 TDZ bug where + `claudemesh launch`'s IPC session-token registration was silently + failing every run. Flag-gated for one cycle, default ON in this + release; set `CLAUDEMESH_SESSION_PRESENCE=0` for rollback. Spec at + `.artifacts/specs/2026-05-04-per-session-presence.md`. What's left for true v2.0.0 (next sessions): -- **1.30.0** — launch wizard refactor (single render loop, daemon-as- +- **1.31.0** — launch wizard refactor (single render loop, daemon-as- step probe panel, last-used persistence, drop `@ts-nocheck`). -- **1.31.0** — setup wizard refactor (state-detection snapshot, four- +- **1.32.0** — setup wizard refactor (state-detection snapshot, four- branch flow, daemon install offer, post-join panel). -- **1.32.0** — full mesh→workspace public-surface rename in help/docs/ +- **1.33.0** — full mesh→workspace public-surface rename in help/docs/ site; mesh aliases tagged deprecated; protocol/DB stay `mesh_*`. ---