@stevezhou/sisu 0.1.4 → 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 CHANGED
@@ -1,16 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sisuMarkLines = exports.sisuMarkArt = void 0;
3
+ exports.sisuTreeLines = exports.sisuTreeArt = exports.sisuMarkLines = exports.sisuMarkArt = void 0;
4
4
  exports.sisuMobiusArt = sisuMobiusArt;
5
5
  exports.sisuWordmark = sisuWordmark;
6
+ exports.displayWidth = displayWidth;
6
7
  exports.sisuSplash = sisuSplash;
8
+ exports.sisuWelcomeCopy = sisuWelcomeCopy;
7
9
  exports.sisuBanner = sisuBanner;
8
10
  exports.stripAnsi = stripAnsi;
9
11
  var mark_1 = require("./mark");
10
12
  Object.defineProperty(exports, "sisuMarkArt", { enumerable: true, get: function () { return mark_1.sisuMarkArt; } });
11
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; } });
12
17
  const mark_2 = require("./mark");
13
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 = ['一', '二', '三'];
14
32
  function sisuMobiusArt(columns = 80, phase = 0, color = false) {
15
33
  return (0, mobius_1.renderMobiusFrame)({
16
34
  cols: (0, mobius_1.mobiusFrameWidth)(columns),
@@ -22,13 +40,130 @@ function sisuMobiusArt(columns = 80, phase = 0, color = false) {
22
40
  function sisuWordmark() {
23
41
  return ['思溯', 'SISU'].join('\n');
24
42
  }
25
- /** Splash used on TUI enter: the web Möbius mark plus 思溯. */
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)),
102
+ '',
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
+ */
26
132
  function sisuSplash(columns = 80, color = true) {
27
- const mark = (0, mark_2.sisuMarkArt)(columns, color);
28
- const markWidth = (0, mark_2.sisuMarkLines)(columns)[0]?.length ?? 0;
29
- const caption = '思溯 SISU';
30
- const pad = Math.max(0, Math.floor((markWidth - caption.length) / 2));
31
- return ['', mark, '', `${' '.repeat(pad)}${caption}`, ''].join('\n');
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;
32
167
  }
33
168
  function sisuBanner(columns = 80, _phase = 0, color = false) {
34
169
  return sisuSplash(columns, color);
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 (Möbius splash)
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.
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.stripAnsi = void 0;
4
4
  exports.renderPager = renderPager;
5
- const mark_1 = require("../mark");
5
+ const logo_1 = require("../logo");
6
6
  const model_1 = require("./model");
7
7
  const theme_1 = require("./theme");
8
8
  Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return theme_1.stripAnsi; } });
@@ -101,28 +101,22 @@ function windowAroundSelected(lines, entryOf, selected, budget, lastEntry) {
101
101
  function isIdleWelcome(state) {
102
102
  return !state.conversationId && state.entries.length === 0;
103
103
  }
104
- function center(text, width, vis = (0, theme_1.stripAnsi)(text).length) {
104
+ function center(text, width, vis = (0, logo_1.displayWidth)(text)) {
105
105
  const padLeft = Math.max(0, Math.floor((width - vis) / 2));
106
106
  return `${' '.repeat(padLeft)}${text}`;
107
107
  }
108
- function welcomeLines(guest, width, height, theme) {
109
- const markCols = height >= 20 && width >= 48 ? width : 40;
110
- const raw = (0, mark_1.sisuMarkLines)(markCols);
111
- const painted = (0, mark_1.sisuMarkArt)(markCols, true).split('\n');
112
- const mark = painted.map((line, i) => center(line, width, raw[i]?.length ?? (0, theme_1.stripAnsi)(line).length));
113
- if (guest) {
114
- return [
115
- ...mark,
116
- '',
117
- theme.text(center('Sign in to start a conversation.', width)),
118
- theme.dim(center('/login browser /help commands', width)),
119
- ];
120
- }
121
- return [
122
- ...mark,
123
- '',
124
- theme.dim(center('Ask anything, or type /help.', width)),
125
- ];
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];
126
120
  }
127
121
  function slashMenuLines(state, theme) {
128
122
  if (!state.slashOpen)
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stevezhou/sisu",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "SiSu CLI — one login, cloud quota, local workspace",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://www.sisu.chat",