lastgen-cli 1.0.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.
@@ -0,0 +1,799 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/ui.ts
4
+ import * as readline from "readline";
5
+ import { stdin, stdout } from "process";
6
+ import chalk from "chalk";
7
+ var colors = {
8
+ brand: chalk.hex("#e6007e").bold,
9
+ // Türk Telekom magenta
10
+ border: chalk.hex("#1577d4"),
11
+ // kurumsal mavi, ince
12
+ logo: chalk.hex("#1577d4").bold,
13
+ user: chalk.cyan.bold,
14
+ assistant: chalk.green.bold,
15
+ dim: chalk.gray,
16
+ error: chalk.red.bold,
17
+ info: chalk.yellow,
18
+ ok: chalk.green,
19
+ white: chalk.whiteBright
20
+ };
21
+ var INNER = 82;
22
+ var _lMain = chalk.hex("#1577d4").bold;
23
+ var _lShadow = chalk.hex("#0b2d5e");
24
+ var BM_L = ["10000", "10000", "10000", "10000", "11111"];
25
+ var BM_A = ["01110", "10001", "11111", "10001", "10001"];
26
+ var BM_S = ["11111", "10000", "01110", "00001", "11111"];
27
+ var BM_T = ["11111", "00100", "00100", "00100", "00100"];
28
+ var BM_G = ["01110", "10000", "10011", "10001", "01110"];
29
+ var BM_E = ["11111", "10000", "11110", "10000", "11111"];
30
+ var BM_N = ["10001", "11001", "10101", "10011", "10001"];
31
+ var _BMS = [BM_L, BM_A, BM_S, BM_T, BM_G, BM_E, BM_N];
32
+ function pxRaw(row) {
33
+ return [...row].map((c) => c === "1" ? "\u2588\u2591" : " ").join("");
34
+ }
35
+ function pxCol(row) {
36
+ return [...row].map((c) => c === "1" ? _lMain("\u2593") + _lShadow("\u2591") : " ").join("");
37
+ }
38
+ var LOGO_RAW = [0, 1, 2, 3, 4].map((r) => _BMS.map((bm) => pxRaw(bm[r])).join(" "));
39
+ var LOGO_COL = [0, 1, 2, 3, 4].map((r) => _BMS.map((bm) => pxCol(bm[r])).join(" "));
40
+ var LOGO_GRID = [0, 1, 2, 3, 4].map(
41
+ (r) => _BMS.flatMap((bm) => [...bm[r]])
42
+ );
43
+ var LOGO_COLS = LOGO_GRID[0]?.length ?? 0;
44
+ var LOGO_ROWS = LOGO_GRID.length;
45
+ function buildLogoSettle(totalFrames) {
46
+ return Array.from(
47
+ { length: LOGO_ROWS },
48
+ () => Array.from({ length: LOGO_COLS }, () => Math.floor(Math.random() * totalFrames))
49
+ );
50
+ }
51
+ function logoDecodeLines(frame, totalFrames, settle = buildLogoSettle(totalFrames)) {
52
+ const lines = [];
53
+ for (let r = 0; r < LOGO_ROWS; r++) {
54
+ let line = "";
55
+ for (let c = 0; c < LOGO_COLS; c++) {
56
+ if (c > 0 && c % 5 === 0) line += " ";
57
+ const on = LOGO_GRID[r][c] === "1";
58
+ if (!on) {
59
+ line += " ";
60
+ } else if (frame >= settle[r][c]) {
61
+ line += _lMain("\u2593") + _lShadow("\u2591");
62
+ } else {
63
+ const g = randomGlitchChar();
64
+ line += turquoiseDim(g) + turquoiseDim(g);
65
+ }
66
+ }
67
+ lines.push(line);
68
+ }
69
+ return lines;
70
+ }
71
+ var LOGO_LINE_COUNT = LOGO_ROWS;
72
+ function boxRow(plain, color = (s) => s) {
73
+ const vis = [...plain].length;
74
+ const pad = Math.max(0, INNER - vis);
75
+ return colors.border("\u2502 ") + color(plain) + " ".repeat(pad) + colors.border(" \u2502");
76
+ }
77
+ function boxTop() {
78
+ return colors.border("\u256D" + "\u2500".repeat(INNER + 2) + "\u256E");
79
+ }
80
+ function boxBottom() {
81
+ return colors.border("\u2570" + "\u2500".repeat(INNER + 2) + "\u256F");
82
+ }
83
+ function boxBlank() {
84
+ return boxRow("");
85
+ }
86
+ function bannerLines(model, logoLines) {
87
+ const logo = logoLines ?? LOGO_COL;
88
+ const lines = [];
89
+ const logoMaxW = Math.max(...LOGO_RAW.map((r) => [...r].length));
90
+ const logoIndent = " ".repeat(Math.max(0, Math.floor((INNER - logoMaxW) / 2)));
91
+ lines.push(boxTop());
92
+ lines.push(boxBlank());
93
+ lines.push(boxBlank());
94
+ for (let i = 0; i < logo.length; i++) {
95
+ const raw = logoIndent + (logoLines ? logoLines[i] : LOGO_COL[i]);
96
+ const vis = visibleLength(raw);
97
+ const pad = Math.max(0, INNER - vis);
98
+ lines.push(colors.border("\u2502 ") + raw + " ".repeat(pad) + colors.border(" \u2502"));
99
+ }
100
+ lines.push(boxBlank());
101
+ lines.push(boxBlank());
102
+ lines.push(boxRow(" Lastgen CLI \xB7 Global | Enterprise AI Terminal Assistant", colors.white));
103
+ lines.push(boxRow(" Lastgen Software CLI Project", colors.dim));
104
+ lines.push(boxBlank());
105
+ lines.push(boxRow(` Aktif model: ${model ?? "(giri\u015F bekleniyor)"}`, colors.dim));
106
+ lines.push(boxRow(" OpenAI uyumlu \xB7 Streaming yan\u0131t \xB7 /help \xB7 /exit", colors.dim));
107
+ lines.push(boxBlank());
108
+ lines.push(boxBottom());
109
+ return lines;
110
+ }
111
+ function banner(model) {
112
+ stdout.write("\n" + bannerLines(model).join("\n") + "\n\n");
113
+ }
114
+ async function bannerDecode(model) {
115
+ if (!stdout.isTTY) {
116
+ banner(model);
117
+ return;
118
+ }
119
+ const TOTAL_FRAMES = 16;
120
+ const settle = buildLogoSettle(TOTAL_FRAMES);
121
+ const initialLogo = logoDecodeLines(0, TOTAL_FRAMES, settle);
122
+ const initialBanner = bannerLines(model, initialLogo);
123
+ const bannerLineCount = initialBanner.length;
124
+ stdout.write("\n" + initialBanner.join("\n") + "\n");
125
+ const moveUp = `\x1B[${bannerLineCount + 1}A`;
126
+ for (let frame = 1; frame <= TOTAL_FRAMES; frame++) {
127
+ const logoLines = logoDecodeLines(frame, TOTAL_FRAMES, settle);
128
+ const banner2 = bannerLines(model, logoLines);
129
+ stdout.write(moveUp + "\r\x1B[J" + banner2.join("\n") + "\n");
130
+ await new Promise((r) => setTimeout(r, 70));
131
+ }
132
+ stdout.write("\n");
133
+ }
134
+ var outputSink = null;
135
+ function setOutputSink(fn) {
136
+ outputSink = fn;
137
+ }
138
+ function out(s) {
139
+ const safe = typeof s === "string" ? s : String(s ?? "");
140
+ if (outputSink) outputSink(safe);
141
+ else stdout.write(safe);
142
+ }
143
+ function info(msg) {
144
+ out(colors.info("\u2022 ") + msg + "\n");
145
+ }
146
+ function ok(msg) {
147
+ out(colors.ok("\u2713 ") + msg + "\n");
148
+ }
149
+ function goodbye() {
150
+ stdout.write("\n" + colors.brand("\u{1F44B} G\xF6r\xFC\u015F\xFCr\xFCz! ") + colors.dim("QAI kapan\u0131yor.") + "\n");
151
+ }
152
+ function error(msg) {
153
+ out(colors.error("\u2717 ") + msg + "\n");
154
+ }
155
+ function write(text) {
156
+ out(typeof text === "string" ? text : String(text ?? ""));
157
+ }
158
+ function newline() {
159
+ out("\n");
160
+ }
161
+ function promptExtraContext(taskTitle, taskDesc) {
162
+ return new Promise((resolve) => {
163
+ const W = Math.min(stdout.columns && stdout.columns > 8 ? stdout.columns : 68, 68);
164
+ const inner = W - 4;
165
+ const wrapWords = (text, width) => {
166
+ const words = text.split(/\s+/).filter(Boolean);
167
+ if (words.length === 0) return [""];
168
+ const lines = [];
169
+ let cur = "";
170
+ for (const word of words) {
171
+ if ([...cur].length + ([...cur].length > 0 ? 1 : 0) + [...word].length > width) {
172
+ if (cur) lines.push(cur);
173
+ if ([...word].length > width) {
174
+ const chars = [...word];
175
+ for (let i = 0; i < chars.length; i += width) {
176
+ lines.push(chars.slice(i, i + width).join(""));
177
+ }
178
+ cur = "";
179
+ } else {
180
+ cur = word;
181
+ }
182
+ } else {
183
+ cur = cur ? cur + " " + word : word;
184
+ }
185
+ }
186
+ if (cur) lines.push(cur);
187
+ return lines;
188
+ };
189
+ const titleLines = wrapWords(taskTitle, inner - 2);
190
+ const descLines = taskDesc?.trim() ? wrapWords(taskDesc.trim(), inner) : [];
191
+ const boxLine = (content, color) => {
192
+ const colored = color ? color(content) : content;
193
+ const vis = visibleLength(colored);
194
+ const pad = Math.max(0, inner - vis);
195
+ return colors.border("\u2502 ") + colored + " ".repeat(pad) + colors.border(" \u2502");
196
+ };
197
+ stdout.write("\n");
198
+ stdout.write(colors.border("\u256D" + "\u2500".repeat(inner + 2) + "\u256E") + "\n");
199
+ stdout.write(boxLine("Se\xE7ilen Task", colors.brand) + "\n");
200
+ stdout.write(colors.border("\u251C" + "\u2500".repeat(inner + 2) + "\u2524") + "\n");
201
+ for (const line of titleLines) {
202
+ stdout.write(boxLine("\u25B8 " + line, colors.white) + "\n");
203
+ }
204
+ if (descLines.length > 0) {
205
+ stdout.write(boxLine("") + "\n");
206
+ stdout.write(boxLine("A\xE7\u0131klama:", colors.dim) + "\n");
207
+ for (const line of descLines.slice(0, 6)) {
208
+ stdout.write(boxLine(line, colors.dim) + "\n");
209
+ }
210
+ if (descLines.length > 6) {
211
+ stdout.write(boxLine("\u2026", colors.dim) + "\n");
212
+ }
213
+ }
214
+ stdout.write(colors.border("\u2570" + "\u2500".repeat(inner + 2) + "\u256F") + "\n");
215
+ const query = colors.dim(" Ekstra bilgi (opsiyonel, bo\u015F Enter = ge\xE7): ");
216
+ if (!stdin.isTTY) {
217
+ const rl = readline.createInterface({ input: stdin, output: stdout, terminal: false });
218
+ rl.question(query, (answer) => {
219
+ rl.close();
220
+ stdout.write("\n");
221
+ resolve(answer.trim());
222
+ });
223
+ return;
224
+ }
225
+ const wasRaw = Boolean(stdin.isRaw);
226
+ stdout.write(query);
227
+ stdin.setRawMode(true);
228
+ stdin.resume();
229
+ stdin.setEncoding("utf8");
230
+ let value = "";
231
+ function cleanup() {
232
+ stdin.removeListener("data", onData);
233
+ stdin.setRawMode(wasRaw);
234
+ stdin.pause();
235
+ }
236
+ function redraw() {
237
+ stdout.write(`\r\x1B[2K${query}${value}`);
238
+ }
239
+ function onData(chunk) {
240
+ for (const ch of chunk) {
241
+ const code = ch.charCodeAt(0);
242
+ if (ch === "\r" || ch === "\n") {
243
+ cleanup();
244
+ stdout.write("\n");
245
+ resolve(value.trim());
246
+ return;
247
+ } else if (code === 27 || chunk === "\x1B") {
248
+ cleanup();
249
+ stdout.write("\n");
250
+ resolve("");
251
+ return;
252
+ } else if (code === CTRL_C) {
253
+ cleanup();
254
+ goodbye();
255
+ process.exit(0);
256
+ } else if (code === BACKSPACE || code === DEL) {
257
+ if (value.length > 0) {
258
+ value = [...value].slice(0, -1).join("");
259
+ redraw();
260
+ }
261
+ } else if (code >= 32) {
262
+ value += ch;
263
+ stdout.write(ch);
264
+ }
265
+ }
266
+ }
267
+ stdin.on("data", onData);
268
+ });
269
+ }
270
+ var GUTTER = " ";
271
+ var PROMPT_LABEL = " siz \u203A ";
272
+ function userPromptLabel() {
273
+ return colors.user(PROMPT_LABEL);
274
+ }
275
+ function ruleWidth() {
276
+ const cols = stdout.columns && stdout.columns > 8 ? stdout.columns : 60;
277
+ return Math.min(cols, 68);
278
+ }
279
+ function renderUserBubble(input) {
280
+ stdout.write(`${GUTTER}${colors.user("\u25E4 siz")}
281
+ `);
282
+ for (const ln of input.split("\n")) {
283
+ stdout.write(`${GUTTER}${colors.white(ln)}
284
+ `);
285
+ }
286
+ }
287
+ function assistantHeader(model) {
288
+ const badge = colors.assistant("\u25E2 lastgen");
289
+ const m = model ? colors.dim(" \xB7 " + model) : "";
290
+ stdout.write(`
291
+ ${GUTTER}${badge}${m}
292
+ `);
293
+ }
294
+ function turnSeparator() {
295
+ stdout.write(colors.dim("\u2500".repeat(ruleWidth())) + "\n");
296
+ }
297
+ var THINKING_PHRASES = [
298
+ "D\xFC\u015F\xFCn\xFCl\xFCyor...",
299
+ "Analiz ediliyor...",
300
+ "\u0130\u015Fleniyor...",
301
+ "Sentezleniyor...",
302
+ "Muhakeme ediliyor...",
303
+ "D\xFC\u015F\xFCnceler aras\u0131nda geziniyor...",
304
+ "Derinlere iniliyor...",
305
+ "Tart\u0131p bi\xE7iyor...",
306
+ "Zihin labirentinde dola\u015F\u0131yor...",
307
+ "\u0130nce elenip s\u0131k dokunuyor...",
308
+ "Geziniyor...",
309
+ "\u0130htimaller taran\u0131yor...",
310
+ "\xC7arklar d\xF6n\xFCyor...",
311
+ "N\xF6ronlar ate\u015Fleniyor...",
312
+ "Par\xE7alar birle\u015Ftiriliyor...",
313
+ "Veri havuzunda kula\xE7 at\u0131l\u0131yor..."
314
+ ];
315
+ function pickThinkingPhrase() {
316
+ return THINKING_PHRASES[Math.floor(Math.random() * THINKING_PHRASES.length)];
317
+ }
318
+ var turquoise = chalk.hex("#1577d4").bold;
319
+ var turquoiseDim = chalk.hex("#0a3d6e");
320
+ var GLITCH_CHARS = "01abcdef#$@!*&%<>/{}[]~^?+=".split("");
321
+ function randomGlitchChar() {
322
+ return GLITCH_CHARS[Math.floor(Math.random() * GLITCH_CHARS.length)];
323
+ }
324
+ function decodeFrame(target, settleAt, frame, glitch = randomGlitchChar) {
325
+ let out2 = "";
326
+ for (let i = 0; i < target.length; i++) {
327
+ const ch = target[i];
328
+ if (ch === " ") {
329
+ out2 += " ";
330
+ continue;
331
+ }
332
+ out2 += frame >= settleAt[i] ? ch : glitch();
333
+ }
334
+ return out2;
335
+ }
336
+ function buildSettle(len, frames) {
337
+ return Array.from({ length: len }, () => Math.floor(Math.random() * frames));
338
+ }
339
+ var SCRAMBLE_FRAMES = 12;
340
+ var HOLD_FRAMES = 22;
341
+ var FRAME_MS = 45;
342
+ function formatTokens(n) {
343
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
344
+ return String(n);
345
+ }
346
+ function startThinking(indent = "", rightInfo) {
347
+ if (!stdout.isTTY) {
348
+ stdout.write(indent + turquoise("\u2022 " + pickThinkingPhrase()));
349
+ return { stop: () => stdout.write("\r\x1B[K") };
350
+ }
351
+ let target = pickThinkingPhrase();
352
+ let settleAt = buildSettle(target.length, SCRAMBLE_FRAMES);
353
+ let frame = 0;
354
+ let holding = 0;
355
+ const draw = (text) => {
356
+ const info2 = rightInfo ? colors.dim(" " + rightInfo()) : "";
357
+ stdout.write("\r\x1B[K" + indent + turquoise("\u2022 ") + text + info2);
358
+ };
359
+ const tick = () => {
360
+ if (holding > 0) {
361
+ draw(turquoise(target));
362
+ holding--;
363
+ return;
364
+ }
365
+ const maxSettle = SCRAMBLE_FRAMES;
366
+ if (frame <= maxSettle) {
367
+ let out2 = "";
368
+ for (let i = 0; i < target.length; i++) {
369
+ const ch = target[i];
370
+ if (ch === " ") {
371
+ out2 += " ";
372
+ } else if (frame >= settleAt[i]) {
373
+ out2 += turquoise(ch);
374
+ } else {
375
+ out2 += turquoiseDim(randomGlitchChar());
376
+ }
377
+ }
378
+ draw(out2);
379
+ frame++;
380
+ } else {
381
+ holding = HOLD_FRAMES;
382
+ let next = pickThinkingPhrase();
383
+ while (next === target && THINKING_PHRASES.length > 1) next = pickThinkingPhrase();
384
+ target = next;
385
+ settleAt = buildSettle(target.length, SCRAMBLE_FRAMES);
386
+ frame = 0;
387
+ }
388
+ };
389
+ tick();
390
+ const timer = setInterval(tick, FRAME_MS);
391
+ timer.unref?.();
392
+ return {
393
+ stop: () => {
394
+ clearInterval(timer);
395
+ stdout.write("\r\x1B[K");
396
+ }
397
+ };
398
+ }
399
+ var CTRL_C = 3;
400
+ var BACKSPACE = 8;
401
+ var DEL = 127;
402
+ function prompt(query) {
403
+ return new Promise((resolve) => {
404
+ if (!stdin.isTTY) {
405
+ const rl = readline.createInterface({ input: stdin, output: stdout, terminal: false });
406
+ rl.question(query, (answer) => {
407
+ rl.close();
408
+ resolve(answer.trim());
409
+ });
410
+ return;
411
+ }
412
+ const wasRaw = Boolean(stdin.isRaw);
413
+ stdout.write(query);
414
+ stdin.setRawMode(true);
415
+ stdin.resume();
416
+ stdin.setEncoding("utf8");
417
+ let value = "";
418
+ function cleanup() {
419
+ stdin.removeListener("data", onData);
420
+ stdin.setRawMode(wasRaw);
421
+ stdin.pause();
422
+ }
423
+ function redraw() {
424
+ stdout.write(`\r\x1B[2K${query}${value}`);
425
+ }
426
+ function onData(chunk) {
427
+ for (const ch of chunk) {
428
+ const code = ch.charCodeAt(0);
429
+ if (ch === "\r" || ch === "\n") {
430
+ cleanup();
431
+ stdout.write("\n");
432
+ resolve(value.trim());
433
+ return;
434
+ } else if (code === 27 || chunk === "\x1B") {
435
+ cleanup();
436
+ stdout.write("\n");
437
+ resolve(null);
438
+ return;
439
+ } else if (code === CTRL_C) {
440
+ cleanup();
441
+ goodbye();
442
+ process.exit(0);
443
+ } else if (code === BACKSPACE || code === DEL) {
444
+ if (value.length > 0) {
445
+ value = [...value].slice(0, -1).join("");
446
+ redraw();
447
+ }
448
+ } else if (code >= 32) {
449
+ value += ch;
450
+ stdout.write(ch);
451
+ }
452
+ }
453
+ }
454
+ stdin.on("data", onData);
455
+ });
456
+ }
457
+ function promptHidden(query) {
458
+ return new Promise((resolve) => {
459
+ stdout.write(query);
460
+ if (!stdin.isTTY) {
461
+ const rl = readline.createInterface({ input: stdin });
462
+ rl.question("", (answer) => {
463
+ rl.close();
464
+ stdout.write("\n");
465
+ resolve(answer.trim());
466
+ });
467
+ return;
468
+ }
469
+ const wasRaw = Boolean(stdin.isRaw);
470
+ stdin.setRawMode(true);
471
+ stdin.resume();
472
+ stdin.setEncoding("utf8");
473
+ let value = "";
474
+ function cleanup() {
475
+ stdin.removeListener("data", onData);
476
+ stdin.setRawMode(wasRaw);
477
+ stdin.pause();
478
+ }
479
+ function onData(chunk) {
480
+ for (const ch of chunk) {
481
+ const code = ch.charCodeAt(0);
482
+ if (ch === "\r" || ch === "\n") {
483
+ cleanup();
484
+ stdout.write("\n");
485
+ resolve(value.trim());
486
+ return;
487
+ } else if (code === 27 || chunk === "\x1B") {
488
+ cleanup();
489
+ stdout.write("\n");
490
+ resolve(null);
491
+ return;
492
+ } else if (code === CTRL_C) {
493
+ cleanup();
494
+ goodbye();
495
+ process.exit(0);
496
+ } else if (code === BACKSPACE || code === DEL) {
497
+ if (value.length > 0) {
498
+ value = value.slice(0, -1);
499
+ stdout.write("\b \b");
500
+ }
501
+ } else if (code >= 32) {
502
+ value += ch;
503
+ stdout.write("*");
504
+ }
505
+ }
506
+ }
507
+ stdin.on("data", onData);
508
+ });
509
+ }
510
+ function pick(items, defaultIndex = 0) {
511
+ return new Promise((resolve) => {
512
+ if (!stdin.isTTY || items.length === 0) {
513
+ resolve(0);
514
+ return;
515
+ }
516
+ let sel = Math.max(0, Math.min(defaultIndex, items.length - 1));
517
+ const wasRaw = Boolean(stdin.isRaw);
518
+ function draw() {
519
+ if (items.length > 0) stdout.write(`\x1B[${items.length * 2}A`);
520
+ items.forEach((item, i) => {
521
+ const active = i === sel;
522
+ const prefix = active ? colors.ok(" \u276F ") : " ";
523
+ const label = active ? chalk.whiteBright.bold(item.label) : colors.dim(item.label);
524
+ stdout.write(`\x1B[2K${prefix}${label}
525
+ `);
526
+ const desc = item.description ?? "";
527
+ stdout.write(`\x1B[2K ${colors.dim(desc)}
528
+ `);
529
+ });
530
+ }
531
+ items.forEach((item) => {
532
+ stdout.write(` ${colors.dim(item.label)}
533
+ `);
534
+ stdout.write(` ${colors.dim(item.description ?? "")}
535
+ `);
536
+ });
537
+ draw();
538
+ function cleanup(result) {
539
+ stdin.setRawMode(wasRaw);
540
+ stdin.removeListener("data", onData);
541
+ if (!wasRaw) stdin.pause();
542
+ resolve(result);
543
+ }
544
+ function onData(chunk) {
545
+ const code = chunk.charCodeAt(0);
546
+ if (code === 3) {
547
+ cleanup(null);
548
+ return;
549
+ }
550
+ if (chunk === "\x1B" || chunk === "\x1B\x1B") {
551
+ cleanup(null);
552
+ return;
553
+ }
554
+ if (chunk === "\x1B[A") {
555
+ sel = sel > 0 ? sel - 1 : items.length - 1;
556
+ draw();
557
+ return;
558
+ }
559
+ if (chunk === "\x1B[B") {
560
+ sel = sel < items.length - 1 ? sel + 1 : 0;
561
+ draw();
562
+ return;
563
+ }
564
+ if (chunk === "\r" || chunk === "\n") {
565
+ cleanup(sel);
566
+ return;
567
+ }
568
+ }
569
+ stdin.setRawMode(true);
570
+ stdin.resume();
571
+ stdin.setEncoding("utf8");
572
+ stdin.on("data", onData);
573
+ });
574
+ }
575
+ var ANSI_RE = /\x1B\[[0-9;]*m/g;
576
+ function visibleLength(s) {
577
+ return [...s.replace(ANSI_RE, "")].length;
578
+ }
579
+ function wrapAnsi(s, width) {
580
+ if (width <= 0) return [s];
581
+ const out2 = [];
582
+ let cur = "";
583
+ let curVis = 0;
584
+ let i = 0;
585
+ while (i < s.length) {
586
+ const m = s.slice(i).match(/^\x1B\[[0-9;]*m/);
587
+ if (m) {
588
+ cur += m[0];
589
+ i += m[0].length;
590
+ continue;
591
+ }
592
+ cur += s[i];
593
+ curVis += 1;
594
+ i += 1;
595
+ if (curVis >= width) {
596
+ out2.push(cur);
597
+ cur = "";
598
+ curVis = 0;
599
+ }
600
+ }
601
+ if (cur !== "") {
602
+ if (curVis === 0 && out2.length > 0) out2[out2.length - 1] += cur;
603
+ else out2.push(cur);
604
+ }
605
+ if (out2.length === 0) out2.push("");
606
+ return out2;
607
+ }
608
+ function tokenLabel(totalTokens) {
609
+ return totalTokens > 0 ? ` total token: ${formatTokens(totalTokens)} ` : "";
610
+ }
611
+ function buildInputRule(totalTokens, width) {
612
+ const label = tokenLabel(totalTokens);
613
+ const dashes = Math.max(0, width - [...label].length);
614
+ return "\u2500".repeat(dashes) + label;
615
+ }
616
+ async function promptBoxed(totalTokens = 0) {
617
+ if (stdout.isTTY) {
618
+ const cols = stdout.columns && stdout.columns > 0 ? stdout.columns : 80;
619
+ const w = Math.min(cols, 80);
620
+ const label = tokenLabel(totalTokens);
621
+ const dashes = Math.max(0, w - [...label].length);
622
+ stdout.write(
623
+ "\n" + colors.border("\u2500".repeat(dashes)) + colors.dim(label) + "\n"
624
+ );
625
+ }
626
+ return await prompt(colors.user(" \u25E4 siz \u203A ")) ?? "";
627
+ }
628
+ function closeInput() {
629
+ }
630
+ var PIN_RESERVED = 3;
631
+ function startPinnedChat(opts) {
632
+ if (!stdin.isTTY || !stdout.isTTY || !stdout.rows) return null;
633
+ const wasRaw = Boolean(stdin.isRaw);
634
+ let boxText = "";
635
+ let busy = false;
636
+ let suspended = false;
637
+ const queue = [];
638
+ const rows = () => stdout.rows || 24;
639
+ const cols = () => stdout.columns || 80;
640
+ function setRegion() {
641
+ stdout.write("\x1B7");
642
+ stdout.write(`\x1B[1;${Math.max(1, rows() - PIN_RESERVED)}r`);
643
+ stdout.write("\x1B8");
644
+ }
645
+ function drawBox() {
646
+ if (suspended) return;
647
+ const C = cols();
648
+ const R = rows();
649
+ const w = C;
650
+ const topDashes = Math.max(0, w - 2 - "\u2500 siz ".length);
651
+ const top = colors.border("\u256D\u2500") + colors.user(" siz ") + colors.border("\u2500".repeat(topDashes)) + colors.border("\u256E");
652
+ const contentW = w - 4;
653
+ const textArea = Math.max(1, contentW - 2);
654
+ const chars = [...boxText];
655
+ const shown = chars.length > textArea - 1 ? chars.slice(chars.length - (textArea - 1)).join("") : boxText;
656
+ const caret = chalk.inverse(" ");
657
+ const vis = 2 + [...shown].length + 1;
658
+ const pad = Math.max(0, contentW - vis);
659
+ const line = colors.border("\u2502 ") + colors.user("\u203A ") + colors.white(shown) + caret + " ".repeat(pad) + colors.border(" \u2502");
660
+ const tot = opts.totalTokens();
661
+ const label = tot > 0 ? ` \u03A3 ${formatTokens(tot)} tok ` : "";
662
+ const dash = Math.max(0, w - 2 - label.length);
663
+ const bottom = colors.border("\u2570" + "\u2500".repeat(dash)) + colors.dim(label) + colors.border("\u256F");
664
+ stdout.write("\x1B7");
665
+ stdout.write(`\x1B[${R - 2};1H\x1B[2K` + top);
666
+ stdout.write(`\x1B[${R - 1};1H\x1B[2K` + line);
667
+ stdout.write(`\x1B[${R};1H\x1B[2K` + bottom);
668
+ stdout.write("\x1B8");
669
+ }
670
+ function run(text) {
671
+ busy = true;
672
+ Promise.resolve(opts.onSubmit(text)).finally(() => {
673
+ busy = false;
674
+ if (queue.length > 0) run(queue.shift());
675
+ });
676
+ }
677
+ function onData(chunk) {
678
+ if (suspended) return;
679
+ if (chunk.charCodeAt(0) === 27) return;
680
+ let submit = false;
681
+ for (const ch of chunk) {
682
+ const code = ch.charCodeAt(0);
683
+ if (ch === "\r" || ch === "\n") {
684
+ submit = true;
685
+ break;
686
+ } else if (code === CTRL_C) {
687
+ opts.onExit();
688
+ return;
689
+ } else if (code === BACKSPACE || code === DEL) {
690
+ boxText = [...boxText].slice(0, -1).join("");
691
+ } else if (code >= 32) {
692
+ boxText += ch;
693
+ }
694
+ }
695
+ if (submit) {
696
+ const t = boxText.trim();
697
+ boxText = "";
698
+ drawBox();
699
+ if (t.length > 0) {
700
+ if (busy) queue.push(t);
701
+ else run(t);
702
+ }
703
+ return;
704
+ }
705
+ drawBox();
706
+ }
707
+ let resizeTimer;
708
+ function onResize() {
709
+ if (resizeTimer) clearTimeout(resizeTimer);
710
+ resizeTimer = setTimeout(() => {
711
+ resizeTimer = void 0;
712
+ setRegion();
713
+ drawBox();
714
+ }, 120);
715
+ }
716
+ stdin.setRawMode(true);
717
+ stdin.resume();
718
+ stdin.setEncoding("utf8");
719
+ stdout.write("\x1B[?25l");
720
+ setRegion();
721
+ drawBox();
722
+ stdin.on("data", onData);
723
+ stdout.on("resize", onResize);
724
+ return {
725
+ refresh: () => drawBox(),
726
+ suspend: () => {
727
+ suspended = true;
728
+ stdin.removeListener("data", onData);
729
+ stdin.setRawMode(wasRaw);
730
+ stdout.write("\x1B[r");
731
+ stdout.write("\x1B[?25h");
732
+ stdout.write(`\x1B[${rows()};1H
733
+ `);
734
+ },
735
+ resume: () => {
736
+ suspended = false;
737
+ stdin.setRawMode(true);
738
+ stdin.resume();
739
+ stdin.setEncoding("utf8");
740
+ stdout.write("\x1B[?25l");
741
+ setRegion();
742
+ drawBox();
743
+ stdin.on("data", onData);
744
+ },
745
+ reinit: () => {
746
+ setRegion();
747
+ drawBox();
748
+ },
749
+ destroy: () => {
750
+ stdin.removeListener("data", onData);
751
+ stdout.removeListener("resize", onResize);
752
+ if (resizeTimer) clearTimeout(resizeTimer);
753
+ stdin.setRawMode(wasRaw);
754
+ stdin.pause();
755
+ stdout.write("\x1B[r");
756
+ stdout.write("\x1B[?25h");
757
+ stdout.write(`\x1B[${rows()};1H
758
+ `);
759
+ }
760
+ };
761
+ }
762
+
763
+ export {
764
+ colors,
765
+ buildLogoSettle,
766
+ logoDecodeLines,
767
+ LOGO_LINE_COUNT,
768
+ bannerLines,
769
+ banner,
770
+ bannerDecode,
771
+ setOutputSink,
772
+ info,
773
+ ok,
774
+ goodbye,
775
+ error,
776
+ write,
777
+ newline,
778
+ promptExtraContext,
779
+ GUTTER,
780
+ userPromptLabel,
781
+ renderUserBubble,
782
+ assistantHeader,
783
+ turnSeparator,
784
+ pickThinkingPhrase,
785
+ randomGlitchChar,
786
+ decodeFrame,
787
+ formatTokens,
788
+ startThinking,
789
+ prompt,
790
+ promptHidden,
791
+ pick,
792
+ visibleLength,
793
+ wrapAnsi,
794
+ tokenLabel,
795
+ buildInputRule,
796
+ promptBoxed,
797
+ closeInput,
798
+ startPinnedChat
799
+ };