@@ -53,6 +53,19 @@ function formatDuration(ms: number, nowLabel: string): string {
5353 return hours > 0 ? `${ hours } h ${ minutes } m` : `${ minutes } m` ;
5454}
5555
56+ // Compact tag for the quota window length shown next to the reset countdown,
57+ // e.g. a 5-hour rolling window ⇒ "5h", a daily window ⇒ "1d", weekly ⇒ "1w".
58+ function formatWindow ( ms : number ) : string {
59+ const WEEK = 7 * 24 * 3600000 ;
60+ const DAY = 24 * 3600000 ;
61+ const HOUR = 3600000 ;
62+ if ( ms <= 0 ) return '' ;
63+ if ( ms % WEEK === 0 ) return `${ ms / WEEK } w` ;
64+ if ( ms % DAY === 0 ) return `${ ms / DAY } d` ;
65+ if ( ms >= HOUR ) return `${ Math . round ( ms / HOUR ) } h` ;
66+ return `${ Math . max ( 1 , Math . round ( ms / 60000 ) ) } m` ;
67+ }
68+
5669function formatDate ( epochMs : number ) : string {
5770 return new Date ( epochMs ) . toISOString ( ) . slice ( 0 , 10 ) ;
5871}
@@ -173,8 +186,15 @@ function renderUnavailableMetric(label: string, unavailableLabel: string, color:
173186 return `${ label } [${ '.' . repeat ( COMPACT_BAR_WIDTH ) } ] ${ unavailableLabel } ` ;
174187}
175188
176- function boxLine ( w : number , l : string , f : string , r : string , c : boolean ) : string {
177- return c ? `${ D } ${ l } ${ f . repeat ( w ) } ${ r } ${ R } ` : `+${ '-' . repeat ( w ) } +` ;
189+ // `div` is a 1-based offset (in display cells) of an optional column divider,
190+ // so the reset column can be boxed off: ├────┬────┤ / ├────┼────┤ / ╰────┴────╯.
191+ function boxLine ( w : number , l : string , f : string , r : string , c : boolean , div ?: number , divChar ?: string ) : string {
192+ if ( div === undefined || divChar === undefined ) {
193+ return c ? `${ D } ${ l } ${ f . repeat ( w ) } ${ r } ${ R } ` : `+${ '-' . repeat ( w ) } +` ;
194+ }
195+ return c
196+ ? `${ D } ${ l } ${ f . repeat ( div - 1 ) } ${ divChar } ${ f . repeat ( w - div ) } ${ r } ${ R } `
197+ : `+${ '-' . repeat ( div - 1 ) } +${ '-' . repeat ( w - div ) } +` ;
178198}
179199
180200function boxRow ( content : string , innerW : number , visLen : number , color : boolean ) : string {
@@ -210,17 +230,29 @@ export function renderQuotaTable(models: QuotaModelRemain[], config: Config): vo
210230 isUnweekly ( m . current_weekly_status ) ,
211231 config . region === 'cn' ? UNLIMITED_LABEL_CN : UNLIMITED_LABEL_EN ,
212232 ) ;
213- const reset = unavailable
214- ? `${ L . resetsIn } —`
215- : `${ L . resetsIn } ${ formatDuration ( m . remains_time , L . now ) } ` ;
233+ // The reset countdown lives in its own boxed column; the dim window tag
234+ // ("5h", "1w", …) tells which quota window the countdown applies to.
235+ const windowTag = unavailable ? '' : formatWindow ( m . end_time - m . start_time ) ;
236+ const resetLabel = windowTag ? `${ windowTag } ${ L . resetsIn } ` : L . resetsIn ;
237+ const resetValue = unavailable ? '—' : formatDuration ( m . remains_time , L . now ) ;
238+ const reset = useColor ? `${ D } ${ resetLabel } ${ R } ${ resetValue } ` : `${ resetLabel } ${ resetValue } ` ;
216239 return { displayName, current, weekly, reset } ;
217240 } ) ;
218241
219242 const nameWidth = Math . max ( 6 , ...rows . map ( r => displayWidth ( r . displayName ) ) ) ;
220243 const currentWidth = Math . max ( ...rows . map ( r => displayWidth ( r . current ) ) , 18 ) ;
221244 const weeklyWidth = Math . max ( ...rows . map ( r => displayWidth ( r . weekly ) ) , 18 ) ;
222245 const resetWidth = Math . max ( ...rows . map ( r => displayWidth ( r . reset ) ) , 10 ) ;
223- const W = Math . max ( 72 , nameWidth + 2 + currentWidth + 2 + weeklyWidth + 2 + resetWidth + 4 ) ;
246+ // Left section holds name + current + weekly; the reset column sits to the
247+ // right of the divider. Keep the historical 72-cell minimum by widening the
248+ // left section when the natural width falls short.
249+ let leftWidth = nameWidth + 2 + currentWidth + 2 + weeklyWidth ;
250+ let W = leftWidth + 3 + resetWidth + 2 ;
251+ if ( W < 72 ) {
252+ leftWidth += 72 - W ;
253+ W = 72 ;
254+ }
255+ const divOffset = leftWidth + 3 ;
224256
225257 const weekRange = models . length > 0
226258 ? `${ formatDate ( models [ 0 ] ! . weekly_start_time ) } — ${ formatDate ( models [ 0 ] ! . weekly_end_time ) } `
@@ -244,17 +276,18 @@ export function renderQuotaTable(models: QuotaModelRemain[], config: Config): vo
244276 return ;
245277 }
246278
247- for ( const row of rows ) {
248- console . log ( boxLine ( W , '├' , '─' , '┤' , useColor ) ) ;
279+ rows . forEach ( ( row , i ) => {
280+ console . log ( boxLine ( W , '├' , '─' , '┤' , useColor , divOffset , i === 0 ? '┬' : '┼' ) ) ;
249281
250282 const name = useColor ? `${ B } ${ row . displayName } ${ R } ` : row . displayName ;
251- const line = `${ name } ${ ' ' . repeat ( Math . max ( 1 , nameWidth - displayWidth ( row . displayName ) + 2 ) ) } ` +
283+ const left = `${ name } ${ ' ' . repeat ( Math . max ( 1 , nameWidth - displayWidth ( row . displayName ) + 2 ) ) } ` +
252284 `${ row . current } ${ ' ' . repeat ( Math . max ( 1 , currentWidth - displayWidth ( row . current ) + 2 ) ) } ` +
253- `${ row . weekly } ${ ' ' . repeat ( Math . max ( 1 , weeklyWidth - displayWidth ( row . weekly ) + 2 ) ) } ` +
254- row . reset ;
285+ row . weekly ;
286+ const divider = useColor ? `${ D } │${ R } ` : '|' ;
287+ const line = `${ left } ${ ' ' . repeat ( Math . max ( 0 , leftWidth - displayWidth ( left ) ) ) } ${ divider } ${ row . reset } ` ;
255288 console . log ( boxRow ( line , W , displayWidth ( line ) , useColor ) ) ;
256- }
289+ } ) ;
257290
258- console . log ( boxLine ( W , '╰' , '─' , '╯' , useColor ) ) ;
291+ console . log ( boxLine ( W , '╰' , '─' , '╯' , useColor , divOffset , '┴' ) ) ;
259292 console . log ( '' ) ;
260293}
0 commit comments