codymaster 4.1.2 → 4.1.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/ui/box.js ADDED
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /**
3
+ * 📦 Box Drawing — Terminal UI components
4
+ * Bordered panels, tables, progress bars, badges
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.termWidth = termWidth;
11
+ exports.renderBox = renderBox;
12
+ exports.renderDivider = renderDivider;
13
+ exports.renderTable = renderTable;
14
+ exports.renderProgressBar = renderProgressBar;
15
+ exports.renderBadge = renderBadge;
16
+ exports.renderPriority = renderPriority;
17
+ exports.renderSpeechBubble = renderSpeechBubble;
18
+ exports.renderStepProgress = renderStepProgress;
19
+ exports.renderFooter = renderFooter;
20
+ exports.renderCommandHeader = renderCommandHeader;
21
+ exports.renderKeyValue = renderKeyValue;
22
+ exports.renderResult = renderResult;
23
+ exports.stripAnsi = stripAnsi;
24
+ const chalk_1 = __importDefault(require("chalk"));
25
+ const theme_1 = require("./theme");
26
+ // ─── Terminal Width ────────────────────────────────────────────────────────
27
+ function termWidth() {
28
+ return process.stdout.columns || 80;
29
+ }
30
+ function clamp(val, min, max) {
31
+ return Math.max(min, Math.min(max, val));
32
+ }
33
+ // ─── Box Components ────────────────────────────────────────────────────────
34
+ const BOX = {
35
+ tl: '╭', tr: '╮', bl: '╰', br: '╯',
36
+ h: '─', v: '│',
37
+ // Table
38
+ ttl: '┌', ttr: '┐', tbl: '└', tbr: '┘',
39
+ th: '─', tv: '│', tc: '┼',
40
+ tlt: '├', trt: '┤', ttt: '┬', tbt: '┴',
41
+ };
42
+ /**
43
+ * Render a bordered box with optional title
44
+ */
45
+ function renderBox(content, opts) {
46
+ var _a, _b;
47
+ const pad = (_a = opts === null || opts === void 0 ? void 0 : opts.padding) !== null && _a !== void 0 ? _a : 1;
48
+ const w = (_b = opts === null || opts === void 0 ? void 0 : opts.width) !== null && _b !== void 0 ? _b : clamp(termWidth() - 4, 40, 80);
49
+ const innerW = w - 2 - (pad * 2);
50
+ const lines = [];
51
+ const padStr = ' '.repeat(pad);
52
+ // Top border with optional title
53
+ if (opts === null || opts === void 0 ? void 0 : opts.title) {
54
+ const title = ` ${opts.title} `;
55
+ const leftLen = 2;
56
+ const rightLen = Math.max(0, w - 2 - leftLen - stripAnsi(title).length);
57
+ lines.push((0, theme_1.dim)(`${BOX.tl}${BOX.h.repeat(leftLen)}`) + (0, theme_1.brand)(title) + (0, theme_1.dim)(`${BOX.h.repeat(rightLen)}${BOX.tr}`));
58
+ }
59
+ else {
60
+ lines.push((0, theme_1.dim)(`${BOX.tl}${BOX.h.repeat(w - 2)}${BOX.tr}`));
61
+ }
62
+ // Content lines
63
+ for (const line of content) {
64
+ const visible = stripAnsi(line);
65
+ const spaces = Math.max(0, innerW - visible.length);
66
+ lines.push((0, theme_1.dim)(BOX.v) + padStr + line + ' '.repeat(spaces) + padStr + (0, theme_1.dim)(BOX.v));
67
+ }
68
+ // Bottom border
69
+ lines.push((0, theme_1.dim)(`${BOX.bl}${BOX.h.repeat(w - 2)}${BOX.br}`));
70
+ return lines.join('\n');
71
+ }
72
+ /**
73
+ * Render a simple divider line
74
+ */
75
+ function renderDivider(width) {
76
+ const w = width !== null && width !== void 0 ? width : clamp(termWidth() - 4, 40, 80);
77
+ return (0, theme_1.dim)(BOX.h.repeat(w));
78
+ }
79
+ /**
80
+ * Render a clean bordered table
81
+ */
82
+ function renderTable(columns, rows) {
83
+ const lines = [];
84
+ const totalW = columns.reduce((sum, c) => sum + c.width, 0) + columns.length + 1;
85
+ // Header separator
86
+ const headerSep = (0, theme_1.dim)(columns.map(c => BOX.th.repeat(c.width)).join((0, theme_1.dim)('─┬─')));
87
+ lines.push(` ${headerSep}`);
88
+ // Header row
89
+ const headerCells = columns.map(c => {
90
+ const text = padCell(c.header, c.width, c.align);
91
+ return (0, theme_1.dim)(text);
92
+ });
93
+ lines.push(` ${headerCells.join((0, theme_1.dim)(' │ '))}`);
94
+ // Header underline
95
+ lines.push(` ${headerSep}`);
96
+ // Data rows
97
+ for (const row of rows) {
98
+ const cells = columns.map(c => {
99
+ const val = row[c.header] || '—';
100
+ const display = padCell(stripAnsi(val).length > c.width ? stripAnsi(val).substring(0, c.width - 1) + '…' : val, c.width, c.align);
101
+ return c.color ? c.color(display) : display;
102
+ });
103
+ lines.push(` ${cells.join((0, theme_1.dim)(' │ '))}`);
104
+ }
105
+ // Bottom separator
106
+ lines.push(` ${headerSep}`);
107
+ return lines.join('\n');
108
+ }
109
+ function padCell(str, width, align) {
110
+ const visible = stripAnsi(str);
111
+ const diff = Math.max(0, width - visible.length);
112
+ if (align === 'right')
113
+ return ' '.repeat(diff) + str;
114
+ if (align === 'center') {
115
+ const left = Math.floor(diff / 2);
116
+ return ' '.repeat(left) + str + ' '.repeat(diff - left);
117
+ }
118
+ return str + ' '.repeat(diff);
119
+ }
120
+ // ─── Progress Bar ──────────────────────────────────────────────────────────
121
+ /**
122
+ * Render a colored progress bar
123
+ */
124
+ function renderProgressBar(pct, width) {
125
+ const w = width !== null && width !== void 0 ? width : 16;
126
+ const filled = Math.round((clamp(pct, 0, 100) / 100) * w);
127
+ const empty = w - filled;
128
+ const color = pct >= 100 ? theme_1.success : pct >= 60 ? chalk_1.default.hex(theme_1.COLORS.success) : pct >= 30 ? theme_1.warning : theme_1.error;
129
+ return color('█'.repeat(filled)) + (0, theme_1.muted)('░'.repeat(empty)) + (0, theme_1.dim)(` ${pct}%`);
130
+ }
131
+ // ─── Status Badge ──────────────────────────────────────────────────────────
132
+ const BADGE_COLORS = {
133
+ 'backlog': chalk_1.default.hex(theme_1.COLORS.backlog),
134
+ 'in-progress': chalk_1.default.hex(theme_1.COLORS.inProgress),
135
+ 'review': chalk_1.default.hex(theme_1.COLORS.warning),
136
+ 'done': chalk_1.default.hex(theme_1.COLORS.done),
137
+ 'success': chalk_1.default.hex(theme_1.COLORS.success),
138
+ 'failed': chalk_1.default.hex(theme_1.COLORS.error),
139
+ 'pending': chalk_1.default.hex(theme_1.COLORS.warning),
140
+ 'running': chalk_1.default.hex(theme_1.COLORS.inProgress),
141
+ };
142
+ /**
143
+ * Render a colored status badge: ● status
144
+ */
145
+ function renderBadge(status) {
146
+ const color = BADGE_COLORS[status] || theme_1.dim;
147
+ return color(`${theme_1.ICONS.dot} ${status}`);
148
+ }
149
+ /**
150
+ * Render priority badge
151
+ */
152
+ function renderPriority(priority) {
153
+ const color = theme_1.PRI[priority] || theme_1.dim;
154
+ return color(`${theme_1.ICONS.dot} ${priority}`);
155
+ }
156
+ // ─── Speech Bubble ─────────────────────────────────────────────────────────
157
+ /**
158
+ * Render a hamster speech bubble
159
+ */
160
+ function renderSpeechBubble(message) {
161
+ const w = stripAnsi(message).length + 4;
162
+ return [
163
+ (0, theme_1.dim)(` ╭${'─'.repeat(w)}╮`),
164
+ (0, theme_1.dim)(` │`) + ` ${message} ` + (0, theme_1.dim)(`│`),
165
+ (0, theme_1.dim)(` ╰${'─'.repeat(w)}╯`),
166
+ (0, theme_1.dim)(` ╰─`),
167
+ ].join('\n');
168
+ }
169
+ // ─── Step Indicator ────────────────────────────────────────────────────────
170
+ /**
171
+ * Render onboarding step progress: Step 2 of 5 ●●○○○
172
+ */
173
+ function renderStepProgress(current, total) {
174
+ const dots = Array.from({ length: total }, (_, i) => i < current ? (0, theme_1.brand)(theme_1.ICONS.dot) : (0, theme_1.muted)(theme_1.ICONS.dotEmpty)).join(' ');
175
+ return ` ${(0, theme_1.dim)('Step')} ${(0, theme_1.brand)(String(current))} ${(0, theme_1.dim)('of')} ${(0, theme_1.dim)(String(total))} ${dots}`;
176
+ }
177
+ // ─── Footer ────────────────────────────────────────────────────────────────
178
+ /**
179
+ * Render a footer hint bar
180
+ */
181
+ function renderFooter(hints) {
182
+ return ` ${hints.map(h => (0, theme_1.dim)(h)).join((0, theme_1.dim)(' • '))}`;
183
+ }
184
+ // ─── Command Header ────────────────────────────────────────────────────────
185
+ /**
186
+ * Render a branded command header: ⚙️ Configuration
187
+ */
188
+ function renderCommandHeader(title, icon) {
189
+ const iconStr = icon ? `${icon} ` : '';
190
+ return `\n ${iconStr}${(0, theme_1.brand)(title)}\n`;
191
+ }
192
+ // ─── Key-Value Display ─────────────────────────────────────────────────────
193
+ /**
194
+ * Render aligned key-value pairs with branded styling
195
+ * Input: [['Version', '4.1.3'], ['Port', '4321']]
196
+ * Output:
197
+ * Version 4.1.3
198
+ * Port 4321
199
+ */
200
+ function renderKeyValue(pairs, opts) {
201
+ var _a, _b;
202
+ const indent = ' '.repeat((_a = opts === null || opts === void 0 ? void 0 : opts.indent) !== null && _a !== void 0 ? _a : 2);
203
+ const maxKey = (_b = opts === null || opts === void 0 ? void 0 : opts.keyWidth) !== null && _b !== void 0 ? _b : Math.max(...pairs.map(([k]) => k.length)) + 1;
204
+ return pairs.map(([key, value]) => {
205
+ const paddedKey = (key + ':').padEnd(maxKey + 1);
206
+ return `${indent}${(0, theme_1.dim)(paddedKey)} ${value}`;
207
+ }).join('\n');
208
+ }
209
+ // ─── Result Messages ───────────────────────────────────────────────────────
210
+ const RESULT_CONFIG = {
211
+ success: { icon: '✅', color: theme_1.success },
212
+ error: { icon: '❌', color: theme_1.error },
213
+ warning: { icon: '⚠️', color: theme_1.warning },
214
+ info: { icon: 'ℹ️', color: (s) => s },
215
+ };
216
+ /**
217
+ * Render standardized result message with optional detail lines
218
+ */
219
+ function renderResult(type, message, details) {
220
+ const cfg = RESULT_CONFIG[type];
221
+ const lines = [`\n ${cfg.icon} ${cfg.color(message)}`];
222
+ if (details) {
223
+ for (const d of details) {
224
+ lines.push(` ${d}`);
225
+ }
226
+ }
227
+ lines.push('');
228
+ return lines.join('\n');
229
+ }
230
+ // ─── Utilities ─────────────────────────────────────────────────────────────
231
+ /**
232
+ * Strip ANSI escape codes for width calculations
233
+ */
234
+ function stripAnsi(str) {
235
+ // eslint-disable-next-line no-control-regex
236
+ return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '').replace(/\x1B\]8;[^;]*;[^\x1B]*\x1B\\/g, '');
237
+ }
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ /**
3
+ * 🐹 Hamster Mascot — ASCII art + personality system
4
+ * The face of CodyMaster CLI
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getHamsterArt = getHamsterArt;
8
+ exports.getGreeting = getGreeting;
9
+ exports.getCelebration = getCelebration;
10
+ exports.getEncouragement = getEncouragement;
11
+ exports.getErrorGuidance = getErrorGuidance;
12
+ exports.renderHamsterBanner = renderHamsterBanner;
13
+ exports.renderHamsterMessage = renderHamsterMessage;
14
+ const theme_1 = require("./theme");
15
+ // ─── ASCII Art States ──────────────────────────────────────────────────────
16
+ const HAMSTER_ART = {
17
+ happy: [
18
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')}`,
19
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.brandBold)('^ ^')} ${(0, theme_1.brand)('\\')}`,
20
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.brandBold)('u')} ${(0, theme_1.brand)(')')}`,
21
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
22
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
23
+ ],
24
+ angry: [
25
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')}`,
26
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.warning)('> <')} ${(0, theme_1.brand)('\\')}`,
27
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.warning)('x')} ${(0, theme_1.brand)(')')}`,
28
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
29
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
30
+ ],
31
+ sad: [
32
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')}`,
33
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.dim)('u u')} ${(0, theme_1.brand)('\\')}`,
34
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.dim)('n')} ${(0, theme_1.brand)(')')}`,
35
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
36
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
37
+ ],
38
+ surprised: [
39
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')}`,
40
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.info)('O O')} ${(0, theme_1.brand)('\\')}`,
41
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.info)('o')} ${(0, theme_1.brand)(')')}`,
42
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
43
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
44
+ ],
45
+ in_love: [
46
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')} ${(0, theme_1.success)('♥')}`,
47
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.success)('* *')} ${(0, theme_1.brand)('\\')}`,
48
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.success)('v')} ${(0, theme_1.brand)(')')}`,
49
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
50
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
51
+ ],
52
+ sleeping: [
53
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')} ${(0, theme_1.dim)('zZ')}`,
54
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.dim)('- -')} ${(0, theme_1.brand)('\\')} ${(0, theme_1.dim)('zZ')}`,
55
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.dim)('u')} ${(0, theme_1.brand)(')')}`,
56
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
57
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
58
+ ],
59
+ thinking: [
60
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')} ${(0, theme_1.dim)('.oO')}`,
61
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.dim)('. .')} ${(0, theme_1.brand)('\\')} ${(0, theme_1.dim)('/')}`,
62
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.dim)('u')} ${(0, theme_1.brand)(')')}`,
63
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
64
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
65
+ ],
66
+ cool: [
67
+ ` ${(0, theme_1.brand)('( . \\ --- / . )')}`,
68
+ ` ${(0, theme_1.brand)('/')} ${(0, theme_1.info)('B B')} ${(0, theme_1.brand)('\\')}`,
69
+ ` ${(0, theme_1.brand)('(')} ${(0, theme_1.info)('v')} ${(0, theme_1.brand)(')')}`,
70
+ ` ${(0, theme_1.brand)('| \\ ___ / |')}`,
71
+ ` ${(0, theme_1.brand)('\'--w---w--\'')}`,
72
+ ],
73
+ celebrating: [
74
+ ` ${(0, theme_1.success)('\\')} ${(0, theme_1.brand)('( \\_/ )')} ${(0, theme_1.success)('/')}`,
75
+ ` ${(0, theme_1.success)('\\')} ${(0, theme_1.brand)('(')} ${(0, theme_1.success)('^ u ^')} ${(0, theme_1.brand)(')')} ${(0, theme_1.success)('/')}`,
76
+ ` ${(0, theme_1.success)('--')} ${(0, theme_1.brand)('( ___ )')} ${(0, theme_1.success)('--')}`,
77
+ ` ${(0, theme_1.brand)('| [ ] |')}`,
78
+ ` ${(0, theme_1.brand)('\'--w-w--\'')}`,
79
+ ],
80
+ };
81
+ // Aliases for compatibility with existing code
82
+ Object.assign(HAMSTER_ART, {
83
+ greeting: HAMSTER_ART.happy,
84
+ working: HAMSTER_ART.thinking,
85
+ error: HAMSTER_ART.angry,
86
+ });
87
+ /**
88
+ * Get hamster ASCII art for a given state
89
+ */
90
+ function getHamsterArt(state = 'greeting') {
91
+ return HAMSTER_ART[state].join('\n');
92
+ }
93
+ // ─── Time-Based Greetings ──────────────────────────────────────────────────
94
+ function getTimeOfDay() {
95
+ const h = new Date().getHours();
96
+ if (h >= 5 && h < 12)
97
+ return 'morning';
98
+ if (h >= 12 && h < 17)
99
+ return 'afternoon';
100
+ if (h >= 17 && h < 21)
101
+ return 'evening';
102
+ return 'night';
103
+ }
104
+ const TIME_GREETINGS = {
105
+ morning: [
106
+ 'Good morning! ☀️ Ready to build?',
107
+ 'Rise and code! ☀️',
108
+ 'Morning! Let\'s ship something today ☀️',
109
+ ],
110
+ afternoon: [
111
+ 'Good afternoon! 🌤️ What are we building?',
112
+ 'Afternoon! Time to make progress 🏗️',
113
+ 'Hey there! Productive day so far? 🌤️',
114
+ ],
115
+ evening: [
116
+ 'Good evening! 🌅 Wrapping up?',
117
+ 'Evening session! 🌙 Let\'s finish strong',
118
+ 'Hey! Late push tonight? 🌅',
119
+ ],
120
+ night: [
121
+ 'Working late? 🌙 Don\'t forget to rest!',
122
+ 'Night owl mode! 🦉 I\'m here for you',
123
+ 'Midnight coding session? 🌙 Let\'s go!',
124
+ ],
125
+ };
126
+ /**
127
+ * Get a greeting based on time of day + optional user name
128
+ */
129
+ function getGreeting(userName) {
130
+ const tod = getTimeOfDay();
131
+ const greetings = TIME_GREETINGS[tod];
132
+ const greeting = greetings[Math.floor(Math.random() * greetings.length)];
133
+ if (userName) {
134
+ return `${greeting.split('!')[0]}, ${userName}! ${greeting.includes('!') ? greeting.split('!').slice(1).join('!').trim() : ''}`.trim();
135
+ }
136
+ return greeting;
137
+ }
138
+ // ─── Hamster Messages ──────────────────────────────────────────────────────
139
+ const CELEBRATIONS = [
140
+ 'Nice work! 🎉',
141
+ 'You\'re on fire! 🔥',
142
+ 'Ship it! 🚀',
143
+ 'Another one bites the dust! ✅',
144
+ 'Level up! ⬆️',
145
+ 'Crushing it! 💪',
146
+ 'That\'s how it\'s done! ⭐',
147
+ 'Clean execution! 🎯',
148
+ 'Boom! Done! 💥',
149
+ 'Progress! Keep going! 📈',
150
+ 'Smooth operator! 🎵',
151
+ 'Task terminated! 🤖',
152
+ 'One step closer! 🏁',
153
+ 'Brilliant move! ♟️',
154
+ 'Unstoppable! ⚡',
155
+ ];
156
+ const ENCOURAGEMENTS = [
157
+ 'You got this! 💪',
158
+ 'Almost there! 🏁',
159
+ 'Keep pushing! Every step counts 🐾',
160
+ 'Rome wasn\'t built in a day, but they were laying bricks! 🧱',
161
+ 'Progress, not perfection! 📈',
162
+ 'One command at a time 🐹',
163
+ ];
164
+ const ERROR_GUIDANCE = [
165
+ 'Oops! Let me help you fix that 🔧',
166
+ 'Not quite! Here\'s what to try instead 💡',
167
+ 'Hmm, that didn\'t work. But we\'ll figure it out! 🐹',
168
+ 'Small detour! Let\'s get back on track 🛤️',
169
+ ];
170
+ const IDLE_MESSAGES = [
171
+ 'Any tasks to tackle? Type cm task list 📋',
172
+ 'Need a skill? Try cm list 🧩',
173
+ 'Been a while! What are we building? 🏗️',
174
+ ];
175
+ /**
176
+ * Get a random celebration message
177
+ */
178
+ function getCelebration() {
179
+ return CELEBRATIONS[Math.floor(Math.random() * CELEBRATIONS.length)];
180
+ }
181
+ /**
182
+ * Get a random encouragement
183
+ */
184
+ function getEncouragement() {
185
+ return ENCOURAGEMENTS[Math.floor(Math.random() * ENCOURAGEMENTS.length)];
186
+ }
187
+ /**
188
+ * Get error guidance
189
+ */
190
+ function getErrorGuidance() {
191
+ return ERROR_GUIDANCE[Math.floor(Math.random() * ERROR_GUIDANCE.length)];
192
+ }
193
+ /**
194
+ * Render the full hamster banner with greeting
195
+ */
196
+ function renderHamsterBanner(userName, version, cwd) {
197
+ const art = getHamsterArt(getTimeOfDay() === 'night' ? 'sleeping' : 'greeting');
198
+ const greeting = getGreeting(userName);
199
+ const lines = [
200
+ '',
201
+ art,
202
+ '',
203
+ ` ${(0, theme_1.brandBold)(greeting)}`,
204
+ '',
205
+ ` ${(0, theme_1.dim)('CodyMaster')} ${(0, theme_1.brand)(`v${version || '?'}`)} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)('34 Skills')} ${(0, theme_1.dim)('•')} ${(0, theme_1.dim)(cwd || '~')}`,
206
+ (0, theme_1.dim)(' ' + '─'.repeat(50)),
207
+ ];
208
+ return lines.join('\n');
209
+ }
210
+ /**
211
+ * Render a compact hamster message (for inline use)
212
+ */
213
+ function renderHamsterMessage(message, state = 'greeting') {
214
+ const art = HAMSTER_ART[state];
215
+ const artWidth = 14;
216
+ // Combine art with message on the same line
217
+ return [
218
+ art[0],
219
+ art[1],
220
+ `${art[2]} ${(0, theme_1.text)(message)}`,
221
+ art[3],
222
+ ].join('\n');
223
+ }