@jun133/kitty 0.0.15 → 0.0.16

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.
@@ -16,8 +16,123 @@ var TUI_COLORS = {
16
16
  error: "#f87171"
17
17
  };
18
18
 
19
- // src/shell/tui/transcriptLayout.ts
20
- import stringWidth2 from "string-width";
19
+ // src/shell/tui/transcriptFrame.ts
20
+ import stringWidth from "string-width";
21
+ var TRANSCRIPT_OUTER_PADDING_X = 3;
22
+ var MIN_BODY_WIDTH = 8;
23
+ function readTranscriptRoleFrame(role, viewportWidth) {
24
+ const frameWidth = Math.max(1, viewportWidth - TRANSCRIPT_OUTER_PADDING_X * 2);
25
+ const base = readRoleFrameBase(role);
26
+ const bodyWidth = Math.max(
27
+ MIN_BODY_WIDTH,
28
+ frameWidth - base.marginLeft - base.paddingLeft - base.paddingRight - stringWidth(base.gutter) - base.gap
29
+ );
30
+ return {
31
+ ...base,
32
+ bodyWidth
33
+ };
34
+ }
35
+ function readTranscriptRoleStyle(role, theme) {
36
+ switch (role) {
37
+ case "user":
38
+ return {
39
+ accent: theme.user,
40
+ background: theme.panelStrong,
41
+ text: theme.text,
42
+ bold: true,
43
+ dim: false,
44
+ italicPrefix: false
45
+ };
46
+ case "reasoning":
47
+ return {
48
+ accent: theme.border,
49
+ background: void 0,
50
+ text: theme.reasoning,
51
+ bold: false,
52
+ dim: true,
53
+ italicPrefix: true
54
+ };
55
+ case "system":
56
+ return {
57
+ accent: theme.border,
58
+ background: theme.panel,
59
+ text: theme.system,
60
+ bold: false,
61
+ dim: false,
62
+ italicPrefix: false
63
+ };
64
+ case "assistant":
65
+ return {
66
+ accent: theme.background,
67
+ background: void 0,
68
+ text: theme.assistant,
69
+ bold: false,
70
+ dim: false,
71
+ italicPrefix: false
72
+ };
73
+ }
74
+ }
75
+ function applyTranscriptMarkdownStyle(base, kind, theme) {
76
+ switch (kind) {
77
+ case "heading":
78
+ return {
79
+ ...base,
80
+ text: theme.user,
81
+ bold: true
82
+ };
83
+ case "code":
84
+ return {
85
+ ...base,
86
+ background: theme.panel,
87
+ text: theme.system
88
+ };
89
+ case "quote":
90
+ return {
91
+ ...base,
92
+ text: theme.reasoning,
93
+ dim: true
94
+ };
95
+ case "rule":
96
+ case "table":
97
+ return {
98
+ ...base,
99
+ text: theme.muted
100
+ };
101
+ case "list":
102
+ case "text":
103
+ case void 0:
104
+ return base;
105
+ }
106
+ }
107
+ function readRoleFrameBase(role) {
108
+ switch (role) {
109
+ case "user":
110
+ case "reasoning":
111
+ return {
112
+ gap: 2,
113
+ gutter: "\u2503",
114
+ marginLeft: 1,
115
+ paddingLeft: 1,
116
+ paddingRight: 1
117
+ };
118
+ case "system":
119
+ return {
120
+ gap: 2,
121
+ gutter: "\u2502",
122
+ marginLeft: 2,
123
+ paddingLeft: 1,
124
+ paddingRight: 1
125
+ };
126
+ case "assistant":
127
+ return {
128
+ gap: 2,
129
+ gutter: " ",
130
+ marginLeft: 2,
131
+ paddingLeft: 1,
132
+ paddingRight: 1
133
+ };
134
+ }
135
+ }
21
136
 
22
137
  // src/shell/tui/markdown.ts
23
138
  import { marked } from "marked";
@@ -115,13 +230,13 @@ function decodeHtmlEntities(text) {
115
230
  }
116
231
 
117
232
  // src/shell/tui/markdownTable.ts
118
- import stringWidth from "string-width";
233
+ import stringWidth2 from "string-width";
119
234
  function renderMarkdownTableLines(header, rows) {
120
235
  const headerTexts = header.map(readCellText);
121
236
  const rowTexts = rows.map((row) => row.map(readCellText));
122
237
  const widths = headerTexts.map((cell, index) => Math.max(
123
- stringWidth(cell),
124
- ...rowTexts.map((row) => stringWidth(row[index] ?? ""))
238
+ stringWidth2(cell),
239
+ ...rowTexts.map((row) => stringWidth2(row[index] ?? ""))
125
240
  ));
126
241
  return [
127
242
  tableLine(joinTableRow(headerTexts, widths)),
@@ -140,10 +255,10 @@ function tableLine(text) {
140
255
  };
141
256
  }
142
257
  function joinTableRow(cells, widths) {
143
- return cells.map((cell, index) => padDisplayEnd(cell, widths[index] ?? stringWidth(cell))).join(" \u2502 ");
258
+ return cells.map((cell, index) => padDisplayEnd(cell, widths[index] ?? stringWidth2(cell))).join(" \u2502 ");
144
259
  }
145
260
  function padDisplayEnd(text, width) {
146
- return `${text}${" ".repeat(Math.max(0, width - stringWidth(text)))}`;
261
+ return `${text}${" ".repeat(Math.max(0, width - stringWidth2(text)))}`;
147
262
  }
148
263
 
149
264
  // src/shell/tui/markdown.ts
@@ -328,165 +443,15 @@ function spansText(spans) {
328
443
  return spans.map((span) => span.text).join("");
329
444
  }
330
445
 
331
- // src/shell/tui/transcriptLayout.ts
332
- var TRANSCRIPT_OUTER_PADDING_X = 3;
333
- var MIN_BODY_WIDTH = 8;
446
+ // src/shell/tui/transcriptWrap.ts
447
+ import stringWidth3 from "string-width";
334
448
  var REASONING_PREFIX = "Thinking: ";
335
- function renderTranscriptLineViews(entries, viewportWidth, theme) {
336
- return entries.flatMap((entry) => renderTranscriptEntryLineViews(entry, viewportWidth, theme));
337
- }
338
- function measureTranscriptRows(entries, viewportWidth, theme) {
339
- return renderTranscriptLineViews(entries, viewportWidth, theme).length;
340
- }
341
- function renderTranscriptEntryLineViews(entry, viewportWidth, theme) {
342
- const frame = readRoleFrame(entry.role, viewportWidth);
343
- const style = readRoleStyle(entry.role, theme);
344
- const sourceRows = readEntryDisplayRows(entry);
345
- const contentRows = wrapEntryRows(entry, sourceRows, frame.bodyWidth);
346
- const rows = contentRows.length > 0 ? contentRows : [{ markdownKind: void 0, language: void 0, prefix: "", text: "", spans: [] }];
347
- const entryId = entry.id;
348
- return [
349
- {
350
- id: `${entryId}-spacer`,
351
- entryId,
352
- role: entry.role,
353
- kind: "spacer",
354
- text: "",
355
- spans: [],
356
- prefix: "",
357
- markdownKind: void 0,
358
- language: void 0,
359
- isFirstContentLine: false,
360
- frame,
361
- style
362
- },
363
- ...rows.map((row, index) => ({
364
- id: `${entryId}-line-${index + 1}`,
365
- entryId,
366
- role: entry.role,
367
- kind: "content",
368
- text: row.text,
369
- spans: row.spans,
370
- prefix: row.prefix,
371
- markdownKind: row.markdownKind,
372
- language: row.language,
373
- isFirstContentLine: index === 0,
374
- frame,
375
- style: applyMarkdownStyle(style, row.markdownKind, theme)
376
- }))
377
- ];
378
- }
379
- function readRoleFrame(role, viewportWidth) {
380
- const frameWidth = Math.max(1, viewportWidth - TRANSCRIPT_OUTER_PADDING_X * 2);
381
- const base = readRoleFrameBase(role);
382
- const bodyWidth = Math.max(
383
- MIN_BODY_WIDTH,
384
- frameWidth - base.marginLeft - base.paddingLeft - base.paddingRight - stringWidth2(base.gutter) - base.gap
385
- );
386
- return {
387
- ...base,
388
- bodyWidth
389
- };
390
- }
391
- function readRoleFrameBase(role) {
392
- switch (role) {
393
- case "user":
394
- return {
395
- gap: 2,
396
- gutter: "\u2503",
397
- marginLeft: 1,
398
- paddingLeft: 1,
399
- paddingRight: 1
400
- };
401
- case "reasoning":
402
- return {
403
- gap: 2,
404
- gutter: "\u2503",
405
- marginLeft: 1,
406
- paddingLeft: 1,
407
- paddingRight: 1
408
- };
409
- case "system":
410
- return {
411
- gap: 2,
412
- gutter: "\u2502",
413
- marginLeft: 2,
414
- paddingLeft: 1,
415
- paddingRight: 1
416
- };
417
- case "assistant":
418
- return {
419
- gap: 2,
420
- gutter: " ",
421
- marginLeft: 2,
422
- paddingLeft: 1,
423
- paddingRight: 1
424
- };
425
- }
426
- }
427
- function readRoleStyle(role, theme) {
428
- switch (role) {
429
- case "user":
430
- return {
431
- accent: theme.user,
432
- background: theme.panelStrong,
433
- text: theme.text,
434
- bold: true,
435
- dim: false,
436
- italicPrefix: false
437
- };
438
- case "reasoning":
439
- return {
440
- accent: theme.border,
441
- background: void 0,
442
- text: theme.reasoning,
443
- bold: false,
444
- dim: true,
445
- italicPrefix: true
446
- };
447
- case "system":
448
- return {
449
- accent: theme.border,
450
- background: theme.panel,
451
- text: theme.system,
452
- bold: false,
453
- dim: false,
454
- italicPrefix: false
455
- };
456
- case "assistant":
457
- return {
458
- accent: theme.background,
459
- background: void 0,
460
- text: theme.assistant,
461
- bold: false,
462
- dim: false,
463
- italicPrefix: false
464
- };
465
- }
466
- }
467
- function readEntryDisplayRows(entry) {
468
- if (entry.role === "assistant" || entry.role === "reasoning") {
469
- const markdownRows = renderMarkdownLines(entry.text);
470
- return markdownRows.length > 0 ? markdownRows.map((row) => ({
471
- markdownKind: row.kind,
472
- text: row.text,
473
- spans: row.spans,
474
- language: row.language
475
- })) : [{ markdownKind: void 0, text: "", spans: [], language: void 0 }];
476
- }
477
- return entry.text.split(/\r?\n/).map((text) => ({
478
- markdownKind: void 0,
479
- text,
480
- spans: [{ text }],
481
- language: void 0
482
- }));
483
- }
484
- function wrapEntryRows(entry, sourceRows, bodyWidth) {
449
+ function wrapTranscriptEntryRows(entry, sourceRows, bodyWidth) {
485
450
  if (entry.role !== "reasoning") {
486
451
  return sourceRows.flatMap((line2) => wrapSourceRow(line2, bodyWidth, ""));
487
452
  }
488
453
  const rows = [];
489
- const firstBodyWidth = Math.max(1, bodyWidth - stringWidth2(REASONING_PREFIX));
454
+ const firstBodyWidth = Math.max(1, bodyWidth - stringWidth3(REASONING_PREFIX));
490
455
  sourceRows.forEach((line2, sourceIndex) => {
491
456
  const width = sourceIndex === 0 ? firstBodyWidth : bodyWidth;
492
457
  const prefix = sourceIndex === 0 ? REASONING_PREFIX : "";
@@ -525,7 +490,7 @@ function appendWrappedSpan(rows, cursorWidth, span, text, width) {
525
490
  }
526
491
  let nextCursor = cursorWidth;
527
492
  for (const segment of splitWrapSegments(text)) {
528
- const segmentWidth = stringWidth2(segment);
493
+ const segmentWidth = stringWidth3(segment);
529
494
  const isBlank = segment.trim() === "";
530
495
  if (!isBlank && nextCursor > 0 && nextCursor + segmentWidth > width) {
531
496
  rows.push([]);
@@ -538,7 +503,7 @@ function appendWrappedSpan(rows, cursorWidth, span, text, width) {
538
503
  nextCursor = 0;
539
504
  }
540
505
  pushTranscriptSpan(rows[rows.length - 1], toTranscriptSpan(span, chunk.text));
541
- nextCursor += stringWidth2(chunk.text);
506
+ nextCursor += stringWidth3(chunk.text);
542
507
  }
543
508
  }
544
509
  return nextCursor;
@@ -551,7 +516,7 @@ function splitSegmentByWidth(segment, width, cursorWidth) {
551
516
  let current = "";
552
517
  let currentWidth = cursorWidth;
553
518
  for (const char of Array.from(segment)) {
554
- const charWidth = stringWidth2(char);
519
+ const charWidth = stringWidth3(char);
555
520
  if (current && currentWidth + charWidth > width) {
556
521
  rows.push({ text: current, newRow: rows.length > 0 || cursorWidth > 0 });
557
522
  current = "";
@@ -597,42 +562,73 @@ function sameTranscriptSpanStyle(left, right) {
597
562
  function transcriptSpansText(spans) {
598
563
  return spans.map((span) => span.text).join("");
599
564
  }
600
- function applyMarkdownStyle(base, kind, theme) {
601
- switch (kind) {
602
- case "heading":
603
- return {
604
- ...base,
605
- text: theme.user,
606
- bold: true
607
- };
608
- case "code":
609
- return {
610
- ...base,
611
- background: theme.panel,
612
- text: theme.system
613
- };
614
- case "quote":
615
- return {
616
- ...base,
617
- text: theme.reasoning,
618
- dim: true
619
- };
620
- case "rule":
621
- case "table":
622
- return {
623
- ...base,
624
- text: theme.muted
625
- };
626
- case "list":
627
- case "text":
628
- case void 0:
629
- return base;
565
+
566
+ // src/shell/tui/transcriptLayout.ts
567
+ function renderTranscriptLineViews(entries, viewportWidth, theme) {
568
+ return entries.flatMap((entry) => renderTranscriptEntryLineViews(entry, viewportWidth, theme));
569
+ }
570
+ function measureTranscriptRows(entries, viewportWidth, theme) {
571
+ return renderTranscriptLineViews(entries, viewportWidth, theme).length;
572
+ }
573
+ function renderTranscriptEntryLineViews(entry, viewportWidth, theme) {
574
+ const frame = readTranscriptRoleFrame(entry.role, viewportWidth);
575
+ const style = readTranscriptRoleStyle(entry.role, theme);
576
+ const sourceRows = readEntryDisplayRows(entry);
577
+ const contentRows = wrapTranscriptEntryRows(entry, sourceRows, frame.bodyWidth);
578
+ const rows = contentRows.length > 0 ? contentRows : [{ markdownKind: void 0, language: void 0, prefix: "", text: "", spans: [] }];
579
+ const entryId = entry.id;
580
+ return [
581
+ {
582
+ id: `${entryId}-spacer`,
583
+ entryId,
584
+ role: entry.role,
585
+ kind: "spacer",
586
+ text: "",
587
+ spans: [],
588
+ prefix: "",
589
+ markdownKind: void 0,
590
+ language: void 0,
591
+ isFirstContentLine: false,
592
+ frame,
593
+ style
594
+ },
595
+ ...rows.map((row, index) => ({
596
+ id: `${entryId}-line-${index + 1}`,
597
+ entryId,
598
+ role: entry.role,
599
+ kind: "content",
600
+ text: row.text,
601
+ spans: row.spans,
602
+ prefix: row.prefix,
603
+ markdownKind: row.markdownKind,
604
+ language: row.language,
605
+ isFirstContentLine: index === 0,
606
+ frame,
607
+ style: applyTranscriptMarkdownStyle(style, row.markdownKind, theme)
608
+ }))
609
+ ];
610
+ }
611
+ function readEntryDisplayRows(entry) {
612
+ if (entry.role === "assistant" || entry.role === "reasoning") {
613
+ const markdownRows = renderMarkdownLines(entry.text);
614
+ return markdownRows.length > 0 ? markdownRows.map((row) => ({
615
+ markdownKind: row.kind,
616
+ text: row.text,
617
+ spans: row.spans,
618
+ language: row.language
619
+ })) : [{ markdownKind: void 0, text: "", spans: [], language: void 0 }];
630
620
  }
621
+ return entry.text.split(/\r?\n/).map((text) => ({
622
+ markdownKind: void 0,
623
+ text,
624
+ spans: [{ text }],
625
+ language: void 0
626
+ }));
631
627
  }
632
628
 
633
629
  // src/shell/tui/store.ts
634
630
  var DEFAULT_DOCK = {
635
- context: "0 chars (0%)"
631
+ context: "0%"
636
632
  };
637
633
  function createInitialTuiState(session) {
638
634
  return {
@@ -746,7 +742,7 @@ function renderTranscriptLineViews2(entries, width) {
746
742
  function formatContextBudget(session) {
747
743
  const budget = session?.contextBudget;
748
744
  if (!budget) {
749
- return "0 chars (0%)";
745
+ return "0%";
750
746
  }
751
747
  const percent = Math.round(budget.usageRatio * 100);
752
748
  return `${budget.estimatedChars}/${budget.limitChars} chars (${percent}%)`;