@blockrun/franklin 3.2.3 → 3.2.4
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/dist/banner.js +72 -73
- package/package.json +1 -1
package/dist/banner.js
CHANGED
|
@@ -2,47 +2,44 @@ import chalk from 'chalk';
|
|
|
2
2
|
// ─── Ben Franklin portrait ─────────────────────────────────────────────────
|
|
3
3
|
//
|
|
4
4
|
// Generated once, at build time, from the Joseph Duplessis 1785 oil painting
|
|
5
|
-
// of Benjamin Franklin (same source
|
|
6
|
-
//
|
|
5
|
+
// of Benjamin Franklin (same source as the portrait on the US $100 bill).
|
|
6
|
+
// Public domain image from Wikimedia Commons:
|
|
7
7
|
// https://commons.wikimedia.org/wiki/File:BenFranklinDuplessis.jpg
|
|
8
8
|
//
|
|
9
9
|
// Pipeline:
|
|
10
10
|
// 1. Crop the 2403×2971 original to a 1400×1400 square centred on the face
|
|
11
11
|
// (sips --cropToHeightWidth 1400 1400 --cropOffset 400 500)
|
|
12
|
-
// 2. Convert
|
|
13
|
-
//
|
|
14
|
-
//
|
|
12
|
+
// 2. Convert via chafa:
|
|
13
|
+
// chafa --size=30x14 --symbols=block --colors=256 ben-face.jpg
|
|
14
|
+
// 3. Strip cursor visibility control codes (\x1b[?25l / \x1b[?25h)
|
|
15
|
+
// 4. Paste here as hex-escaped string array (readable + diff-friendly)
|
|
15
16
|
//
|
|
16
|
-
//
|
|
17
|
-
// a 34×16 braille output gives 68×64 = 4,352 effective "pixels" — 2.7× the
|
|
18
|
-
// resolution of chafa half-block mode at the same visible size. For a face,
|
|
19
|
-
// which is all about silhouette + key features, this is a massive win.
|
|
17
|
+
// Visible dimensions: ~28 characters wide × 14 rows tall.
|
|
20
18
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// brand tinting, and it ships as a clean readable TS array.
|
|
19
|
+
// Rendered best in a 256-color or truecolor terminal. Degrades gracefully
|
|
20
|
+
// on ancient terminals — but those are long gone and we don't support them.
|
|
24
21
|
const BEN_PORTRAIT_ROWS = [
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'⣿⡟⠻⣿⣦⡀⠀⢁⡆⠀⠹⢿⣿⣮⣟⠿⣿⠏⠀⠀⣀⣴⣶⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
40
|
-
'⣿⣷⣄⠈⠿⣷⡀⣾⣿⡀⢦⢸⣿⡹⣿⣿⡆⣤⡐⠻⡻⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
22
|
+
'\x1b[0m\x1b[38;5;16;48;5;16m \x1b[38;5;232m▁\x1b[38;5;235;48;5;232m▂\x1b[38;5;58;48;5;233m▄\x1b[38;5;95;48;5;234m▆\x1b[38;5;137;48;5;58m▄\x1b[38;5;173m▅\x1b[48;5;94m▅\x1b[48;5;58m▆▅\x1b[48;5;237m▄\x1b[38;5;137;48;5;234m▃\x1b[38;5;235;48;5;233m▂ \x1b[38;5;233;48;5;232m▂▅\x1b[48;5;233m \x1b[0m',
|
|
23
|
+
'\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▗\x1b[38;5;233;48;5;236m▘\x1b[38;5;8;48;5;239m▌\x1b[38;5;95;48;5;137m▋\x1b[38;5;137;48;5;179m▘ \x1b[38;5;179;48;5;173m▃\x1b[48;5;179m \x1b[48;5;173m▊\x1b[38;5;58;48;5;137m▝\x1b[38;5;94;48;5;235m▖\x1b[38;5;234;48;5;233m▅▄▂ ▂▗▄▃\x1b[0m',
|
|
24
|
+
'\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▗\x1b[38;5;236;48;5;237m▍ \x1b[38;5;58;48;5;94m▋\x1b[38;5;95;48;5;173m▌\x1b[48;5;179m \x1b[38;5;179;48;5;215m▍\x1b[48;5;221m▔\x1b[38;5;222;48;5;180m▍\x1b[48;5;179m \x1b[38;5;173m▕\x1b[38;5;179;48;5;173m▅\x1b[38;5;137m▕\x1b[38;5;95;48;5;58m▍\x1b[38;5;58;48;5;235m▖\x1b[38;5;235;48;5;234m▖▃▄ \x1b[0m',
|
|
25
|
+
'\x1b[38;5;16;48;5;16m \x1b[38;5;233m▗\x1b[48;5;235m▏\x1b[38;5;237;48;5;238m▊\x1b[38;5;238;48;5;236m▌\x1b[38;5;236;48;5;58m▖\x1b[38;5;95;48;5;179m▌ \x1b[38;5;137m▗\x1b[38;5;94m▄\x1b[38;5;58m▄\x1b[38;5;94m▄\x1b[38;5;137m▖\x1b[38;5;173m▗\x1b[38;5;131m▗\x1b[38;5;58;48;5;137m▃\x1b[38;5;131;48;5;58m▘\x1b[38;5;234m▕\x1b[48;5;236m▖\x1b[38;5;236;48;5;235m▃ \x1b[38;5;234m▝\x1b[38;5;235;48;5;234m▃\x1b[0m',
|
|
26
|
+
'\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▂\x1b[38;5;236;48;5;234m▄\x1b[38;5;237;48;5;236m▗\x1b[38;5;8;48;5;239m▖\x1b[38;5;240;48;5;8m▎\x1b[38;5;94;48;5;236m▕\x1b[38;5;137;48;5;179m▍ \x1b[38;5;94;48;5;137m▝\x1b[38;5;173;48;5;94m▂\x1b[38;5;137;48;5;58m▂\x1b[48;5;94m▃\x1b[48;5;179m▘\x1b[38;5;173m▝\x1b[38;5;137;48;5;235m▍\x1b[38;5;94;48;5;236m▝\x1b[38;5;235;48;5;94m▖\x1b[38;5;52;48;5;58m▖\x1b[38;5;235;48;5;233m▝\x1b[48;5;236m▁\x1b[48;5;235m \x1b[0m',
|
|
27
|
+
'\x1b[38;5;232;48;5;16m▗\x1b[38;5;233;48;5;236m▌\x1b[38;5;95;48;5;239m▅\x1b[48;5;240m▃\x1b[38;5;94;48;5;238m▖\x1b[38;5;240;48;5;8m▝\x1b[38;5;95;48;5;236m▘\x1b[38;5;236;48;5;95m▘\x1b[38;5;173;48;5;179m▏ \x1b[38;5;215m▄ \x1b[38;5;179;48;5;137m▅\x1b[38;5;137;48;5;179m▘\x1b[38;5;216m▘\x1b[38;5;179;48;5;216m▃\x1b[48;5;94m▌\x1b[38;5;94;48;5;131m▘\x1b[38;5;95;48;5;94m▋\x1b[38;5;94;48;5;52m▃\x1b[38;5;52;48;5;233m▎\x1b[38;5;233;48;5;235m▅\x1b[38;5;234m▂ \x1b[0m',
|
|
28
|
+
'\x1b[38;5;233;48;5;232m▕\x1b[38;5;234;48;5;236m▘\x1b[38;5;8;48;5;95m▌ \x1b[38;5;236m▃\x1b[38;5;58;48;5;234m▘\x1b[38;5;94m▝\x1b[48;5;137m▎\x1b[38;5;179;48;5;173m▍\x1b[38;5;173;48;5;179m▌▆▖▃▞\x1b[38;5;94;48;5;173m▗\x1b[48;5;179m▄\x1b[38;5;179;48;5;58m▘\x1b[38;5;94;48;5;52m▝\x1b[38;5;130;48;5;131m▃\x1b[38;5;94;48;5;58m▍\x1b[38;5;52;48;5;232m▎\x1b[38;5;232;48;5;233m▌\x1b[38;5;233;48;5;234m▏\x1b[38;5;234;48;5;235m▎\x1b[38;5;236m▌▅▄ \x1b[0m',
|
|
29
|
+
'\x1b[38;5;232;48;5;235m▋\x1b[38;5;58;48;5;236m▝\x1b[48;5;58m \x1b[38;5;239;48;5;94m▅\x1b[38;5;237;48;5;235m▂\x1b[38;5;235;48;5;233m▂\x1b[38;5;234;48;5;94m▄\x1b[38;5;94;48;5;137m▖\x1b[48;5;173m \x1b[38;5;173;48;5;179m▃ \x1b[38;5;137m▂▃▂\x1b[38;5;131;48;5;137m▃\x1b[38;5;58;48;5;131m▝\x1b[38;5;94;48;5;52m▅\x1b[48;5;94m \x1b[48;5;58m▍\x1b[38;5;235;48;5;232m▎\x1b[38;5;232;48;5;233m▋\x1b[38;5;233;48;5;234m▍\x1b[38;5;235;48;5;236m▏ \x1b[38;5;236;48;5;235m▎ \x1b[0m',
|
|
30
|
+
'\x1b[38;5;234;48;5;235m▏\x1b[38;5;236;48;5;237m▋\x1b[38;5;237;48;5;8m▃\x1b[38;5;235;48;5;238m▗\x1b[38;5;237m▖\x1b[38;5;58;48;5;234m▌\x1b[38;5;234;48;5;233m▎\x1b[38;5;236;48;5;137m▎\x1b[38;5;137;48;5;173m▄ \x1b[38;5;173;48;5;179m▄▃ \x1b[38;5;179;48;5;215m▅\x1b[38;5;173;48;5;179m▄\x1b[38;5;179;48;5;137m▘\x1b[38;5;137;48;5;131m▌\x1b[48;5;94m \x1b[38;5;58m▗\x1b[38;5;233;48;5;58m▗\x1b[48;5;233m \x1b[38;5;234;48;5;236m▘ \x1b[38;5;236;48;5;235m▃▞\x1b[38;5;235;48;5;236m▄\x1b[48;5;235m \x1b[0m',
|
|
31
|
+
'\x1b[38;5;234;48;5;235m▏▆\x1b[38;5;235;48;5;237m▌\x1b[38;5;236m▝\x1b[38;5;237;48;5;234m▍\x1b[38;5;234;48;5;233m▖\x1b[38;5;240;48;5;234m▗\x1b[38;5;101;48;5;186m▌\x1b[38;5;137m▝\x1b[48;5;137m \x1b[48;5;173m▆▄▃\x1b[38;5;131m▂\x1b[38;5;130;48;5;137m▂\x1b[38;5;58;48;5;94m▃\x1b[48;5;58m \x1b[38;5;234;48;5;233m▏\x1b[38;5;235;48;5;234m▅\x1b[48;5;236m▌ ▝ \x1b[48;5;235m \x1b[0m',
|
|
32
|
+
'\x1b[38;5;234;48;5;233m▕\x1b[38;5;239;48;5;235m▂\x1b[38;5;95m▃\x1b[48;5;237m▄\x1b[48;5;236m▄\x1b[48;5;235m▄\x1b[38;5;236;48;5;240m▘\x1b[38;5;101;48;5;95m▕\x1b[48;5;186m▖\x1b[38;5;179;48;5;229m▝\x1b[38;5;223;48;5;137m▃\x1b[38;5;137;48;5;131m▁\x1b[38;5;95m▅\x1b[38;5;94m▂\x1b[48;5;94m \x1b[38;5;58m▗\x1b[38;5;94;48;5;58m▔\x1b[38;5;236m▁ \x1b[48;5;235m▆\x1b[38;5;235;48;5;236m▍\x1b[38;5;236;48;5;235m▆\x1b[48;5;236m \x1b[38;5;235m▅\x1b[48;5;235m \x1b[0m',
|
|
33
|
+
'\x1b[38;5;237;48;5;95m▔ \x1b[38;5;137;48;5;101m▝\x1b[48;5;187m▅\x1b[38;5;180;48;5;229m▂\x1b[38;5;143;48;5;222m▔\x1b[38;5;186;48;5;58m▅\x1b[38;5;179m▂\x1b[38;5;95m▁\x1b[38;5;235m▂\x1b[38;5;236m▄\x1b[48;5;233m▌\x1b[38;5;235m▔\x1b[38;5;233;48;5;236m▅\x1b[38;5;234m▃\x1b[38;5;235m▁ ▔\x1b[48;5;235m \x1b[0m',
|
|
34
|
+
'\x1b[38;5;101;48;5;137m▔\x1b[38;5;95;48;5;101m▄▔\x1b[38;5;101;48;5;95m▄ ▗ \x1b[38;5;240m▖\x1b[38;5;95;48;5;101m▘\x1b[38;5;137m▔\x1b[48;5;222m▅\x1b[48;5;186m▃\x1b[48;5;179m▂\x1b[38;5;101;48;5;95m▌\x1b[48;5;58m \x1b[38;5;238;48;5;236m▁\x1b[38;5;180;48;5;234m▃\x1b[48;5;235m▄\x1b[38;5;179;48;5;234m▃\x1b[38;5;95m▁\x1b[38;5;234;48;5;235m▊\x1b[48;5;236m▆\x1b[38;5;235m▃\x1b[38;5;234m▂\x1b[38;5;235m▁ \x1b[38;5;236;48;5;235m▎\x1b[0m',
|
|
35
|
+
'\x1b[38;5;137;48;5;137m \x1b[48;5;95m▄ \x1b[38;5;95;48;5;101m▖\x1b[48;5;137m▝\x1b[48;5;95m \x1b[38;5;101m▅\x1b[48;5;239m▋\x1b[48;5;95m \x1b[38;5;95;48;5;137m▋\x1b[38;5;101;48;5;95m▍\x1b[38;5;95;48;5;101m▖\x1b[38;5;101;48;5;95m▆\x1b[38;5;239m▗\x1b[38;5;101m▄ \x1b[38;5;95;48;5;137m▅\x1b[38;5;137;48;5;180m▅\x1b[38;5;180;48;5;186m▃\x1b[48;5;143m▆\x1b[38;5;95m▔\x1b[38;5;143;48;5;235m▖\x1b[48;5;234m \x1b[38;5;235m▆\x1b[38;5;234;48;5;235m▝\x1b[38;5;235;48;5;234m▞\x1b[38;5;234;48;5;235m▄ \x1b[0m',
|
|
41
36
|
];
|
|
42
37
|
// ─── FRANKLIN text banner (gold → emerald gradient) ────────────────────────
|
|
43
38
|
//
|
|
44
|
-
// Kept from v3.1.0. 6 block-letter rows
|
|
45
|
-
//
|
|
39
|
+
// Kept from v3.1.0. The text is laid out as 6 block-letter rows. Each row
|
|
40
|
+
// is tinted with a color interpolated between GOLD_START and EMERALD_END,
|
|
41
|
+
// giving the smooth vertical gradient that's been Franklin's banner since
|
|
42
|
+
// v3.1.0.
|
|
46
43
|
const FRANKLIN_ART = [
|
|
47
44
|
' ███████╗██████╗ █████╗ ███╗ ██╗██╗ ██╗██╗ ██╗███╗ ██╗',
|
|
48
45
|
' ██╔════╝██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝██║ ██║████╗ ██║',
|
|
@@ -72,19 +69,23 @@ function interpolateHex(start, end, t) {
|
|
|
72
69
|
}
|
|
73
70
|
// ─── Banner layout ─────────────────────────────────────────────────────────
|
|
74
71
|
// Minimum terminal width to show the side-by-side portrait + text layout.
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
const MIN_WIDTH_FOR_PORTRAIT =
|
|
72
|
+
// The portrait is ~28 chars, the FRANKLIN text is ~65 chars, plus a 3-char
|
|
73
|
+
// gap = 96 chars. We add a small margin so 100 cols is the threshold.
|
|
74
|
+
const MIN_WIDTH_FOR_PORTRAIT = 100;
|
|
78
75
|
/**
|
|
79
|
-
* Pad a line to an exact visual width
|
|
80
|
-
*
|
|
81
|
-
* codepoint count.
|
|
76
|
+
* Pad a line to an exact visual width, ignoring ANSI escape codes when
|
|
77
|
+
* measuring. Used to align the portrait's right edge before the text block.
|
|
82
78
|
*/
|
|
83
|
-
function
|
|
84
|
-
|
|
79
|
+
function padVisible(s, targetWidth) {
|
|
80
|
+
// Strip ANSI color codes to measure visible length
|
|
81
|
+
// eslint-disable-next-line no-control-regex
|
|
82
|
+
const visible = s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
83
|
+
// Unicode block characters are width 1 (they're half-blocks, not double-width)
|
|
84
|
+
const current = [...visible].length;
|
|
85
85
|
if (current >= targetWidth)
|
|
86
86
|
return s;
|
|
87
|
-
|
|
87
|
+
// Append a reset + padding so background colors don't bleed into the gap
|
|
88
|
+
return s + '\x1b[0m' + ' '.repeat(targetWidth - current);
|
|
88
89
|
}
|
|
89
90
|
export function printBanner(version) {
|
|
90
91
|
const termWidth = process.stdout.columns ?? 80;
|
|
@@ -97,42 +98,37 @@ export function printBanner(version) {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
/**
|
|
100
|
-
* Full layout: Ben Franklin
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* giving the classic "portrait and nameplate" composition.
|
|
101
|
+
* Full layout: Ben Franklin portrait on the left, FRANKLIN text block on the
|
|
102
|
+
* right. Portrait is 14 rows × ~28 chars, text is 6 rows — text is vertically
|
|
103
|
+
* centred inside the portrait with 4 rows of padding above and 4 below,
|
|
104
|
+
* tagline sitting right under the FRANKLIN block.
|
|
105
105
|
*
|
|
106
|
-
* row 1
|
|
107
|
-
* row 2
|
|
108
|
-
* row 3
|
|
109
|
-
* row 4
|
|
110
|
-
* row 5
|
|
111
|
-
* row 6
|
|
112
|
-
* row 7
|
|
113
|
-
* row 8
|
|
114
|
-
* row 9
|
|
115
|
-
* row 10
|
|
116
|
-
* row 11
|
|
117
|
-
* row 12
|
|
118
|
-
* row 13
|
|
106
|
+
* [portrait row 1] (empty)
|
|
107
|
+
* [portrait row 2] (empty)
|
|
108
|
+
* [portrait row 3] (empty)
|
|
109
|
+
* [portrait row 4] (empty)
|
|
110
|
+
* [portrait row 5] ███████╗██████╗ █████╗ ...
|
|
111
|
+
* [portrait row 6] ██╔════╝██╔══██╗██╔══██╗...
|
|
112
|
+
* [portrait row 7] █████╗ ██████╔╝███████║...
|
|
113
|
+
* [portrait row 8] ██╔══╝ ██╔══██╗██╔══██║...
|
|
114
|
+
* [portrait row 9] ██║ ██║ ██║██║ ██║...
|
|
115
|
+
* [portrait row 10] ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝...
|
|
116
|
+
* [portrait row 11] blockrun.ai · The AI agent with a wallet · vX
|
|
117
|
+
* [portrait row 12] (empty)
|
|
118
|
+
* [portrait row 13] (empty)
|
|
119
|
+
* [portrait row 14] (empty)
|
|
119
120
|
*/
|
|
120
121
|
function printSideBySide(version) {
|
|
121
|
-
const TEXT_TOP_OFFSET = 4; //
|
|
122
|
-
const PORTRAIT_WIDTH =
|
|
123
|
-
const GAP = ' ';
|
|
122
|
+
const TEXT_TOP_OFFSET = 4; // rows of portrait above the text
|
|
123
|
+
const PORTRAIT_WIDTH = 29; // columns (char width) of the portrait + 1 pad
|
|
124
|
+
const GAP = ' '; // gap between portrait and text
|
|
124
125
|
const portraitRows = BEN_PORTRAIT_ROWS;
|
|
125
126
|
const textRows = FRANKLIN_ART.length;
|
|
126
127
|
const totalRows = Math.max(portraitRows.length, TEXT_TOP_OFFSET + textRows + 2);
|
|
127
|
-
// Tint the braille portrait in dim white for a "pencil portrait" feel.
|
|
128
|
-
// Braille chars carry no colour on their own — chalk wraps them in an
|
|
129
|
-
// ANSI colour sequence at render time.
|
|
130
|
-
const portraitTint = chalk.hex('#E8E8E8');
|
|
131
128
|
for (let i = 0; i < totalRows; i++) {
|
|
132
|
-
const
|
|
133
|
-
?
|
|
129
|
+
const portraitLine = i < portraitRows.length
|
|
130
|
+
? padVisible(portraitRows[i], PORTRAIT_WIDTH)
|
|
134
131
|
: ' '.repeat(PORTRAIT_WIDTH);
|
|
135
|
-
const portraitLine = portraitTint(rawPortraitLine);
|
|
136
132
|
// Text column content
|
|
137
133
|
let textCol = '';
|
|
138
134
|
const textIdx = i - TEXT_TOP_OFFSET;
|
|
@@ -144,21 +140,24 @@ function printSideBySide(version) {
|
|
|
144
140
|
}
|
|
145
141
|
else if (textIdx === textRows) {
|
|
146
142
|
// Tagline row sits right under the FRANKLIN block.
|
|
147
|
-
// The big block-letter FRANKLIN above already says the product
|
|
148
|
-
// — the tagline uses that
|
|
149
|
-
// (blockrun.ai
|
|
150
|
-
//
|
|
143
|
+
// The big block-letter "FRANKLIN" above already says the product
|
|
144
|
+
// name — the tagline uses that real estate for the parent brand URL
|
|
145
|
+
// (blockrun.ai, which is a real live domain — unlike franklin.run
|
|
146
|
+
// which we own but haven't deployed yet, see v3.1.0 changelog).
|
|
151
147
|
textCol =
|
|
152
148
|
chalk.bold.hex(GOLD_START)(' blockrun.ai') +
|
|
153
149
|
chalk.dim(' · The AI agent with a wallet · v' + version);
|
|
154
150
|
}
|
|
155
|
-
|
|
151
|
+
// Write with a reset at the very start to prevent stray bg from the
|
|
152
|
+
// previous line bleeding into the current row's portrait column.
|
|
153
|
+
process.stdout.write('\x1b[0m' + portraitLine + GAP + textCol + '\x1b[0m\n');
|
|
156
154
|
}
|
|
155
|
+
// Trailing blank line for breathing room
|
|
157
156
|
process.stdout.write('\n');
|
|
158
157
|
}
|
|
159
158
|
/**
|
|
160
159
|
* Compact layout for narrow terminals: just the FRANKLIN text block with
|
|
161
|
-
* its gradient, no portrait.
|
|
160
|
+
* its gradient, no portrait. Matches the v3.1.0 banner exactly.
|
|
162
161
|
*/
|
|
163
162
|
function printTextOnly(version) {
|
|
164
163
|
const textRows = FRANKLIN_ART.length;
|
package/package.json
CHANGED