feat(cli): 1.31.5 — JSON peer list lifts role to top level + skill renders it
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

After 1.31.4 the human renderer surfaced role and groups, but launched-
session LLMs still dropped them when they called peer list --json and
built their own tables.

- Top-level role field. The broker returns role nested under
  profile.role; the CLI now lifts it to a top-level role field at
  parse time so it is the second-most-visible JSON field after
  displayName. profile.role is preserved.
- Updated claudemesh skill SKILL.md peer-list section with the full
  JSON shape (memberPubkey, sessionId, role, profile, isSelf,
  isThisSession) plus explicit guidance to render role + groups in
  any peer table inside a launched session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-04 16:36:23 +01:00
parent 4cfb682eab
commit a852a9df18
4 changed files with 51 additions and 5 deletions

View File

@@ -33,6 +33,10 @@ interface PeerRecord {
status?: string;
summary?: string;
groups: Array<{ name: string; role?: string }>;
/** Top-level convenience alias for `profile.role`. Lifted by the
* CLI so JSON consumers see role at the shape's top level instead
* of nested under profile. Same value either way. */
role?: string;
peerType?: string;
channel?: string;
model?: string;
@@ -110,6 +114,13 @@ async function listPeersForMesh(slug: string): Promise<PeerRecord[]> {
* tell sender's own sessions from real peers. The broker has always
* surfaced a sender's siblings as separate rows because they're separate
* presence rows; the cli just hadn't been making that visible.
*
* Also lifts `profile.role` to a top-level `role` field. The broker has
* always returned role nested under `profile.role`, but downstream JSON
* consumers (LLMs in launched sessions, jq pipelines, dashboards) kept
* missing it because nothing pointed at the nesting. A dedicated
* top-level alias makes the intent unmissable without breaking the
* `profile` object's shape for callers that already drill into it.
*/
function annotateSelf(
peer: PeerRecord,
@@ -126,7 +137,8 @@ function annotateSelf(
selfSessionPubkey &&
peer.pubkey === selfSessionPubkey
);
return { ...peer, isSelf, isThisSession };
const role = peer.profile?.role?.trim() || undefined;
return { ...peer, ...(role ? { role } : {}), isSelf, isThisSession };
}
export async function runPeers(flags: PeersFlags): Promise<void> {