chore(release): claudemesh-cli@1.6.1
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

Patch release on top of 1.6.0:

- Revoke-by-id-prefix bug fix (broker.revokeApiKey now returns
  structured status; CLI surfaces not_found / not_unique). Pasting
  the 8-char prefix from `apikey list` output now works as users
  expect, instead of silently no-op'ing with a misleading "✔
  revoked" message. Already deployed to broker.
- whoami falls back to local mesh-config view when no web session
  is signed in. Users who joined via invite (and never ran
  `claudemesh login`) now see their member ids and pubkey prefixes
  per mesh, instead of a "Not signed in" dead end.
- README updated: REST surface lives at claudemesh.com/api/v1/*
  (web app), NOT ic.claudemesh.com/api/v1/* (broker). Surfaced
  during CLI-only smoke test against prod when curl on the broker
  host returned 404.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-02 18:50:22 +01:00
parent 0f32529370
commit d7cef45640
5 changed files with 65 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
import { whoAmI } from "~/services/auth/facade.js";
import { render } from "~/ui/render.js";
import { bold, dim } from "~/ui/styles.js";
import { bold, clay, dim } from "~/ui/styles.js";
import { EXIT } from "~/constants/exit-codes.js";
export async function whoami(opts: { json?: boolean }): Promise<number> {
@@ -8,22 +8,40 @@ export async function whoami(opts: { json?: boolean }): Promise<number> {
if (opts.json) {
console.log(JSON.stringify({ schema_version: "1.0", ...result }, null, 2));
return EXIT.SUCCESS;
return result.signed_in || result.local ? EXIT.SUCCESS : EXIT.AUTH_FAILED;
}
if (!result.signed_in) {
render.err("Not signed in", "Run `claudemesh login` to sign in.");
// Show whatever we have. Both the web session and the local mesh
// config are independent surfaces of identity; suppress sections that
// are empty.
if (!result.signed_in && !result.local) {
render.err("Not signed in", "Run `claudemesh login` to sign in or `claudemesh <invite>` to join.");
return EXIT.AUTH_FAILED;
}
render.section("whoami");
render.kv([
["user", `${bold(result.user!.display_name)} ${dim(`(${result.user!.email})`)}`],
["token", `${result.token_source} ${dim("(~/.claudemesh/auth.json)")}`],
...(result.meshes
? [["meshes", `${result.meshes.owned} owned · ${result.meshes.guest} guest`] as [string, string]]
: []),
]);
if (result.signed_in) {
render.kv([
["user", `${bold(result.user!.display_name)} ${dim(`(${result.user!.email})`)}`],
["token", `${result.token_source} ${dim("(~/.claudemesh/auth.json)")}`],
...(result.meshes
? [["meshes", `${result.meshes.owned} owned · ${result.meshes.guest} guest`] as [string, string]]
: []),
]);
} else {
render.kv([
["web", dim("not signed in · run `claudemesh login` for account features")],
]);
}
if (result.local) {
render.blank();
render.kv([
["local", `${result.local.meshes.length} mesh${result.local.meshes.length === 1 ? "" : "es"} · ${dim(result.local.config_path)}`],
]);
for (const m of result.local.meshes) {
console.log(` ${clay("●")} ${bold(m.slug)} ${dim(`member ${m.member_id.slice(0, 8)}… pk ${m.pubkey_prefix}`)}`);
}
}
render.blank();
return EXIT.SUCCESS;