@barekey/cli 0.5.5 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -162,6 +162,7 @@ async function runWhoami(options) {
162
162
  console.log(await formatWhoamiWithAvatar({
163
163
  displayName: resolveDisplayName(session),
164
164
  email: session.email,
165
+ plan: session.plan,
165
166
  imageUrl: session.imageUrl,
166
167
  }));
167
168
  }
@@ -54,6 +54,7 @@ export declare const CliSessionResponseSchema: Schema.Struct<{
54
54
  displayName: Schema.NullOr<typeof Schema.String>;
55
55
  email: Schema.NullOr<typeof Schema.String>;
56
56
  imageUrl: Schema.NullOr<typeof Schema.String>;
57
+ plan: Schema.NullOr<Schema.Literal<["free", "pro", "max"]>>;
57
58
  orgId: typeof Schema.String;
58
59
  orgSlug: typeof Schema.String;
59
60
  source: Schema.Literal<["clerk", "cli"]>;
@@ -56,6 +56,7 @@ export const CliSessionResponseSchema = Schema.Struct({
56
56
  displayName: Schema.NullOr(Schema.String),
57
57
  email: Schema.NullOr(Schema.String),
58
58
  imageUrl: Schema.NullOr(Schema.String),
59
+ plan: Schema.NullOr(Schema.Literal("free", "pro", "max")),
59
60
  orgId: Schema.String,
60
61
  orgSlug: Schema.String,
61
62
  source: Schema.Literal("clerk", "cli"),
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
3
3
  *
4
- * @param input The display name, email, and optional avatar image URL.
4
+ * @param input The display name, email, plan, and optional avatar image URL.
5
5
  * @returns The formatted `whoami` string ready for stdout.
6
6
  * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
7
7
  * @lastModified 2026-03-19
@@ -10,5 +10,6 @@
10
10
  export declare function formatWhoamiWithAvatar(input: {
11
11
  displayName: string;
12
12
  email: string | null;
13
+ plan: "free" | "pro" | "max" | null;
13
14
  imageUrl: string | null;
14
15
  }): Promise<string>;
@@ -1,6 +1,10 @@
1
1
  import { Jimp } from "jimp";
2
- const DEFAULT_AVATAR_COLUMNS = 8;
3
- const DEFAULT_AVATAR_ROWS = 8;
2
+ import pc from "picocolors";
3
+ const DEFAULT_AVATAR_COLUMNS = 10;
4
+ const DEFAULT_AVATAR_ROWS = 5;
5
+ const EMAIL_HEX = "#9ca3af";
6
+ const BULLET_HEX = "#4b5563";
7
+ const PLAN_HEX = "#fbbf24";
4
8
  function supportsAnsiAvatar() {
5
9
  if (!process.stdout.isTTY) {
6
10
  return false;
@@ -35,6 +39,18 @@ function foregroundColor(pixel) {
35
39
  function backgroundColor(pixel) {
36
40
  return `\u001b[48;2;${pixel.red};${pixel.green};${pixel.blue}m`;
37
41
  }
42
+ function parseHexColor(hex) {
43
+ const normalized = hex.replace(/^#/, "");
44
+ return {
45
+ red: Number.parseInt(normalized.slice(0, 2), 16),
46
+ green: Number.parseInt(normalized.slice(2, 4), 16),
47
+ blue: Number.parseInt(normalized.slice(4, 6), 16),
48
+ };
49
+ }
50
+ function truecolorText(hex, value) {
51
+ const { red, green, blue } = parseHexColor(hex);
52
+ return `\u001b[38;2;${red};${green};${blue}m${value}\u001b[39m`;
53
+ }
38
54
  function renderPixelPair(top, bottom) {
39
55
  const topOpaque = isOpaque(top);
40
56
  const bottomOpaque = isOpaque(bottom);
@@ -93,17 +109,39 @@ function joinAvatarAndText(avatarLines, textLines) {
93
109
  }
94
110
  return renderedRows.join("\n");
95
111
  }
112
+ function formatPlanLabel(plan) {
113
+ if (plan === null) {
114
+ return "No plan";
115
+ }
116
+ if (plan === "free") {
117
+ return "Free";
118
+ }
119
+ if (plan === "pro") {
120
+ return "Pro";
121
+ }
122
+ return "Max";
123
+ }
96
124
  /**
97
125
  * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
98
126
  *
99
- * @param input The display name, email, and optional avatar image URL.
127
+ * @param input The display name, email, plan, and optional avatar image URL.
100
128
  * @returns The formatted `whoami` string ready for stdout.
101
129
  * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
102
130
  * @lastModified 2026-03-19
103
131
  * @author GPT-5.4
104
132
  */
105
133
  export async function formatWhoamiWithAvatar(input) {
106
- const textLines = [`Signed in as ${input.displayName}.`, input.email ?? ""].filter((line) => line.length > 0);
134
+ const firstLine = `Signed in as ${pc.bold(input.displayName)}`;
135
+ const secondSegments = [];
136
+ if (input.email !== null && input.email.length > 0) {
137
+ secondSegments.push(truecolorText(EMAIL_HEX, input.email));
138
+ }
139
+ const formattedPlan = truecolorText(PLAN_HEX, formatPlanLabel(input.plan));
140
+ if (secondSegments.length > 0) {
141
+ secondSegments.push(truecolorText(BULLET_HEX, "•"));
142
+ }
143
+ secondSegments.push(formattedPlan);
144
+ const textLines = [firstLine, secondSegments.join(" ")].filter((line) => line.length > 0);
107
145
  if (!supportsAnsiAvatar() || input.imageUrl === null) {
108
146
  return textLines.join("\n");
109
147
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barekey/cli",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Barekey command line interface",
5
5
  "type": "module",
6
6
  "bin": {
@@ -201,6 +201,7 @@ async function runWhoami(options: { json?: boolean }): Promise<void> {
201
201
  await formatWhoamiWithAvatar({
202
202
  displayName: resolveDisplayName(session),
203
203
  email: session.email,
204
+ plan: session.plan,
204
205
  imageUrl: session.imageUrl,
205
206
  }),
206
207
  );
@@ -78,6 +78,7 @@ export const CliSessionResponseSchema = Schema.Struct({
78
78
  displayName: Schema.NullOr(Schema.String),
79
79
  email: Schema.NullOr(Schema.String),
80
80
  imageUrl: Schema.NullOr(Schema.String),
81
+ plan: Schema.NullOr(Schema.Literal("free", "pro", "max")),
81
82
  orgId: Schema.String,
82
83
  orgSlug: Schema.String,
83
84
  source: Schema.Literal("clerk", "cli"),
@@ -1,7 +1,8 @@
1
1
  import { Jimp } from "jimp";
2
+ import pc from "picocolors";
2
3
 
3
- const DEFAULT_AVATAR_COLUMNS = 8;
4
- const DEFAULT_AVATAR_ROWS = 8;
4
+ const DEFAULT_AVATAR_COLUMNS = 10;
5
+ const DEFAULT_AVATAR_ROWS = 5;
5
6
 
6
7
  type Rgba = {
7
8
  red: number;
@@ -10,6 +11,10 @@ type Rgba = {
10
11
  alpha: number;
11
12
  };
12
13
 
14
+ const EMAIL_HEX = "#9ca3af";
15
+ const BULLET_HEX = "#4b5563";
16
+ const PLAN_HEX = "#fbbf24";
17
+
13
18
  function supportsAnsiAvatar(): boolean {
14
19
  if (!process.stdout.isTTY) {
15
20
  return false;
@@ -53,6 +58,20 @@ function backgroundColor(pixel: Rgba): string {
53
58
  return `\u001b[48;2;${pixel.red};${pixel.green};${pixel.blue}m`;
54
59
  }
55
60
 
61
+ function parseHexColor(hex: string): { red: number; green: number; blue: number } {
62
+ const normalized = hex.replace(/^#/, "");
63
+ return {
64
+ red: Number.parseInt(normalized.slice(0, 2), 16),
65
+ green: Number.parseInt(normalized.slice(2, 4), 16),
66
+ blue: Number.parseInt(normalized.slice(4, 6), 16),
67
+ };
68
+ }
69
+
70
+ function truecolorText(hex: string, value: string): string {
71
+ const { red, green, blue } = parseHexColor(hex);
72
+ return `\u001b[38;2;${red};${green};${blue}m${value}\u001b[39m`;
73
+ }
74
+
56
75
  function renderPixelPair(top: Rgba, bottom: Rgba): string {
57
76
  const topOpaque = isOpaque(top);
58
77
  const bottomOpaque = isOpaque(bottom);
@@ -131,10 +150,26 @@ function joinAvatarAndText(
131
150
  return renderedRows.join("\n");
132
151
  }
133
152
 
153
+ function formatPlanLabel(plan: "free" | "pro" | "max" | null): string {
154
+ if (plan === null) {
155
+ return "No plan";
156
+ }
157
+
158
+ if (plan === "free") {
159
+ return "Free";
160
+ }
161
+
162
+ if (plan === "pro") {
163
+ return "Pro";
164
+ }
165
+
166
+ return "Max";
167
+ }
168
+
134
169
  /**
135
170
  * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
136
171
  *
137
- * @param input The display name, email, and optional avatar image URL.
172
+ * @param input The display name, email, plan, and optional avatar image URL.
138
173
  * @returns The formatted `whoami` string ready for stdout.
139
174
  * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
140
175
  * @lastModified 2026-03-19
@@ -143,9 +178,23 @@ function joinAvatarAndText(
143
178
  export async function formatWhoamiWithAvatar(input: {
144
179
  displayName: string;
145
180
  email: string | null;
181
+ plan: "free" | "pro" | "max" | null;
146
182
  imageUrl: string | null;
147
183
  }): Promise<string> {
148
- const textLines = [`Signed in as ${input.displayName}.`, input.email ?? ""].filter(
184
+ const firstLine = `Signed in as ${pc.bold(input.displayName)}`;
185
+ const secondSegments: Array<string> = [];
186
+
187
+ if (input.email !== null && input.email.length > 0) {
188
+ secondSegments.push(truecolorText(EMAIL_HEX, input.email));
189
+ }
190
+
191
+ const formattedPlan = truecolorText(PLAN_HEX, formatPlanLabel(input.plan));
192
+ if (secondSegments.length > 0) {
193
+ secondSegments.push(truecolorText(BULLET_HEX, "•"));
194
+ }
195
+ secondSegments.push(formattedPlan);
196
+
197
+ const textLines = [firstLine, secondSegments.join(" ")].filter(
149
198
  (line) => line.length > 0,
150
199
  );
151
200