@semalt-ai/code 1.6.0 → 1.8.0

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/lib/ui.js CHANGED
@@ -1,603 +1,47 @@
1
1
  'use strict';
2
2
 
3
- const readline = require('readline');
4
-
5
- function getCols() {
6
- return process.stdout.columns || 80;
7
- }
8
-
9
- const RST = '\x1b[0m';
10
- const BOLD = '\x1b[1m';
11
- const DIM = '\x1b[2m';
12
-
13
- const FG_GRAY = '\x1b[38;5;245m';
14
- const FG_DARK = '\x1b[38;5;240m';
15
- const FG_BLUE = '\x1b[38;5;75m';
16
- const FG_CYAN = '\x1b[38;5;116m';
17
- const FG_GREEN = '\x1b[38;5;114m';
18
- const FG_YELLOW = '\x1b[38;5;222m';
19
- const FG_RED = '\x1b[38;5;203m';
20
- const FG_TEAL = '\x1b[38;5;73m';
21
-
22
- const BOX_H = '─';
23
- const BOX_V = '│';
24
- const BOX_TL = '╭';
25
- const BOX_TR = '╮';
26
- const BOX_BL = '╰';
27
- const BOX_BR = '╯';
28
-
29
- const FG_CODE_BG = '\x1b[48;5;236m';
30
- const FG_CODE_BORDER = '\x1b[38;5;240m';
31
- const FG_CODE_LANG = '\x1b[38;5;75m';
32
- const FG_INLINE_CODE = '\x1b[38;5;215m';
33
- const FG_HEADING = '\x1b[38;5;75m';
34
- const FG_BULLET = '\x1b[38;5;114m';
35
- const FG_BOLD_TEXT = '\x1b[38;5;255m';
36
- const FG_DIFF_ADD = '\x1b[38;5;114m';
37
- const FG_DIFF_DEL = '\x1b[38;5;203m';
38
- const FG_DIFF_HDR = '\x1b[38;5;75m';
39
- const FG_FILEPATH = '\x1b[38;5;222m';
40
- const FG_TAG = '\x1b[38;5;176m';
41
-
42
- const KEYWORDS = new Set([
43
- 'def', 'class', 'import', 'from', 'return', 'if', 'else', 'elif',
44
- 'for', 'while', 'try', 'except', 'finally', 'with', 'as', 'in',
45
- 'not', 'and', 'or', 'is', 'None', 'True', 'False', 'async', 'await',
46
- 'function', 'const', 'let', 'var', 'export', 'require', 'func',
47
- 'type', 'struct', 'interface', 'package', 'fn', 'pub', 'use',
48
- 'mod', 'impl', 'match', 'enum', 'self', 'print', 'len', 'range',
49
- 'yield', 'lambda', 'raise', 'pass', 'break', 'continue', 'del',
50
- 'global', 'nonlocal', 'assert',
51
- ]);
52
-
53
- function hr(char = '─', color = FG_DARK) {
54
- process.stdout.write(`${color}${char.repeat(getCols())}${RST}\n`);
55
- }
56
-
57
- function stripAnsi(str) {
58
- return str.replace(/\x1b\[[^m]*m/g, '');
59
- }
60
-
61
- function boxLine(text, width) {
62
- const w = width || (getCols() - 4);
63
- const visible = stripAnsi(text).length;
64
- const pad = Math.max(0, w - visible);
65
- return ` ${FG_DARK}${BOX_V}${RST} ${text}${' '.repeat(pad)}${FG_DARK}${BOX_V}${RST}`;
66
- }
67
-
68
- function insertCharAt(text, index, value) {
69
- const chars = Array.from(text || '');
70
- chars.splice(index, 0, value);
71
- return chars.join('');
72
- }
73
-
74
- function removeCharAt(text, index) {
75
- const chars = Array.from(text || '');
76
- chars.splice(index, 1);
77
- return chars.join('');
78
- }
79
-
80
- function isPrintableKey(str, key = {}) {
81
- if (!str || key.ctrl || key.meta) return false;
82
- if (key.name === 'return' || key.name === 'enter' || key.name === 'tab') return false;
83
- if (key.name && ['up', 'down', 'left', 'right', 'home', 'end', 'pageup', 'pagedown', 'escape', 'delete', 'backspace'].includes(key.name)) {
84
- return false;
85
- }
86
- return !/[\x00-\x1f\x7f]/.test(str);
87
- }
88
-
89
- function readInteractiveInput(promptText, options = {}) {
90
- const {
91
- allowed = null,
92
- immediate = false,
93
- trim = false,
94
- allowCursorNavigation = false,
95
- history = null,
96
- } = options;
97
-
98
- return new Promise((resolve) => {
99
- if (!process.stdin.isTTY) {
100
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
101
- rl.question(promptText, (answer) => {
102
- rl.close();
103
- resolve({ type: 'submit', value: trim ? (answer || '').trim() : (answer || '') });
104
- });
105
- return;
106
- }
107
-
108
- const wasRaw = typeof process.stdin.isRaw === 'boolean' ? process.stdin.isRaw : false;
109
- let buffer = '';
110
- let cursor = 0;
111
- let done = false;
112
- let historyIndex = Array.isArray(history) ? history.length : -1;
113
- let historyActive = false;
114
- let pasting = false;
115
- let lastLineCount = 1;
116
- let lastCursorRow = 0;
117
- let lastWasCR = false;
118
-
119
- process.stdin.setRawMode(true);
120
- process.stdin.resume();
121
- process.stdout.write('\x1b[?2004h'); // enable bracketed paste mode
122
-
123
- const promptWidth = stripAnsi(promptText).length;
124
-
125
- const render = () => {
126
- const lines = buffer.split('\n');
127
- const newLineCount = lines.length;
128
-
129
- if (lastLineCount > 1) {
130
- readline.moveCursor(process.stdout, 0, -(lastLineCount - 1));
131
- }
132
-
133
- readline.cursorTo(process.stdout, 0);
134
- readline.clearLine(process.stdout, 0);
135
- process.stdout.write(`${promptText}${lines[0]}`);
136
-
137
- for (let i = 1; i < newLineCount; i++) {
138
- process.stdout.write('\n');
139
- readline.cursorTo(process.stdout, 0);
140
- readline.clearLine(process.stdout, 0);
141
- process.stdout.write(lines[i]);
142
- }
143
-
144
- // Clear any extra lines from a previous longer render
145
- for (let i = newLineCount; i < lastLineCount; i++) {
146
- process.stdout.write('\n');
147
- readline.cursorTo(process.stdout, 0);
148
- readline.clearLine(process.stdout, 0);
149
- }
150
-
151
- lastLineCount = newLineCount;
152
-
153
- const beforeCursor = Array.from(buffer).slice(0, cursor).join('');
154
- const cursorLines = beforeCursor.split('\n');
155
- lastCursorRow = cursorLines.length - 1;
156
- const cursorCol = (lastCursorRow === 0 ? promptWidth : 0) + cursorLines[lastCursorRow].length;
157
-
158
- const rowsFromBottom = newLineCount - 1 - lastCursorRow;
159
- if (rowsFromBottom > 0) {
160
- readline.moveCursor(process.stdout, 0, -rowsFromBottom);
161
- }
162
- readline.cursorTo(process.stdout, cursorCol);
163
- };
164
-
165
- const finish = (result, addNewline = true) => {
166
- if (done) return;
167
- done = true;
168
- process.stdout.write('\x1b[?2004l'); // disable bracketed paste mode
169
- process.stdin.setRawMode(wasRaw);
170
- process.stdin.removeListener('data', onData);
171
- if (addNewline) {
172
- const rowsToBottom = lastLineCount - 1 - lastCursorRow;
173
- if (rowsToBottom > 0) {
174
- readline.moveCursor(process.stdout, 0, rowsToBottom);
175
- }
176
- process.stdout.write('\n');
177
- }
178
- resolve(result);
179
- };
180
-
181
- // Parse raw stdin data directly so we can intercept bracketed paste markers
182
- // (\x1b[200~ ... \x1b[201~) before any higher-level key parser sees them.
183
- const onData = (chunk) => {
184
- if (done) return;
185
- const data = chunk.toString('utf8');
186
- let i = 0;
187
-
188
- while (i < data.length) {
189
- // --- Bracketed paste markers ---
190
- if (data.startsWith('\x1b[200~', i)) {
191
- pasting = true;
192
- lastWasCR = false;
193
- i += 6;
194
- continue;
195
- }
196
- if (data.startsWith('\x1b[201~', i)) {
197
- pasting = false;
198
- lastWasCR = false;
199
- i += 6;
200
- continue;
201
- }
202
-
203
- const ch = data[i];
204
-
205
- // --- Escape sequences ---
206
- if (ch === '\x1b') {
207
- lastWasCR = false;
208
- const next = data[i + 1];
209
-
210
- // CSI sequences: \x1b[...
211
- if (next === '[') {
212
- const seq3 = data.slice(i, i + 3);
213
- const seq4 = data.slice(i, i + 4);
214
-
215
- if (seq3 === '\x1b[A') { // up
216
- if (Array.isArray(history) && history.length) {
217
- if (historyActive || buffer.length === 0) {
218
- historyActive = true;
219
- historyIndex = Math.max(0, historyIndex - 1);
220
- buffer = historyIndex >= history.length ? '' : history[historyIndex];
221
- cursor = Array.from(buffer).length;
222
- render();
223
- }
224
- }
225
- i += 3; continue;
226
- }
227
- if (seq3 === '\x1b[B') { // down
228
- if (Array.isArray(history) && history.length) {
229
- if (historyActive || buffer.length === 0) {
230
- historyActive = true;
231
- historyIndex = Math.min(history.length, historyIndex + 1);
232
- buffer = historyIndex >= history.length ? '' : history[historyIndex];
233
- cursor = Array.from(buffer).length;
234
- render();
235
- }
236
- }
237
- i += 3; continue;
238
- }
239
- if (seq3 === '\x1b[C') { // right
240
- if (allowCursorNavigation && cursor < Array.from(buffer).length) { cursor++; render(); }
241
- i += 3; continue;
242
- }
243
- if (seq3 === '\x1b[D') { // left
244
- if (allowCursorNavigation && cursor > 0) { cursor--; render(); }
245
- i += 3; continue;
246
- }
247
- if (seq3 === '\x1b[H' || seq4 === '\x1b[1~') { // home
248
- if (allowCursorNavigation) { cursor = 0; render(); }
249
- i += (seq3 === '\x1b[H' ? 3 : 4); continue;
250
- }
251
- if (seq3 === '\x1b[F' || seq4 === '\x1b[4~') { // end
252
- if (allowCursorNavigation) { cursor = Array.from(buffer).length; render(); }
253
- i += (seq3 === '\x1b[F' ? 3 : 4); continue;
254
- }
255
- if (seq4 === '\x1b[3~') { // delete
256
- if (cursor < Array.from(buffer).length) {
257
- buffer = removeCharAt(buffer, cursor);
258
- historyActive = false;
259
- render();
260
- }
261
- i += 4; continue;
262
- }
263
- // Skip unknown CSI sequence (read until terminating byte)
264
- let j = i + 2;
265
- while (j < data.length && (data.charCodeAt(j) < 0x40 || data.charCodeAt(j) > 0x7e)) j++;
266
- i = j + 1;
267
- continue;
268
- }
269
-
270
- // SS3 sequences: \x1bO... (application cursor keys)
271
- if (next === 'O') {
272
- const c = data[i + 2];
273
- if (c === 'A') { // up
274
- if (Array.isArray(history) && history.length && (historyActive || buffer.length === 0)) {
275
- historyActive = true;
276
- historyIndex = Math.max(0, historyIndex - 1);
277
- buffer = historyIndex >= history.length ? '' : history[historyIndex];
278
- cursor = Array.from(buffer).length;
279
- render();
280
- }
281
- i += 3; continue;
282
- }
283
- if (c === 'B') { // down
284
- if (Array.isArray(history) && history.length && (historyActive || buffer.length === 0)) {
285
- historyActive = true;
286
- historyIndex = Math.min(history.length, historyIndex + 1);
287
- buffer = historyIndex >= history.length ? '' : history[historyIndex];
288
- cursor = Array.from(buffer).length;
289
- render();
290
- }
291
- i += 3; continue;
292
- }
293
- if (c === 'C' && allowCursorNavigation) { if (cursor < Array.from(buffer).length) { cursor++; render(); } i += 3; continue; }
294
- if (c === 'D' && allowCursorNavigation) { if (cursor > 0) { cursor--; render(); } i += 3; continue; }
295
- if (c === 'H' && allowCursorNavigation) { cursor = 0; render(); i += 3; continue; }
296
- if (c === 'F' && allowCursorNavigation) { cursor = Array.from(buffer).length; render(); i += 3; continue; }
297
- i += 3; continue;
298
- }
299
-
300
- // Unknown escape - skip
301
- i += 2;
302
- continue;
303
- }
304
-
305
- // --- Ctrl+C ---
306
- if (ch === '\x03') {
307
- lastWasCR = false;
308
- if (buffer) { buffer = ''; cursor = 0; pasting = false; render(); }
309
- else { finish({ type: 'sigint' }, false); return; }
310
- i++; continue;
311
- }
312
-
313
- // --- Ctrl+D ---
314
- if (ch === '\x04') {
315
- lastWasCR = false;
316
- if (!buffer) { finish({ type: 'eof' }, false); return; }
317
- i++; continue;
318
- }
319
-
320
- // --- Enter / newline ---
321
- if (ch === '\r' || ch === '\n') {
322
- // Collapse CRLF into a single newline
323
- if (ch === '\n' && lastWasCR) { lastWasCR = false; i++; continue; }
324
- lastWasCR = (ch === '\r');
325
-
326
- if (pasting) {
327
- buffer = insertCharAt(buffer, cursor, '\n');
328
- cursor++;
329
- historyActive = false;
330
- render();
331
- } else {
332
- finish({ type: 'submit', value: trim ? buffer.trim() : buffer });
333
- return;
334
- }
335
- i++; continue;
336
- }
337
- lastWasCR = false;
338
-
339
- // --- Backspace ---
340
- if (ch === '\x7f' || ch === '\x08') {
341
- if (cursor > 0) {
342
- buffer = removeCharAt(buffer, cursor - 1);
343
- cursor--;
344
- historyActive = false;
345
- render();
346
- }
347
- i++; continue;
348
- }
349
-
350
- // --- Tab ---
351
- if (ch === '\t') {
352
- if (pasting) {
353
- buffer = insertCharAt(buffer, cursor, '\t');
354
- cursor++;
355
- render();
356
- }
357
- i++; continue;
358
- }
359
-
360
- // --- Other control characters: skip ---
361
- if (ch.charCodeAt(0) < 0x20) { i++; continue; }
362
-
363
- // --- Printable character (handles multi-byte Unicode via code points) ---
364
- const cp = data.codePointAt(i);
365
- const char = String.fromCodePoint(cp);
366
-
367
- if (allowed && !allowed.includes(char)) { i += char.length; continue; }
368
-
369
- if (immediate) {
370
- buffer = char;
371
- cursor = 1;
372
- historyActive = false;
373
- render();
374
- finish({ type: 'submit', value: char });
375
- return;
376
- }
377
-
378
- buffer = insertCharAt(buffer, cursor, char);
379
- cursor++;
380
- historyActive = false;
381
- render();
382
- i += char.length;
383
- }
384
- };
385
-
386
- process.stdin.on('data', onData);
387
- render();
388
- });
389
- }
390
-
391
- class StreamRenderer {
392
- constructor() {
393
- this.buffer = '';
394
- this.inCodeBlock = false;
395
- this.codeLang = '';
396
- }
397
-
398
- feed(chunk) {
399
- this.buffer += chunk;
400
- while (this.buffer.includes('\n')) {
401
- const idx = this.buffer.indexOf('\n');
402
- const line = this.buffer.slice(0, idx);
403
- this.buffer = this.buffer.slice(idx + 1);
404
- this._renderLine(line);
405
- }
406
- }
407
-
408
- flush() {
409
- if (this.buffer) {
410
- this._renderLine(this.buffer);
411
- this.buffer = '';
412
- }
413
- if (this.inCodeBlock) {
414
- process.stdout.write(` ${FG_CODE_BORDER}╰${'─'.repeat(50)}${RST}\n`);
415
- this.inCodeBlock = false;
416
- }
417
- }
418
-
419
- _renderLine(line) {
420
- if (line.startsWith('```') && !this.inCodeBlock) {
421
- this.inCodeBlock = true;
422
- this.codeLang = line.slice(3).trim();
423
- const label = this.codeLang ? ` ${this.codeLang} ` : '';
424
- process.stdout.write(
425
- ` ${FG_CODE_BORDER}╭${'─'.repeat(20)}${RST}${FG_CODE_LANG}${label}${RST}` +
426
- `${FG_CODE_BORDER}${'─'.repeat(Math.max(1, 30 - label.length))}${RST}\n`
427
- );
428
- return;
429
- }
430
-
431
- if (line.trim() === '```' && this.inCodeBlock) {
432
- process.stdout.write(` ${FG_CODE_BORDER}╰${'─'.repeat(50)}${RST}\n`);
433
- this.inCodeBlock = false;
434
- return;
435
- }
436
-
437
- if (this.inCodeBlock) {
438
- process.stdout.write(` ${FG_CODE_BORDER}│${RST} ${FG_CODE_BG}${this._colorizeCode(line)}${RST}\n`);
439
- return;
440
- }
441
-
442
- if (/^\+(?!\+\+)/.test(line)) {
443
- process.stdout.write(` ${FG_DIFF_ADD}${line}${RST}\n`);
444
- return;
445
- }
446
- if (/^-(?!--)/.test(line)) {
447
- process.stdout.write(` ${FG_DIFF_DEL}${line}${RST}\n`);
448
- return;
449
- }
450
- if (line.startsWith('@@')) {
451
- process.stdout.write(` ${FG_DIFF_HDR}${line}${RST}\n`);
452
- return;
453
- }
454
- if (/^<(exec|shell|read_file|write_file)/.test(line)) {
455
- process.stdout.write(` ${FG_TAG}${line}${RST}\n`);
456
- return;
457
- }
458
- if (/^<\/(exec|shell|read_file|write_file)/.test(line)) {
459
- process.stdout.write(` ${FG_TAG}${line}${RST}\n`);
460
- return;
461
- }
462
-
463
- const hm = line.match(/^(#{1,4})\s+(.*)/);
464
- if (hm) {
465
- const text = hm[2];
466
- if (hm[1].length <= 2) {
467
- process.stdout.write(` ${FG_HEADING}${BOLD}${hm[1]} ${text}${RST}\n`);
468
- } else {
469
- process.stdout.write(` ${FG_HEADING}${hm[1]} ${text}${RST}\n`);
470
- }
471
- return;
472
- }
473
-
474
- const bm = line.match(/^(\s*)([-*•])\s+(.*)/);
475
- if (bm) {
476
- process.stdout.write(` ${bm[1]}${FG_BULLET}•${RST} ${this._inlineFormat(bm[3])}\n`);
477
- return;
478
- }
479
-
480
- const nm = line.match(/^(\s*)(\d+\.)\s+(.*)/);
481
- if (nm) {
482
- process.stdout.write(` ${nm[1]}${FG_CYAN}${nm[2]}${RST} ${this._inlineFormat(nm[3])}\n`);
483
- return;
484
- }
485
-
486
- process.stdout.write(` ${this._inlineFormat(line)}\n`);
487
- }
488
-
489
- _inlineFormat(text) {
490
- text = text.replace(/\*\*(.+?)\*\*/g, `${FG_BOLD_TEXT}${BOLD}$1${RST}`);
491
- text = text.replace(/`([^`]+)`/g, `${FG_INLINE_CODE}$1${RST}`);
492
- text = text.replace(/(?<!\w)((?:\/[\w\-.]+)+(?:\.\w+)?)/g, `${FG_FILEPATH}$1${RST}`);
493
- return text;
494
- }
495
-
496
- _colorizeCode(line) {
497
- const C_KW = '\x1b[38;5;176m';
498
- const C_STR = '\x1b[38;5;114m';
499
- const C_CMT = '\x1b[38;5;242m';
500
- const C_NUM = '\x1b[38;5;215m';
501
- const C_RST = `${RST}${FG_CODE_BG}`;
502
-
503
- let result = '';
504
- let i = 0;
505
-
506
- while (i < line.length) {
507
- if (line[i] === '#' || (line[i] === '/' && line[i + 1] === '/')) {
508
- result += `${C_CMT}${line.slice(i)}${C_RST}`;
509
- break;
510
- }
511
-
512
- if (line[i] === '"' || line[i] === "'") {
513
- const quote = line[i];
514
- let j = i + 1;
515
- while (j < line.length && line[j] !== quote) {
516
- if (line[j] === '\\') j++;
517
- j++;
518
- }
519
- j = Math.min(j + 1, line.length);
520
- result += `${C_STR}${line.slice(i, j)}${C_RST}`;
521
- i = j;
522
- continue;
523
- }
524
-
525
- if (/[a-zA-Z_]/.test(line[i])) {
526
- let j = i;
527
- while (j < line.length && /\w/.test(line[j])) j++;
528
- const word = line.slice(i, j);
529
- result += KEYWORDS.has(word) ? `${C_KW}${word}${C_RST}` : word;
530
- i = j;
531
- continue;
532
- }
533
-
534
- if (/\d/.test(line[i])) {
535
- let j = i;
536
- while (j < line.length && /[\d.]/.test(line[j])) j++;
537
- result += `${C_NUM}${line.slice(i, j)}${C_RST}`;
538
- i = j;
539
- continue;
540
- }
541
-
542
- result += line[i++];
543
- }
544
-
545
- return result;
546
- }
547
- }
548
-
549
- function printBanner() {
550
- const w = Math.min(getCols() - 4, 60);
551
- console.log();
552
- console.log(` ${FG_DARK}${BOX_TL}${BOX_H.repeat(w + 2)}${BOX_TR}${RST}`);
553
- console.log(boxLine('', w));
554
- console.log(boxLine(`${FG_TEAL}${BOLD}◆ Semalt.AI${RST}`, w));
555
- console.log(boxLine(`${FG_GRAY}Self-hosted AI coding assistant${RST}`, w));
556
- console.log(boxLine('', w));
557
- console.log(` ${FG_DARK}${BOX_BL}${BOX_H.repeat(w + 2)}${BOX_BR}${RST}`);
558
- console.log();
559
- }
560
-
561
- function printStatusBar(model, cwd) {
562
- const left = `${FG_TEAL}${BOLD}◆${RST} ${FG_GRAY}${model}${RST}`;
563
- const right = `${FG_DARK}${cwd}${RST}`;
564
- console.log(` ${left} ${FG_DARK}│${RST} ${right}`);
565
- hr();
566
- }
567
-
568
- function printHelpHints() {
569
- const hints = [
570
- [`${FG_BLUE}/help${RST}`, 'commands'],
571
- [`${FG_BLUE}/model${RST}`, 'switch'],
572
- [`${FG_BLUE}/file${RST}`, 'context'],
573
- [`${FG_BLUE}/clear${RST}`, 'reset'],
574
- ];
575
- process.stdout.write(` ${FG_DARK}Tips:${RST}`);
576
- for (const [cmd, desc] of hints) {
577
- process.stdout.write(` ${cmd} ${FG_DARK}${desc}${RST}`);
578
- }
579
- console.log();
580
- console.log();
581
- }
3
+ const ansi = require('./ui/ansi');
4
+ const utils = require('./ui/utils');
5
+ const diff = require('./ui/diff');
6
+ const stream = require('./ui/stream');
7
+ const legacy = require('./ui/legacy');
8
+ const layout = require('./ui/layout');
9
+ const history = require('./ui/chat-history');
10
+ const statusB = require('./ui/status-bar');
11
+ const input = require('./ui/input-field');
12
+ const createUi = require('./ui/create-ui');
582
13
 
583
14
  module.exports = {
584
- BOLD,
585
- DIM,
586
- FG_BLUE,
587
- FG_CYAN,
588
- FG_DARK,
589
- FG_GRAY,
590
- FG_GREEN,
591
- FG_RED,
592
- FG_TEAL,
593
- FG_YELLOW,
594
- RST,
595
- StreamRenderer,
596
- getCols,
597
- hr,
598
- printBanner,
599
- printHelpHints,
600
- printStatusBar,
601
- readInteractiveInput,
602
- stripAnsi,
15
+ // ANSI constants
16
+ BOLD: ansi.BOLD, DIM: ansi.DIM, RST: ansi.RST, THEME: ansi.THEME,
17
+ FG_BLUE: ansi.FG_BLUE, FG_CYAN: ansi.FG_CYAN, FG_DARK: ansi.FG_DARK,
18
+ FG_GRAY: ansi.FG_GRAY, FG_GREEN: ansi.FG_GREEN, FG_RED: ansi.FG_RED,
19
+ FG_TEAL: ansi.FG_TEAL, FG_YELLOW: ansi.FG_YELLOW,
20
+ BG_SELECTED: ansi.BG_SELECTED,
21
+
22
+ // Utilities
23
+ getCols: utils.getCols, getRows: utils.getRows, stripAnsi: utils.stripAnsi,
24
+ hr: utils.hr, boxLine: utils.boxLine,
25
+ insertCharAt: utils.insertCharAt, removeCharAt: utils.removeCharAt,
26
+ isPrintableKey: utils.isPrintableKey,
27
+
28
+ // Diff + Markdown
29
+ renderDiff: diff.renderDiff, renderMarkdown: diff.renderMarkdown,
30
+
31
+ // Stream renderer
32
+ StreamRenderer: stream.StreamRenderer,
33
+
34
+ // Legacy (still-active) components
35
+ StatusBar: legacy.StatusBar, interactiveSelect: legacy.interactiveSelect,
36
+ SelectMenu: legacy.SelectMenu,
37
+
38
+ // TUI components
39
+ LayoutManager: layout.LayoutManager,
40
+ ChatHistory: history.ChatHistory,
41
+ FullStatusBar: statusB.FullStatusBar,
42
+ InputField: input.InputField,
43
+ parseKeySequence: input.parseKeySequence,
44
+
45
+ // Factory
46
+ createUI: createUi.createUI,
603
47
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semalt-ai/code",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Self-hosted AI Coding Assistant CLI",
5
5
  "main": "index.js",
6
6
  "bin": {
package/path ADDED
@@ -0,0 +1 @@
1
+ contenttext