feat(cli): v0.1.7 — --name, --mesh, --join flags for launch
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
Release / Publish multi-arch images (push) Has been cancelled

- `claudemesh launch --name Mou` sets per-session display name
- `claudemesh launch --mesh car-dealers` selects mesh (interactive picker if >1)
- `claudemesh launch --join <token-or-url>` joins a mesh inline before launching
- Broker stores per-presence displayName override (prefers over member default)
- Session config isolated via tmpdir (auto-cleanup on exit)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-06 10:45:29 +01:00
parent e0659b0b6f
commit 2a2aac3622
9 changed files with 230 additions and 56 deletions

View File

@@ -307,6 +307,7 @@ export async function refreshStatusFromJsonl(
export interface ConnectParams {
memberId: string;
sessionId: string;
displayName?: string;
pid: number;
cwd: string;
}
@@ -321,6 +322,7 @@ export async function connectPresence(
.values({
memberId: params.memberId,
sessionId: params.sessionId,
displayName: params.displayName ?? null,
pid: params.pid,
cwd: params.cwd,
status: "idle",
@@ -370,7 +372,8 @@ export async function listPeersInMesh(
const rows = await db
.select({
pubkey: memberTable.peerPubkey,
displayName: memberTable.displayName,
memberDisplayName: memberTable.displayName,
presenceDisplayName: presence.displayName,
status: presence.status,
summary: presence.summary,
sessionId: presence.sessionId,
@@ -385,7 +388,15 @@ export async function listPeersInMesh(
),
)
.orderBy(asc(presence.connectedAt));
return rows;
// Prefer per-session displayName over member-level displayName.
return rows.map((r) => ({
pubkey: r.pubkey,
displayName: r.presenceDisplayName || r.memberDisplayName,
status: r.status,
summary: r.summary,
sessionId: r.sessionId,
connectedAt: r.connectedAt,
}));
}
/** Update the summary text on a presence row. */

View File

@@ -400,6 +400,7 @@ async function handleHello(
const presenceId = await connectPresence({
memberId: member.id,
sessionId: hello.sessionId,
displayName: hello.displayName,
pid: hello.pid,
cwd: hello.cwd,
});
@@ -411,9 +412,10 @@ async function handleHello(
cwd: hello.cwd,
});
incMeshCount(hello.meshId);
const effectiveDisplayName = hello.displayName || member.displayName;
log.info("ws hello", {
mesh_id: hello.meshId,
member: member.displayName,
member: effectiveDisplayName,
presence_id: presenceId,
session_id: hello.sessionId,
});
@@ -422,7 +424,7 @@ async function handleHello(
// races the caller's closure assignment, causing subsequent client
// messages to fail the "no_hello" check.
void maybePushQueuedMessages(presenceId);
return { presenceId, memberDisplayName: member.displayName };
return { presenceId, memberDisplayName: effectiveDisplayName };
}
async function handleSend(

View File

@@ -52,6 +52,7 @@ export interface WSHelloMessage {
meshId: string;
memberId: string;
pubkey: string; // must match mesh.member.peerPubkey
displayName?: string; // optional override for this session
sessionId: string;
pid: number;
cwd: string;