@stevezhou/sisu 0.1.3 → 0.1.5
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/logo.js +150 -7
- package/dist/main.js +1 -1
- package/dist/mark.js +76 -0
- package/dist/pager/render.js +16 -20
- package/dist/tree.js +116 -0
- package/dist/tui.js +1 -1
- package/package.json +1 -1
package/dist/logo.js
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sisuTreeLines = exports.sisuTreeArt = exports.sisuMarkLines = exports.sisuMarkArt = void 0;
|
|
3
4
|
exports.sisuMobiusArt = sisuMobiusArt;
|
|
4
5
|
exports.sisuWordmark = sisuWordmark;
|
|
6
|
+
exports.displayWidth = displayWidth;
|
|
7
|
+
exports.sisuSplash = sisuSplash;
|
|
8
|
+
exports.sisuWelcomeCopy = sisuWelcomeCopy;
|
|
5
9
|
exports.sisuBanner = sisuBanner;
|
|
6
10
|
exports.stripAnsi = stripAnsi;
|
|
11
|
+
var mark_1 = require("./mark");
|
|
12
|
+
Object.defineProperty(exports, "sisuMarkArt", { enumerable: true, get: function () { return mark_1.sisuMarkArt; } });
|
|
13
|
+
Object.defineProperty(exports, "sisuMarkLines", { enumerable: true, get: function () { return mark_1.sisuMarkLines; } });
|
|
14
|
+
var tree_1 = require("./tree");
|
|
15
|
+
Object.defineProperty(exports, "sisuTreeArt", { enumerable: true, get: function () { return tree_1.sisuTreeArt; } });
|
|
16
|
+
Object.defineProperty(exports, "sisuTreeLines", { enumerable: true, get: function () { return tree_1.sisuTreeLines; } });
|
|
17
|
+
const mark_2 = require("./mark");
|
|
7
18
|
const mobius_1 = require("./mobius");
|
|
19
|
+
const tree_2 = require("./tree");
|
|
20
|
+
const RESET = '\x1b[0m';
|
|
21
|
+
const TERRACOTTA = '\x1b[38;2;184;90;58m';
|
|
22
|
+
const INK = '\x1b[38;2;220;214;204m';
|
|
23
|
+
const INK_DIM = '\x1b[38;2;140;132;120m';
|
|
24
|
+
const HEADLINE = '思有所溯';
|
|
25
|
+
const TAGLINE = '为科研而生的工作台——记录退到思考之后,不打扰任何一念。';
|
|
26
|
+
const COLOPHON = [
|
|
27
|
+
'对话、文献与数据,落笔成档',
|
|
28
|
+
'每个结论,都能沿枝回到它的根',
|
|
29
|
+
'众人的知识彼此嫁接,长成一片林',
|
|
30
|
+
];
|
|
31
|
+
const NUMERALS = ['一', '二', '三'];
|
|
8
32
|
function sisuMobiusArt(columns = 80, phase = 0, color = false) {
|
|
9
33
|
return (0, mobius_1.renderMobiusFrame)({
|
|
10
34
|
cols: (0, mobius_1.mobiusFrameWidth)(columns),
|
|
@@ -16,14 +40,133 @@ function sisuMobiusArt(columns = 80, phase = 0, color = false) {
|
|
|
16
40
|
function sisuWordmark() {
|
|
17
41
|
return ['思溯', 'SISU'].join('\n');
|
|
18
42
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
43
|
+
/** Terminal cells, not JS string length — CJK and ∞ must sit on the grid. */
|
|
44
|
+
function displayWidth(text) {
|
|
45
|
+
let width = 0;
|
|
46
|
+
for (const ch of stripAnsi(text)) {
|
|
47
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
48
|
+
width += isWide(code) ? 2 : 1;
|
|
49
|
+
}
|
|
50
|
+
return width;
|
|
51
|
+
}
|
|
52
|
+
function isWide(code) {
|
|
53
|
+
return ((code >= 0x1100 && code <= 0x115f) ||
|
|
54
|
+
(code >= 0x2e80 && code <= 0xa4cf && code !== 0x303f) ||
|
|
55
|
+
(code >= 0xac00 && code <= 0xd7a3) ||
|
|
56
|
+
(code >= 0xf900 && code <= 0xfaff) ||
|
|
57
|
+
(code >= 0xfe10 && code <= 0xfe19) ||
|
|
58
|
+
(code >= 0xfe30 && code <= 0xfe6f) ||
|
|
59
|
+
(code >= 0xff00 && code <= 0xff60) ||
|
|
60
|
+
(code >= 0xffe0 && code <= 0xffe6));
|
|
61
|
+
}
|
|
62
|
+
function paint(text, prefix, color) {
|
|
63
|
+
if (!color || !text)
|
|
64
|
+
return text;
|
|
65
|
+
return `${prefix}${text}${RESET}`;
|
|
66
|
+
}
|
|
67
|
+
function infinityMark(color) {
|
|
68
|
+
if (!color)
|
|
69
|
+
return '∞';
|
|
70
|
+
const [r, g, b] = (0, mark_2.markRgb)(0, 2);
|
|
71
|
+
return `\x1b[38;2;${r};${g};${b}m∞${RESET}`;
|
|
72
|
+
}
|
|
73
|
+
function lockup(color) {
|
|
74
|
+
const inf = infinityMark(color);
|
|
75
|
+
const name = paint('思溯', INK, color);
|
|
76
|
+
const latin = paint('SiSu', INK_DIM, color);
|
|
77
|
+
return [`${inf} ${name}`, ` ${latin}`];
|
|
78
|
+
}
|
|
79
|
+
function colophon(columns, color) {
|
|
80
|
+
const lines = [];
|
|
81
|
+
for (let i = 0; i < COLOPHON.length; i += 1) {
|
|
82
|
+
const num = paint(NUMERALS[i], TERRACOTTA, color);
|
|
83
|
+
const body = paint(COLOPHON[i], INK_DIM, color);
|
|
84
|
+
const line = `${num} ${body}`;
|
|
85
|
+
if (displayWidth(line) + 2 <= columns)
|
|
86
|
+
lines.push(line);
|
|
87
|
+
}
|
|
88
|
+
return lines;
|
|
89
|
+
}
|
|
90
|
+
function padLeft(text, n) {
|
|
91
|
+
return `${' '.repeat(Math.max(0, n))}${text}`;
|
|
92
|
+
}
|
|
93
|
+
function center(text, width) {
|
|
94
|
+
const vis = displayWidth(text);
|
|
95
|
+
const pad = Math.max(0, Math.floor((width - vis) / 2));
|
|
96
|
+
return padLeft(text, pad);
|
|
97
|
+
}
|
|
98
|
+
function copyColumn(columns, color, compact) {
|
|
99
|
+
const indent = 2;
|
|
100
|
+
const lines = [
|
|
101
|
+
...lockup(color).map((line) => padLeft(line, indent)),
|
|
25
102
|
'',
|
|
26
|
-
|
|
103
|
+
padLeft(paint(HEADLINE, INK, color), indent),
|
|
104
|
+
];
|
|
105
|
+
if (!compact && displayWidth(TAGLINE) + indent <= columns) {
|
|
106
|
+
lines.push(padLeft(paint(TAGLINE, INK_DIM, color), indent));
|
|
107
|
+
}
|
|
108
|
+
if (!compact) {
|
|
109
|
+
const notes = colophon(columns, color);
|
|
110
|
+
if (notes.length) {
|
|
111
|
+
lines.push('');
|
|
112
|
+
for (const note of notes)
|
|
113
|
+
lines.push(padLeft(note, indent));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return lines;
|
|
117
|
+
}
|
|
118
|
+
function treeColumn(columns, color) {
|
|
119
|
+
const raw = (0, tree_2.sisuTreeLines)(columns);
|
|
120
|
+
const painted = (0, tree_2.sisuTreeArt)(columns, color).split('\n');
|
|
121
|
+
const treeWidth = raw.reduce((max, line) => Math.max(max, line.length), 0);
|
|
122
|
+
const pad = Math.max(0, Math.floor((columns - treeWidth) / 2));
|
|
123
|
+
return painted.map((line, i) => {
|
|
124
|
+
const vis = raw[i]?.length ?? displayWidth(line);
|
|
125
|
+
return padLeft(`${line}${' '.repeat(Math.max(0, treeWidth - vis))}`, pad);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Login-page splash: lockup + 思有所溯 + 题跋 over the 溯源之树.
|
|
130
|
+
* Side-by-side on a wide terminal; stacked when the sheet is narrow.
|
|
131
|
+
*/
|
|
132
|
+
function sisuSplash(columns = 80, color = true) {
|
|
133
|
+
const width = Math.max(20, Math.floor(columns));
|
|
134
|
+
const compact = width < 52;
|
|
135
|
+
const copy = copyColumn(width, color, compact);
|
|
136
|
+
const tree = treeColumn(width, color);
|
|
137
|
+
if (width >= 100) {
|
|
138
|
+
const gap = 3;
|
|
139
|
+
const leftW = Math.max(...copy.map((line) => displayWidth(line)));
|
|
140
|
+
const rightW = width - leftW - gap;
|
|
141
|
+
const right = treeColumn(rightW, color);
|
|
142
|
+
const rows = Math.max(copy.length, right.length);
|
|
143
|
+
const merged = [''];
|
|
144
|
+
for (let i = 0; i < rows; i += 1) {
|
|
145
|
+
const left = copy[i] ?? '';
|
|
146
|
+
const pad = Math.max(0, leftW + gap - displayWidth(left));
|
|
147
|
+
merged.push(`${left}${' '.repeat(pad)}${right[i] ?? ''}`);
|
|
148
|
+
}
|
|
149
|
+
merged.push('');
|
|
150
|
+
return merged.join('\n');
|
|
151
|
+
}
|
|
152
|
+
return ['', ...copy, '', ...tree, ''].join('\n');
|
|
153
|
+
}
|
|
154
|
+
function sisuWelcomeCopy(guest, color = true) {
|
|
155
|
+
const lines = [
|
|
156
|
+
...lockup(color),
|
|
157
|
+
paint(HEADLINE, INK, color),
|
|
158
|
+
];
|
|
159
|
+
if (guest) {
|
|
160
|
+
lines.push(paint('Sign in to start a conversation.', INK_DIM, color));
|
|
161
|
+
lines.push(paint('/login browser /help commands', INK_DIM, color));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
lines.push(paint('Ask anything, or type /help.', INK_DIM, color));
|
|
165
|
+
}
|
|
166
|
+
return lines;
|
|
167
|
+
}
|
|
168
|
+
function sisuBanner(columns = 80, _phase = 0, color = false) {
|
|
169
|
+
return sisuSplash(columns, color);
|
|
27
170
|
}
|
|
28
171
|
function stripAnsi(text) {
|
|
29
172
|
return text.replace(/\x1b\[[0-9;]*m/g, '');
|
package/dist/main.js
CHANGED
|
@@ -28,7 +28,7 @@ Usage:
|
|
|
28
28
|
sisu history
|
|
29
29
|
sisu thread <conversation-id>
|
|
30
30
|
sisu training --on|--off
|
|
31
|
-
sisu interactive TUI (
|
|
31
|
+
sisu interactive TUI (welcome tree)
|
|
32
32
|
sisu help
|
|
33
33
|
|
|
34
34
|
Auth and workspaces live in $SISU_HOME (default ~/.sisu), shared with Desktop.
|
package/dist/mark.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Hand-drawn SiSu Möbius mark — the web ∞ ribbon, not a 3D rasterizer. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.markRgb = markRgb;
|
|
5
|
+
exports.sisuMarkLines = sisuMarkLines;
|
|
6
|
+
exports.sisuMarkArt = sisuMarkArt;
|
|
7
|
+
exports.sisuMarkWidth = sisuMarkWidth;
|
|
8
|
+
exports.sisuMarkHeight = sisuMarkHeight;
|
|
9
|
+
const RESET = '\x1b[0m';
|
|
10
|
+
const MARK_WIDE = [
|
|
11
|
+
' ▄▄████▄▄ ▄▄████▄▄ ',
|
|
12
|
+
' ▄██▀ ▀██▄ ▄██▀ ▀██▄ ',
|
|
13
|
+
' ██ ▀█▄ ▄█▀ ██ ',
|
|
14
|
+
' ██ ▀████▀ ██ ',
|
|
15
|
+
' ██ ▄████▄ ██ ',
|
|
16
|
+
' ██ ▄█▀ ▀█▄ ██ ',
|
|
17
|
+
' ▀██▄ ▄██▀ ▀██▄ ▄██▀ ',
|
|
18
|
+
' ▀▀████▀▀ ▀▀████▀▀ ',
|
|
19
|
+
];
|
|
20
|
+
const MARK_NARROW = [
|
|
21
|
+
' ▄██▄ ▄██▄ ',
|
|
22
|
+
' █▀ ▀█▄ ▄█▀ ▀█ ',
|
|
23
|
+
' █ ▀██▀ █ ',
|
|
24
|
+
' █ ▄██▄ █ ',
|
|
25
|
+
' █▄ ▄█▀ ▀█▄ ▄█ ',
|
|
26
|
+
' ▀██▀ ▀██▀ ',
|
|
27
|
+
];
|
|
28
|
+
function lerp(a, b, t) {
|
|
29
|
+
return a + (b - a) * t;
|
|
30
|
+
}
|
|
31
|
+
/** Brand gradient along the ribbon: blue → purple → gold. */
|
|
32
|
+
function markRgb(x, width) {
|
|
33
|
+
const t = width <= 1 ? 0 : Math.max(0, Math.min(1, x / (width - 1)));
|
|
34
|
+
if (t < 0.5) {
|
|
35
|
+
const k = t / 0.5;
|
|
36
|
+
return [
|
|
37
|
+
Math.round(lerp(37, 124, k)),
|
|
38
|
+
Math.round(lerp(99, 58, k)),
|
|
39
|
+
Math.round(lerp(235, 237, k)),
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
const k = (t - 0.5) / 0.5;
|
|
43
|
+
return [
|
|
44
|
+
Math.round(lerp(124, 217, k)),
|
|
45
|
+
Math.round(lerp(58, 119, k)),
|
|
46
|
+
Math.round(lerp(237, 6, k)),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
function paintLine(line) {
|
|
50
|
+
const width = line.length;
|
|
51
|
+
let out = '';
|
|
52
|
+
for (let i = 0; i < line.length; i += 1) {
|
|
53
|
+
const ch = line[i];
|
|
54
|
+
if (ch === ' ') {
|
|
55
|
+
out += ' ';
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const [r, g, b] = markRgb(i, width);
|
|
59
|
+
out += `\x1b[38;2;${r};${g};${b}m${ch}`;
|
|
60
|
+
}
|
|
61
|
+
return `${out}${RESET}`;
|
|
62
|
+
}
|
|
63
|
+
function sisuMarkLines(columns = 80) {
|
|
64
|
+
return columns >= 48 ? MARK_WIDE : MARK_NARROW;
|
|
65
|
+
}
|
|
66
|
+
function sisuMarkArt(columns = 80, color = true) {
|
|
67
|
+
const lines = sisuMarkLines(columns);
|
|
68
|
+
const painted = color ? lines.map(paintLine) : lines;
|
|
69
|
+
return painted.join('\n');
|
|
70
|
+
}
|
|
71
|
+
function sisuMarkWidth(columns = 80) {
|
|
72
|
+
return sisuMarkLines(columns).reduce((max, line) => Math.max(max, line.length), 0);
|
|
73
|
+
}
|
|
74
|
+
function sisuMarkHeight(columns = 80) {
|
|
75
|
+
return sisuMarkLines(columns).length;
|
|
76
|
+
}
|
package/dist/pager/render.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.stripAnsi = void 0;
|
|
4
4
|
exports.renderPager = renderPager;
|
|
5
|
+
const logo_1 = require("../logo");
|
|
5
6
|
const model_1 = require("./model");
|
|
6
7
|
const theme_1 = require("./theme");
|
|
7
8
|
Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return theme_1.stripAnsi; } });
|
|
@@ -100,27 +101,22 @@ function windowAroundSelected(lines, entryOf, selected, budget, lastEntry) {
|
|
|
100
101
|
function isIdleWelcome(state) {
|
|
101
102
|
return !state.conversationId && state.entries.length === 0;
|
|
102
103
|
}
|
|
103
|
-
function center(text, width) {
|
|
104
|
-
const padLeft = Math.max(0, Math.floor((width -
|
|
104
|
+
function center(text, width, vis = (0, logo_1.displayWidth)(text)) {
|
|
105
|
+
const padLeft = Math.max(0, Math.floor((width - vis) / 2));
|
|
105
106
|
return `${' '.repeat(padLeft)}${text}`;
|
|
106
107
|
}
|
|
107
|
-
function welcomeLines(guest, width,
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return [
|
|
120
|
-
title,
|
|
121
|
-
'',
|
|
122
|
-
theme.dim(center('Ask anything, or type /help.', width)),
|
|
123
|
-
];
|
|
108
|
+
function welcomeLines(guest, width, height, _theme) {
|
|
109
|
+
const copy = (0, logo_1.sisuWelcomeCopy)(guest, true).map((line) => center(line, width));
|
|
110
|
+
const treeCols = height >= 18 && width >= 48 ? Math.min(width, 72) : width >= 36 ? 44 : 28;
|
|
111
|
+
const raw = (0, logo_1.sisuTreeLines)(treeCols);
|
|
112
|
+
const painted = (0, logo_1.sisuTreeArt)(treeCols, true).split('\n');
|
|
113
|
+
const treeWidth = raw.reduce((max, line) => Math.max(max, line.length), 0);
|
|
114
|
+
const treePad = Math.max(0, Math.floor((width - treeWidth) / 2));
|
|
115
|
+
const tree = painted.map((line, i) => {
|
|
116
|
+
const vis = raw[i]?.length ?? (0, logo_1.displayWidth)(line);
|
|
117
|
+
return `${' '.repeat(treePad)}${line}${' '.repeat(Math.max(0, treeWidth - vis))}`;
|
|
118
|
+
});
|
|
119
|
+
return [...copy, '', ...tree];
|
|
124
120
|
}
|
|
125
121
|
function slashMenuLines(state, theme) {
|
|
126
122
|
if (!state.slashOpen)
|
|
@@ -150,7 +146,7 @@ function renderPager(state, cols, rows, themeName = 'dark') {
|
|
|
150
146
|
const slash = slashMenuLines(state, theme);
|
|
151
147
|
const slashTake = Math.min(slash.length, bodyBudget);
|
|
152
148
|
const guest = !(state.statusLine || '').trim() || (state.statusLine || '').includes('not signed in');
|
|
153
|
-
const welcome = isIdleWelcome(state) ? welcomeLines(guest, width, theme) : [];
|
|
149
|
+
const welcome = isIdleWelcome(state) ? welcomeLines(guest, width, height, theme) : [];
|
|
154
150
|
const welcomeTake = Math.min(welcome.length, Math.max(0, bodyBudget - slashTake));
|
|
155
151
|
const scrollBudget = bodyBudget - slashTake - welcomeTake;
|
|
156
152
|
const laid = layoutScrollback(state, width, theme);
|
package/dist/tree.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** 溯源之树 — hand-inked ASCII of the login welcome painting. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.sisuTreeLines = sisuTreeLines;
|
|
5
|
+
exports.sisuTreeArt = sisuTreeArt;
|
|
6
|
+
exports.sisuTreeWidth = sisuTreeWidth;
|
|
7
|
+
exports.sisuTreeHeight = sisuTreeHeight;
|
|
8
|
+
const RESET = '\x1b[0m';
|
|
9
|
+
const INK = [196, 186, 170];
|
|
10
|
+
const INK_DIM = [130, 120, 108];
|
|
11
|
+
const FRUIT = [184, 90, 58];
|
|
12
|
+
const HILL = [90, 82, 70];
|
|
13
|
+
/**
|
|
14
|
+
* Desktop login tree. Trunk sits near center; crown opens into an airy
|
|
15
|
+
* fan with terracotta tips — the same 图景 as BrandCanvas, not a Möbius.
|
|
16
|
+
*/
|
|
17
|
+
const TREE_WIDE = [
|
|
18
|
+
' • • • • • • •',
|
|
19
|
+
' • • • • • • • • • •',
|
|
20
|
+
' • • • • • • • • • • • •',
|
|
21
|
+
' • • ╲ • ╲ • ╱ • ╲ • • •',
|
|
22
|
+
' • ╲ ╱ ╲ ╲ ╱ ╲ ╱ ╲ ╲ ╲ ╱',
|
|
23
|
+
' • ╲ ╱ ╲ ╲ ╱ ╲ ╱ ╲ ╲ ╲╱',
|
|
24
|
+
' ╲ ╲╱ ╲ ╲╱ ╲ ╱ ╲ ╲ ╱',
|
|
25
|
+
' ╲ ╱ ╲ ╱ Y ╲ ╲ ╱',
|
|
26
|
+
' ╲ ╱ ╲ ╱ ╱ ╲ ╲╱',
|
|
27
|
+
' ╲ ╱ Y ╱ ╲ ╱',
|
|
28
|
+
' ╲ ╱ ╱ ╲ ╱ ╲╱',
|
|
29
|
+
' Y ╱ ╲ ╱ ╱',
|
|
30
|
+
' │ ╱ ╲ ╱',
|
|
31
|
+
' │ ╱ Y',
|
|
32
|
+
' │ ╱',
|
|
33
|
+
' │',
|
|
34
|
+
'▁▁▁▂▂▁▁▁▁▁▁▁▁▁│▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁',
|
|
35
|
+
];
|
|
36
|
+
const TREE_MID = [
|
|
37
|
+
' • • • • • • •',
|
|
38
|
+
' • • • • • • • • •',
|
|
39
|
+
' • • ╲ • ╲ • ╱ • ╲ • •',
|
|
40
|
+
' • ╲ ╱ ╲ ╲ ╱ ╲ ╱ ╲ ╲ ╱',
|
|
41
|
+
' ╲ ╲ ╱ ╲ ╲ ╱ ╲ ╱ ╲ Y',
|
|
42
|
+
' ╲ Y ╲ Y ╲╱ ╲ ╱',
|
|
43
|
+
' ╲ ╱ ╲ ╱ ╱ Y',
|
|
44
|
+
' ╲╱ Y ╱ ╱',
|
|
45
|
+
' │ ╱ ╲ ╱',
|
|
46
|
+
' │ ╱ ╲ ╱',
|
|
47
|
+
' │ ╱ ╲╱',
|
|
48
|
+
' │',
|
|
49
|
+
'▁▁▂▂▁▁▁▁▁▁▁│▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁',
|
|
50
|
+
];
|
|
51
|
+
const TREE_NARROW = [
|
|
52
|
+
' • • • • •',
|
|
53
|
+
' • ╲ • ╱ • ╲ •',
|
|
54
|
+
' ╲ ╱ ╲ ╱ ╲ ╱ ╲╱',
|
|
55
|
+
' ╲ ╱ Y ╲╱ ╱',
|
|
56
|
+
' Y ╱ ╲ ╱',
|
|
57
|
+
' │ ╱ ╲╱',
|
|
58
|
+
' │',
|
|
59
|
+
'▁▁▁▁▁▁▁▁│▁▁▁▁▁▁▁▁▁▁▁▁▁▁',
|
|
60
|
+
];
|
|
61
|
+
function lerp(a, b, t) {
|
|
62
|
+
return a + (b - a) * t;
|
|
63
|
+
}
|
|
64
|
+
function paintRgb(ch, rgb) {
|
|
65
|
+
return `\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m${ch}`;
|
|
66
|
+
}
|
|
67
|
+
function inkAt(x, width) {
|
|
68
|
+
const t = width <= 1 ? 0 : x / (width - 1);
|
|
69
|
+
return [
|
|
70
|
+
Math.round(lerp(INK[0], INK_DIM[0], t * 0.45)),
|
|
71
|
+
Math.round(lerp(INK[1], INK_DIM[1], t * 0.45)),
|
|
72
|
+
Math.round(lerp(INK[2], INK_DIM[2], t * 0.45)),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
function paintLine(line, color) {
|
|
76
|
+
if (!color)
|
|
77
|
+
return line;
|
|
78
|
+
let out = '';
|
|
79
|
+
for (let i = 0; i < line.length; i += 1) {
|
|
80
|
+
const ch = line[i];
|
|
81
|
+
if (ch === ' ') {
|
|
82
|
+
out += ' ';
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (ch === '•') {
|
|
86
|
+
out += paintRgb(ch, FRUIT);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (ch === '▁' || ch === '▂') {
|
|
90
|
+
out += paintRgb(ch, HILL);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
out += paintRgb(ch, inkAt(i, line.length));
|
|
94
|
+
}
|
|
95
|
+
return `${out}${RESET}`;
|
|
96
|
+
}
|
|
97
|
+
function padBlock(lines) {
|
|
98
|
+
const width = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
99
|
+
return lines.map((line) => line.padEnd(width, ' '));
|
|
100
|
+
}
|
|
101
|
+
function sisuTreeLines(columns = 80) {
|
|
102
|
+
if (columns >= 68)
|
|
103
|
+
return padBlock(TREE_WIDE);
|
|
104
|
+
if (columns >= 44)
|
|
105
|
+
return padBlock(TREE_MID);
|
|
106
|
+
return padBlock(TREE_NARROW);
|
|
107
|
+
}
|
|
108
|
+
function sisuTreeArt(columns = 80, color = true) {
|
|
109
|
+
return sisuTreeLines(columns).map((line) => paintLine(line, color)).join('\n');
|
|
110
|
+
}
|
|
111
|
+
function sisuTreeWidth(columns = 80) {
|
|
112
|
+
return sisuTreeLines(columns).reduce((max, line) => Math.max(max, line.length), 0);
|
|
113
|
+
}
|
|
114
|
+
function sisuTreeHeight(columns = 80) {
|
|
115
|
+
return sisuTreeLines(columns).length;
|
|
116
|
+
}
|
package/dist/tui.js
CHANGED
|
@@ -174,7 +174,7 @@ async function runTui(io, deps = {}) {
|
|
|
174
174
|
const columns = deps.columns ?? process.stdout.columns ?? 80;
|
|
175
175
|
const animate = deps.animate ?? shouldAnimateSplash();
|
|
176
176
|
try {
|
|
177
|
-
io.write(
|
|
177
|
+
io.write(`${(0, logo_1.sisuSplash)(columns, true)}\n`);
|
|
178
178
|
if (animate) {
|
|
179
179
|
await (deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))))(80);
|
|
180
180
|
}
|