@barekey/cli 0.5.0 → 0.5.2

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.
package/bun.lock CHANGED
@@ -8,6 +8,7 @@
8
8
  "@clack/prompts": "^0.11.0",
9
9
  "commander": "^14.0.1",
10
10
  "effect": "3.19.19",
11
+ "jimp": "^1.6.0",
11
12
  "open": "^10.2.0",
12
13
  "picocolors": "^1.1.1",
13
14
  },
@@ -22,10 +23,80 @@
22
23
 
23
24
  "@clack/prompts": ["@clack/prompts@0.11.0", "", { "dependencies": { "@clack/core": "0.5.0", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw=="],
24
25
 
26
+ "@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="],
27
+
28
+ "@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="],
29
+
30
+ "@jimp/file-ops": ["@jimp/file-ops@1.6.0", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="],
31
+
32
+ "@jimp/js-bmp": ["@jimp/js-bmp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="],
33
+
34
+ "@jimp/js-gif": ["@jimp/js-gif@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="],
35
+
36
+ "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="],
37
+
38
+ "@jimp/js-png": ["@jimp/js-png@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="],
39
+
40
+ "@jimp/js-tiff": ["@jimp/js-tiff@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="],
41
+
42
+ "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="],
43
+
44
+ "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="],
45
+
46
+ "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="],
47
+
48
+ "@jimp/plugin-color": ["@jimp/plugin-color@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="],
49
+
50
+ "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="],
51
+
52
+ "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="],
53
+
54
+ "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="],
55
+
56
+ "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="],
57
+
58
+ "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="],
59
+
60
+ "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="],
61
+
62
+ "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="],
63
+
64
+ "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="],
65
+
66
+ "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="],
67
+
68
+ "@jimp/plugin-print": ["@jimp/plugin-print@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="],
69
+
70
+ "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.0", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="],
71
+
72
+ "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="],
73
+
74
+ "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="],
75
+
76
+ "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="],
77
+
78
+ "@jimp/types": ["@jimp/types@1.6.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="],
79
+
80
+ "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="],
81
+
25
82
  "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
26
83
 
84
+ "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
85
+
27
86
  "@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="],
28
87
 
88
+ "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
89
+
90
+ "any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="],
91
+
92
+ "await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="],
93
+
94
+ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
95
+
96
+ "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="],
97
+
98
+ "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
99
+
29
100
  "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
30
101
 
31
102
  "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
@@ -38,28 +109,98 @@
38
109
 
39
110
  "effect": ["effect@3.19.19", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-Yc8U/SVXo2dHnaP7zNBlAo83h/nzSJpi7vph6Hzyl4ulgMBIgPmz3UzOjb9sBgpFE00gC0iETR244sfXDNLHRg=="],
40
111
 
112
+ "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
113
+
114
+ "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
115
+
116
+ "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="],
117
+
41
118
  "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
42
119
 
120
+ "file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="],
121
+
122
+ "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
123
+
124
+ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
125
+
126
+ "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="],
127
+
43
128
  "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
44
129
 
45
130
  "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
46
131
 
47
132
  "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
48
133
 
134
+ "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="],
135
+
136
+ "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="],
137
+
138
+ "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
139
+
140
+ "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="],
141
+
49
142
  "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
50
143
 
144
+ "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
145
+
146
+ "parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="],
147
+
148
+ "parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="],
149
+
150
+ "parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="],
151
+
152
+ "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="],
153
+
51
154
  "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
52
155
 
156
+ "pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="],
157
+
158
+ "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
159
+
160
+ "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
161
+
53
162
  "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
54
163
 
164
+ "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
165
+
166
+ "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="],
167
+
55
168
  "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="],
56
169
 
170
+ "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
171
+
172
+ "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
173
+
174
+ "simple-xml-to-json": ["simple-xml-to-json@1.2.4", "", {}, "sha512-3MY16e0ocMHL7N1ufpdObURGyX+lCo0T/A+y6VCwosLdH1HSda4QZl1Sdt/O+2qWp48WFi26XEp5rF0LoaL0Dg=="],
175
+
57
176
  "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
58
177
 
178
+ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
179
+
180
+ "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="],
181
+
182
+ "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="],
183
+
184
+ "token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="],
185
+
59
186
  "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
60
187
 
61
188
  "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
62
189
 
190
+ "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="],
191
+
63
192
  "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
193
+
194
+ "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="],
195
+
196
+ "xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="],
197
+
198
+ "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
199
+
200
+ "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
201
+
202
+ "image-q/@types/node": ["@types/node@16.9.1", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="],
203
+
204
+ "pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="],
64
205
  }
65
206
  }
@@ -8,6 +8,7 @@ import { buildSessionId } from "../context/session-id.js";
8
8
  import { clearConfig, deleteCredentials, saveConfig, saveCredentials, } from "../credentials-store.js";
9
9
  import { CliSessionResponseSchema, DevicePollResponseSchema, DeviceStartResponseSchema, RefreshResponseSchema, } from "../contracts/index.js";
10
10
  import { getJson, postJson } from "../http.js";
11
+ import { formatWhoamiWithAvatar } from "../output/avatar.js";
11
12
  import { requireLocalSession, resolveBaseUrl, toJsonOutput } from "../command-utils.js";
12
13
  function resolveClientName() {
13
14
  const configured = process.env.BAREKEY_CLIENT_NAME?.trim() ||
@@ -35,6 +36,10 @@ function resolveVerificationUri(baseUrl, verificationUri) {
35
36
  }
36
37
  return verificationUri;
37
38
  }
39
+ function resolveDisplayName(input) {
40
+ const displayName = input.displayName?.trim();
41
+ return displayName && displayName.length > 0 ? displayName : input.clerkUserId;
42
+ }
38
43
  async function runLogin(options) {
39
44
  const baseUrl = await resolveBaseUrl(options.baseUrl);
40
45
  intro("Barekey CLI login");
@@ -89,6 +94,8 @@ async function runLogin(options) {
89
94
  orgId: poll.orgId,
90
95
  orgSlug: poll.orgSlug,
91
96
  clerkUserId: poll.clerkUserId,
97
+ displayName: poll.displayName,
98
+ email: poll.email,
92
99
  });
93
100
  const sessionId = buildSessionId(baseUrl, refreshed.clerkUserId);
94
101
  await saveCredentials(sessionId, {
@@ -108,7 +115,7 @@ async function runLogin(options) {
108
115
  });
109
116
  pollSpinner.stop("Login approved");
110
117
  pollActive = false;
111
- outro(`Logged in as ${pc.bold(refreshed.clerkUserId)}.`);
118
+ outro(`Signed in as ${pc.bold(resolveDisplayName(refreshed))}.`);
112
119
  return;
113
120
  }
114
121
  pollSpinner.stop("Timed out");
@@ -152,9 +159,11 @@ async function runWhoami(options) {
152
159
  toJsonOutput(true, session);
153
160
  return;
154
161
  }
155
- console.log(`${pc.bold("User")}: ${session.clerkUserId}`);
156
- console.log(`${pc.bold("Current org")}: ${session.orgSlug}`);
157
- console.log(`${pc.bold("Source")}: ${session.source}`);
162
+ console.log(await formatWhoamiWithAvatar({
163
+ displayName: resolveDisplayName(session),
164
+ email: session.email,
165
+ imageUrl: session.imageUrl,
166
+ }));
158
167
  }
159
168
  export function registerAuthCommands(program) {
160
169
  const auth = program.command("auth").description("Authentication commands");
@@ -5,12 +5,9 @@ import { getJson, postJson } from "../http.js";
5
5
  import { promptForOrganizationSlug } from "./target-prompts.js";
6
6
  async function runBillingCatalog(options) {
7
7
  const local = await requireLocalSession();
8
- const authProvider = createCliAuthProvider();
9
- const accessToken = await authProvider.getAccessToken();
10
8
  const response = await getJson({
11
9
  baseUrl: local.baseUrl,
12
10
  path: "/v1/cli/billing/catalog",
13
- accessToken,
14
11
  schema: BillingCatalogResponseSchema,
15
12
  });
16
13
  if (options.json) {
@@ -7,11 +7,11 @@
7
7
  * @author GPT-5.4
8
8
  */
9
9
  export declare function listOrganizationsForCurrentUser(): Promise<readonly {
10
+ readonly imageUrl: string;
10
11
  readonly name: string;
11
12
  readonly id: string;
12
13
  readonly slug: string;
13
14
  readonly role: string;
14
- readonly imageUrl: string;
15
15
  }[]>;
16
16
  /**
17
17
  * Loads projects for one organization.
@@ -51,6 +51,9 @@ export declare const ErrorEnvelopeSchema: Schema.Struct<{
51
51
  }>;
52
52
  export declare const CliSessionResponseSchema: Schema.Struct<{
53
53
  clerkUserId: typeof Schema.String;
54
+ displayName: Schema.NullOr<typeof Schema.String>;
55
+ email: Schema.NullOr<typeof Schema.String>;
56
+ imageUrl: Schema.NullOr<typeof Schema.String>;
54
57
  orgId: typeof Schema.String;
55
58
  orgSlug: typeof Schema.String;
56
59
  source: Schema.Literal<["clerk", "cli"]>;
@@ -79,6 +82,8 @@ export declare const DevicePollApprovedSchema: Schema.Struct<{
79
82
  orgId: typeof Schema.String;
80
83
  orgSlug: typeof Schema.String;
81
84
  clerkUserId: typeof Schema.String;
85
+ displayName: Schema.NullOr<typeof Schema.String>;
86
+ email: Schema.NullOr<typeof Schema.String>;
82
87
  requestId: Schema.optional<typeof Schema.String>;
83
88
  }>;
84
89
  export declare const DevicePollResponseSchema: Schema.Union<[Schema.Struct<{
@@ -95,6 +100,8 @@ export declare const DevicePollResponseSchema: Schema.Union<[Schema.Struct<{
95
100
  orgId: typeof Schema.String;
96
101
  orgSlug: typeof Schema.String;
97
102
  clerkUserId: typeof Schema.String;
103
+ displayName: Schema.NullOr<typeof Schema.String>;
104
+ email: Schema.NullOr<typeof Schema.String>;
98
105
  requestId: Schema.optional<typeof Schema.String>;
99
106
  }>]>;
100
107
  export declare const RefreshResponseSchema: Schema.Struct<{
@@ -105,6 +112,8 @@ export declare const RefreshResponseSchema: Schema.Struct<{
105
112
  orgId: typeof Schema.String;
106
113
  orgSlug: typeof Schema.String;
107
114
  clerkUserId: typeof Schema.String;
115
+ displayName: Schema.NullOr<typeof Schema.String>;
116
+ email: Schema.NullOr<typeof Schema.String>;
108
117
  requestId: Schema.optional<typeof Schema.String>;
109
118
  }>;
110
119
  export declare const EnvDecisionSchema: Schema.Struct<{
@@ -53,6 +53,9 @@ export const ErrorEnvelopeSchema = Schema.Struct({
53
53
  });
54
54
  export const CliSessionResponseSchema = Schema.Struct({
55
55
  clerkUserId: Schema.String,
56
+ displayName: Schema.NullOr(Schema.String),
57
+ email: Schema.NullOr(Schema.String),
58
+ imageUrl: Schema.NullOr(Schema.String),
56
59
  orgId: Schema.String,
57
60
  orgSlug: Schema.String,
58
61
  source: Schema.Literal("clerk", "cli"),
@@ -81,6 +84,8 @@ export const DevicePollApprovedSchema = Schema.Struct({
81
84
  orgId: Schema.String,
82
85
  orgSlug: Schema.String,
83
86
  clerkUserId: Schema.String,
87
+ displayName: Schema.NullOr(Schema.String),
88
+ email: Schema.NullOr(Schema.String),
84
89
  requestId: Schema.optional(Schema.String),
85
90
  });
86
91
  export const DevicePollResponseSchema = Schema.Union(DevicePollPendingSchema, DevicePollApprovedSchema);
@@ -92,6 +97,8 @@ export const RefreshResponseSchema = Schema.Struct({
92
97
  orgId: Schema.String,
93
98
  orgSlug: Schema.String,
94
99
  clerkUserId: Schema.String,
100
+ displayName: Schema.NullOr(Schema.String),
101
+ email: Schema.NullOr(Schema.String),
95
102
  requestId: Schema.optional(Schema.String),
96
103
  });
97
104
  export const EnvDecisionSchema = Schema.Struct({
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
3
+ *
4
+ * @param input The display name, email, and optional avatar image URL.
5
+ * @returns The formatted `whoami` string ready for stdout.
6
+ * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
7
+ * @lastModified 2026-03-19
8
+ * @author GPT-5.4
9
+ */
10
+ export declare function formatWhoamiWithAvatar(input: {
11
+ displayName: string;
12
+ email: string | null;
13
+ imageUrl: string | null;
14
+ }): Promise<string>;
@@ -0,0 +1,114 @@
1
+ import { Jimp } from "jimp";
2
+ const DEFAULT_AVATAR_COLUMNS = 10;
3
+ const DEFAULT_AVATAR_ROWS = 8;
4
+ function supportsAnsiAvatar() {
5
+ if (!process.stdout.isTTY) {
6
+ return false;
7
+ }
8
+ if ((process.env.NO_COLOR ?? "").trim().length > 0) {
9
+ return false;
10
+ }
11
+ const term = (process.env.TERM ?? "").toLowerCase();
12
+ if (term === "dumb") {
13
+ return false;
14
+ }
15
+ return true;
16
+ }
17
+ function pixelOffset(width, x, y) {
18
+ return (y * width + x) * 4;
19
+ }
20
+ function readPixel(data, width, x, y) {
21
+ const offset = pixelOffset(width, x, y);
22
+ return {
23
+ red: data[offset] ?? 0,
24
+ green: data[offset + 1] ?? 0,
25
+ blue: data[offset + 2] ?? 0,
26
+ alpha: data[offset + 3] ?? 0,
27
+ };
28
+ }
29
+ function isOpaque(pixel) {
30
+ return pixel.alpha >= 96;
31
+ }
32
+ function foregroundColor(pixel) {
33
+ return `\u001b[38;2;${pixel.red};${pixel.green};${pixel.blue}m`;
34
+ }
35
+ function backgroundColor(pixel) {
36
+ return `\u001b[48;2;${pixel.red};${pixel.green};${pixel.blue}m`;
37
+ }
38
+ function renderPixelPair(top, bottom) {
39
+ const topOpaque = isOpaque(top);
40
+ const bottomOpaque = isOpaque(bottom);
41
+ if (!topOpaque && !bottomOpaque) {
42
+ return " ";
43
+ }
44
+ if (topOpaque && bottomOpaque) {
45
+ return `${foregroundColor(top)}${backgroundColor(bottom)}▀`;
46
+ }
47
+ if (topOpaque) {
48
+ return `${foregroundColor(top)}▀`;
49
+ }
50
+ return `${foregroundColor(bottom)}▄`;
51
+ }
52
+ async function fetchAvatarBuffer(imageUrl) {
53
+ const response = await fetch(imageUrl, {
54
+ signal: AbortSignal.timeout(4_000),
55
+ });
56
+ if (!response.ok) {
57
+ throw new Error(`Avatar request failed with HTTP ${response.status}.`);
58
+ }
59
+ return Buffer.from(await response.arrayBuffer());
60
+ }
61
+ async function renderAvatarLines(imageUrl) {
62
+ const bitmapRows = DEFAULT_AVATAR_ROWS * 2;
63
+ const buffer = await fetchAvatarBuffer(imageUrl);
64
+ const image = await Jimp.read(buffer);
65
+ image.cover({
66
+ w: DEFAULT_AVATAR_COLUMNS,
67
+ h: bitmapRows,
68
+ });
69
+ image.circle();
70
+ const { data, width, height } = image.bitmap;
71
+ const lines = [];
72
+ for (let y = 0; y < height; y += 2) {
73
+ let line = "";
74
+ for (let x = 0; x < width; x += 1) {
75
+ const top = readPixel(data, width, x, y);
76
+ const bottom = readPixel(data, width, x, Math.min(y + 1, height - 1));
77
+ line += renderPixelPair(top, bottom);
78
+ }
79
+ lines.push(`${line}\u001b[0m`);
80
+ }
81
+ return lines;
82
+ }
83
+ function joinAvatarAndText(avatarLines, textLines) {
84
+ const totalRows = Math.max(avatarLines.length, textLines.length);
85
+ const renderedRows = [];
86
+ for (let index = 0; index < totalRows; index += 1) {
87
+ const avatarLine = avatarLines[index] ?? " ".repeat(DEFAULT_AVATAR_COLUMNS);
88
+ const textLine = textLines[index] ?? "";
89
+ renderedRows.push(textLine.length > 0 ? `${avatarLine} ${textLine}` : avatarLine);
90
+ }
91
+ return renderedRows.join("\n");
92
+ }
93
+ /**
94
+ * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
95
+ *
96
+ * @param input The display name, email, and optional avatar image URL.
97
+ * @returns The formatted `whoami` string ready for stdout.
98
+ * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
99
+ * @lastModified 2026-03-19
100
+ * @author GPT-5.4
101
+ */
102
+ export async function formatWhoamiWithAvatar(input) {
103
+ const textLines = [`Signed in as ${input.displayName}.`, input.email ?? ""].filter((line) => line.length > 0);
104
+ if (!supportsAnsiAvatar() || input.imageUrl === null) {
105
+ return textLines.join("\n");
106
+ }
107
+ try {
108
+ const avatarLines = await renderAvatarLines(input.imageUrl);
109
+ return joinAvatarAndText(avatarLines, textLines);
110
+ }
111
+ catch {
112
+ return textLines.join("\n");
113
+ }
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barekey/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Barekey command line interface",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,6 +17,7 @@
17
17
  "@clack/prompts": "^0.11.0",
18
18
  "commander": "^14.0.1",
19
19
  "effect": "3.19.19",
20
+ "jimp": "^1.6.0",
20
21
  "open": "^10.2.0",
21
22
  "picocolors": "^1.1.1"
22
23
  },
@@ -21,6 +21,7 @@ import {
21
21
  RefreshResponseSchema,
22
22
  } from "../contracts/index.js";
23
23
  import { getJson, postJson } from "../http.js";
24
+ import { formatWhoamiWithAvatar } from "../output/avatar.js";
24
25
  import { requireLocalSession, resolveBaseUrl, toJsonOutput } from "../command-utils.js";
25
26
 
26
27
  function resolveClientName(): string | undefined {
@@ -57,6 +58,14 @@ function resolveVerificationUri(baseUrl: string, verificationUri: string): strin
57
58
  return verificationUri;
58
59
  }
59
60
 
61
+ function resolveDisplayName(input: {
62
+ displayName: string | null;
63
+ clerkUserId: string;
64
+ }): string {
65
+ const displayName = input.displayName?.trim();
66
+ return displayName && displayName.length > 0 ? displayName : input.clerkUserId;
67
+ }
68
+
60
69
  async function runLogin(options: { baseUrl?: string }): Promise<void> {
61
70
  const baseUrl = await resolveBaseUrl(options.baseUrl);
62
71
  intro("Barekey CLI login");
@@ -117,6 +126,8 @@ async function runLogin(options: { baseUrl?: string }): Promise<void> {
117
126
  orgId: poll.orgId,
118
127
  orgSlug: poll.orgSlug,
119
128
  clerkUserId: poll.clerkUserId,
129
+ displayName: poll.displayName,
130
+ email: poll.email,
120
131
  });
121
132
  const sessionId = buildSessionId(baseUrl, refreshed.clerkUserId);
122
133
 
@@ -138,7 +149,7 @@ async function runLogin(options: { baseUrl?: string }): Promise<void> {
138
149
 
139
150
  pollSpinner.stop("Login approved");
140
151
  pollActive = false;
141
- outro(`Logged in as ${pc.bold(refreshed.clerkUserId)}.`);
152
+ outro(`Signed in as ${pc.bold(resolveDisplayName(refreshed))}.`);
142
153
  return;
143
154
  }
144
155
 
@@ -186,9 +197,13 @@ async function runWhoami(options: { json?: boolean }): Promise<void> {
186
197
  return;
187
198
  }
188
199
 
189
- console.log(`${pc.bold("User")}: ${session.clerkUserId}`);
190
- console.log(`${pc.bold("Current org")}: ${session.orgSlug}`);
191
- console.log(`${pc.bold("Source")}: ${session.source}`);
200
+ console.log(
201
+ await formatWhoamiWithAvatar({
202
+ displayName: resolveDisplayName(session),
203
+ email: session.email,
204
+ imageUrl: session.imageUrl,
205
+ }),
206
+ );
192
207
  }
193
208
 
194
209
  export function registerAuthCommands(program: Command): void {
@@ -8,12 +8,9 @@ import { promptForOrganizationSlug } from "./target-prompts.js";
8
8
 
9
9
  async function runBillingCatalog(options: { json?: boolean }) {
10
10
  const local = await requireLocalSession();
11
- const authProvider = createCliAuthProvider();
12
- const accessToken = await authProvider.getAccessToken();
13
11
  const response = await getJson({
14
12
  baseUrl: local.baseUrl,
15
13
  path: "/v1/cli/billing/catalog",
16
- accessToken,
17
14
  schema: BillingCatalogResponseSchema,
18
15
  });
19
16
 
@@ -75,6 +75,9 @@ export const ErrorEnvelopeSchema = Schema.Struct({
75
75
 
76
76
  export const CliSessionResponseSchema = Schema.Struct({
77
77
  clerkUserId: Schema.String,
78
+ displayName: Schema.NullOr(Schema.String),
79
+ email: Schema.NullOr(Schema.String),
80
+ imageUrl: Schema.NullOr(Schema.String),
78
81
  orgId: Schema.String,
79
82
  orgSlug: Schema.String,
80
83
  source: Schema.Literal("clerk", "cli"),
@@ -106,6 +109,8 @@ export const DevicePollApprovedSchema = Schema.Struct({
106
109
  orgId: Schema.String,
107
110
  orgSlug: Schema.String,
108
111
  clerkUserId: Schema.String,
112
+ displayName: Schema.NullOr(Schema.String),
113
+ email: Schema.NullOr(Schema.String),
109
114
  requestId: Schema.optional(Schema.String),
110
115
  });
111
116
 
@@ -122,6 +127,8 @@ export const RefreshResponseSchema = Schema.Struct({
122
127
  orgId: Schema.String,
123
128
  orgSlug: Schema.String,
124
129
  clerkUserId: Schema.String,
130
+ displayName: Schema.NullOr(Schema.String),
131
+ email: Schema.NullOr(Schema.String),
125
132
  requestId: Schema.optional(Schema.String),
126
133
  });
127
134
 
@@ -0,0 +1,157 @@
1
+ import { Jimp } from "jimp";
2
+
3
+ const DEFAULT_AVATAR_COLUMNS = 10;
4
+ const DEFAULT_AVATAR_ROWS = 8;
5
+
6
+ type Rgba = {
7
+ red: number;
8
+ green: number;
9
+ blue: number;
10
+ alpha: number;
11
+ };
12
+
13
+ function supportsAnsiAvatar(): boolean {
14
+ if (!process.stdout.isTTY) {
15
+ return false;
16
+ }
17
+
18
+ if ((process.env.NO_COLOR ?? "").trim().length > 0) {
19
+ return false;
20
+ }
21
+
22
+ const term = (process.env.TERM ?? "").toLowerCase();
23
+ if (term === "dumb") {
24
+ return false;
25
+ }
26
+
27
+ return true;
28
+ }
29
+
30
+ function pixelOffset(width: number, x: number, y: number): number {
31
+ return (y * width + x) * 4;
32
+ }
33
+
34
+ function readPixel(data: Buffer, width: number, x: number, y: number): Rgba {
35
+ const offset = pixelOffset(width, x, y);
36
+ return {
37
+ red: data[offset] ?? 0,
38
+ green: data[offset + 1] ?? 0,
39
+ blue: data[offset + 2] ?? 0,
40
+ alpha: data[offset + 3] ?? 0,
41
+ };
42
+ }
43
+
44
+ function isOpaque(pixel: Rgba): boolean {
45
+ return pixel.alpha >= 96;
46
+ }
47
+
48
+ function foregroundColor(pixel: Rgba): string {
49
+ return `\u001b[38;2;${pixel.red};${pixel.green};${pixel.blue}m`;
50
+ }
51
+
52
+ function backgroundColor(pixel: Rgba): string {
53
+ return `\u001b[48;2;${pixel.red};${pixel.green};${pixel.blue}m`;
54
+ }
55
+
56
+ function renderPixelPair(top: Rgba, bottom: Rgba): string {
57
+ const topOpaque = isOpaque(top);
58
+ const bottomOpaque = isOpaque(bottom);
59
+
60
+ if (!topOpaque && !bottomOpaque) {
61
+ return " ";
62
+ }
63
+
64
+ if (topOpaque && bottomOpaque) {
65
+ return `${foregroundColor(top)}${backgroundColor(bottom)}▀`;
66
+ }
67
+
68
+ if (topOpaque) {
69
+ return `${foregroundColor(top)}▀`;
70
+ }
71
+
72
+ return `${foregroundColor(bottom)}▄`;
73
+ }
74
+
75
+ async function fetchAvatarBuffer(imageUrl: string): Promise<Buffer> {
76
+ const response = await fetch(imageUrl, {
77
+ signal: AbortSignal.timeout(4_000),
78
+ });
79
+ if (!response.ok) {
80
+ throw new Error(`Avatar request failed with HTTP ${response.status}.`);
81
+ }
82
+
83
+ return Buffer.from(await response.arrayBuffer());
84
+ }
85
+
86
+ async function renderAvatarLines(imageUrl: string): Promise<Array<string>> {
87
+ const bitmapRows = DEFAULT_AVATAR_ROWS * 2;
88
+ const buffer = await fetchAvatarBuffer(imageUrl);
89
+ const image = await Jimp.read(buffer);
90
+
91
+ image.cover({
92
+ w: DEFAULT_AVATAR_COLUMNS,
93
+ h: bitmapRows,
94
+ });
95
+ image.circle();
96
+
97
+ const { data, width, height } = image.bitmap;
98
+ const lines: Array<string> = [];
99
+
100
+ for (let y = 0; y < height; y += 2) {
101
+ let line = "";
102
+ for (let x = 0; x < width; x += 1) {
103
+ const top = readPixel(data, width, x, y);
104
+ const bottom = readPixel(data, width, x, Math.min(y + 1, height - 1));
105
+ line += renderPixelPair(top, bottom);
106
+ }
107
+ lines.push(`${line}\u001b[0m`);
108
+ }
109
+
110
+ return lines;
111
+ }
112
+
113
+ function joinAvatarAndText(
114
+ avatarLines: Array<string>,
115
+ textLines: Array<string>,
116
+ ): string {
117
+ const totalRows = Math.max(avatarLines.length, textLines.length);
118
+ const renderedRows: Array<string> = [];
119
+
120
+ for (let index = 0; index < totalRows; index += 1) {
121
+ const avatarLine = avatarLines[index] ?? " ".repeat(DEFAULT_AVATAR_COLUMNS);
122
+ const textLine = textLines[index] ?? "";
123
+ renderedRows.push(textLine.length > 0 ? `${avatarLine} ${textLine}` : avatarLine);
124
+ }
125
+
126
+ return renderedRows.join("\n");
127
+ }
128
+
129
+ /**
130
+ * Builds the terminal `whoami` output with a tiny ANSI avatar when supported.
131
+ *
132
+ * @param input The display name, email, and optional avatar image URL.
133
+ * @returns The formatted `whoami` string ready for stdout.
134
+ * @remarks Non-TTY terminals and avatar failures fall back to plain text without throwing.
135
+ * @lastModified 2026-03-19
136
+ * @author GPT-5.4
137
+ */
138
+ export async function formatWhoamiWithAvatar(input: {
139
+ displayName: string;
140
+ email: string | null;
141
+ imageUrl: string | null;
142
+ }): Promise<string> {
143
+ const textLines = [`Signed in as ${input.displayName}.`, input.email ?? ""].filter(
144
+ (line) => line.length > 0,
145
+ );
146
+
147
+ if (!supportsAnsiAvatar() || input.imageUrl === null) {
148
+ return textLines.join("\n");
149
+ }
150
+
151
+ try {
152
+ const avatarLines = await renderAvatarLines(input.imageUrl);
153
+ return joinAvatarAndText(avatarLines, textLines);
154
+ } catch {
155
+ return textLines.join("\n");
156
+ }
157
+ }