@@ -19,22 +19,55 @@ function getVisibleLength(str: string): number {
1919}
2020
2121function truncateMessage ( msg : string , maxLength ?: number ) : string {
22+ // Non-TTY (CI): no spinner width to honor — skip truncation entirely.
23+ // Character-by-character truncation is O(n²) and hangs deploys on large graphs.
24+ if ( maxLength === undefined && ( ! process . stdout . isTTY || ! process . stdout . columns ) ) {
25+ return msg ;
26+ }
27+
2228 const terminalWidth = maxLength ?? process . stdout . columns ?? 80 ;
2329 const availableWidth = terminalWidth - 5 ; // Reserve some space for the spinner and padding
30+ const targetWidth = availableWidth - 3 ; // room for "..."
2431 const visibleLength = getVisibleLength ( msg ) ;
2532
2633 if ( visibleLength <= availableWidth ) {
2734 return msg ;
2835 }
2936
30- // We need to truncate based on visible characters, but preserve ANSI sequences
31- // Simple approach: truncate character by character until we fit
32- let truncated = msg ;
33- while ( getVisibleLength ( truncated ) > availableWidth - 3 ) {
34- truncated = truncated . slice ( 0 , - 1 ) ;
37+ // Walk once, counting visible characters, and cut at the first overflow.
38+ // Preserve ANSI sequences so colors/links remain valid.
39+ let visible = 0 ;
40+ let i = 0 ;
41+ while ( i < msg . length ) {
42+ // OSC 8 hyperlinks: \u001b]8;;URL\u0007TEXT\u001b]8;;\u0007
43+ if ( msg . startsWith ( "\u001b]8;;" , i ) ) {
44+ const end = msg . indexOf ( "\u0007" , i ) ;
45+ if ( end === - 1 ) {
46+ break ;
47+ }
48+ i = end + 1 ;
49+ continue ;
50+ }
51+ // CSI sequences: \x1b[...X
52+ if ( msg [ i ] === "\x1b" && msg [ i + 1 ] === "[" ) {
53+ i += 2 ;
54+ while ( i < msg . length && ! / [ a - z A - Z ] / . test ( msg [ i ] ! ) ) {
55+ i ++ ;
56+ }
57+ if ( i < msg . length ) {
58+ i ++ ;
59+ }
60+ continue ;
61+ }
62+
63+ if ( visible >= targetWidth ) {
64+ return msg . slice ( 0 , i ) + "..." ;
65+ }
66+ visible ++ ;
67+ i ++ ;
3568 }
3669
37- return truncated + "..." ;
70+ return msg . slice ( 0 , i ) + "..." ;
3871}
3972
4073const wrappedClackSpinner = ( ) => {
0 commit comments