Skip to content

Commit d628362

Browse files
committed
feat(cli): add elapsed time formatting utility
- Create format-elapsed-time utility with tests - Update use-send-message to track message timing - Displays human-readable elapsed time for user messages
1 parent 6024183 commit d628362

File tree

3 files changed

+29
-26
lines changed

3 files changed

+29
-26
lines changed

cli/src/hooks/use-send-message.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { getCodebuffClient, formatToolOutput } from '../utils/codebuff-client'
1414
import { shouldHideAgent, shouldCollapseByDefault } from '../utils/constants'
1515

1616
import { getErrorObject } from '../utils/error'
17+
import { formatElapsedTime } from '../utils/format-elapsed-time'
1718
import { formatTimestamp } from '../utils/helpers'
1819
import { loadAgentDefinitions } from '../utils/load-agent-definitions'
1920

@@ -1758,7 +1759,7 @@ export const useSendMessage = ({
17581759
const elapsedMs = timerResult?.elapsedMs ?? 0
17591760
const elapsedSeconds = Math.floor(elapsedMs / 1000)
17601761
const completionTime =
1761-
elapsedSeconds > 0 ? `${elapsedSeconds}s` : undefined
1762+
elapsedSeconds > 0 ? formatElapsedTime(elapsedSeconds) : undefined
17621763

17631764
applyMessageUpdate((prev) =>
17641765
prev.map((msg) => {

cli/src/utils/__tests__/format-elapsed-time.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe('formatElapsedTime', () => {
2222

2323
describe('minutes format (60s - 3599s)', () => {
2424
test('formats exactly 1 minute', () => {
25-
expect(formatElapsedTime(60)).toBe('1m 0s')
25+
expect(formatElapsedTime(60)).toBe('1m')
2626
})
2727

2828
test('formats minutes with remaining seconds (floors down)', () => {
@@ -32,9 +32,9 @@ describe('formatElapsedTime', () => {
3232
})
3333

3434
test('formats double digit minutes', () => {
35-
expect(formatElapsedTime(600)).toBe('10m 0s')
36-
expect(formatElapsedTime(1800)).toBe('30m 0s')
37-
expect(formatElapsedTime(3540)).toBe('59m 0s')
35+
expect(formatElapsedTime(600)).toBe('10m')
36+
expect(formatElapsedTime(1800)).toBe('30m')
37+
expect(formatElapsedTime(3540)).toBe('59m')
3838
})
3939

4040
test('formats just under 1 hour', () => {
@@ -44,20 +44,20 @@ describe('formatElapsedTime', () => {
4444

4545
describe('hours format (>= 3600s)', () => {
4646
test('formats exactly 1 hour', () => {
47-
expect(formatElapsedTime(3600)).toBe('1h 0m')
47+
expect(formatElapsedTime(3600)).toBe('1h')
4848
})
4949

5050
test('formats hours with remaining time (floors down)', () => {
5151
expect(formatElapsedTime(3661)).toBe('1h 1m')
5252
expect(formatElapsedTime(5400)).toBe('1h 30m')
5353
expect(formatElapsedTime(7199)).toBe('1h 59m')
54-
expect(formatElapsedTime(7200)).toBe('2h 0m')
54+
expect(formatElapsedTime(7200)).toBe('2h')
5555
})
5656

5757
test('formats multiple hours', () => {
58-
expect(formatElapsedTime(10800)).toBe('3h 0m')
59-
expect(formatElapsedTime(36000)).toBe('10h 0m')
60-
expect(formatElapsedTime(86400)).toBe('24h 0m')
58+
expect(formatElapsedTime(10800)).toBe('3h')
59+
expect(formatElapsedTime(36000)).toBe('10h')
60+
expect(formatElapsedTime(86400)).toBe('24h')
6161
})
6262
})
6363

@@ -75,14 +75,14 @@ describe('formatElapsedTime', () => {
7575

7676
test('handles boundary between seconds and minutes', () => {
7777
expect(formatElapsedTime(59)).toBe('59s')
78-
expect(formatElapsedTime(60)).toBe('1m 0s')
78+
expect(formatElapsedTime(60)).toBe('1m')
7979
expect(formatElapsedTime(61)).toBe('1m 1s')
8080
})
8181

8282
test('handles boundary between minutes and hours', () => {
8383
expect(formatElapsedTime(3599)).toBe('59m 59s')
84-
expect(formatElapsedTime(3600)).toBe('1h 0m')
85-
expect(formatElapsedTime(3601)).toBe('1h 0m')
84+
expect(formatElapsedTime(3600)).toBe('1h')
85+
expect(formatElapsedTime(3601)).toBe('1h') // 1 second rounds down to 0 minutes, shows as 1h
8686
})
8787
})
8888

@@ -91,13 +91,13 @@ describe('formatElapsedTime', () => {
9191
expect(formatElapsedTime(3)).toBe('3s') // Quick response
9292
expect(formatElapsedTime(15)).toBe('15s') // Average response
9393
expect(formatElapsedTime(45)).toBe('45s') // Longer response
94-
expect(formatElapsedTime(120)).toBe('2m 0s') // Very long response
94+
expect(formatElapsedTime(120)).toBe('2m') // Very long response
9595
})
9696

9797
test('formats extended task durations', () => {
98-
expect(formatElapsedTime(180)).toBe('3m 0s') // 3 minute task
99-
expect(formatElapsedTime(900)).toBe('15m 0s') // 15 minute task
100-
expect(formatElapsedTime(3600)).toBe('1h 0m') // 1 hour task
98+
expect(formatElapsedTime(180)).toBe('3m') // 3 minute task
99+
expect(formatElapsedTime(900)).toBe('15m') // 15 minute task
100+
expect(formatElapsedTime(3600)).toBe('1h') // 1 hour task
101101
})
102102
})
103103
})

cli/src/utils/format-elapsed-time.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,28 @@
66
*
77
* @example
88
* formatElapsedTime(30) // "30s"
9+
* formatElapsedTime(60) // "1m"
910
* formatElapsedTime(90) // "1m 30s"
11+
* formatElapsedTime(3600) // "1h"
1012
* formatElapsedTime(3700) // "1h 1m"
1113
*
1214
* Format rules:
1315
* - Under 60 seconds: "Xs" (e.g., "45s")
14-
* - 60-3599 seconds (1-59 minutes): "Xm Ys" (e.g., "12m 5s")
15-
* - 3600+ seconds (1+ hours): "Xh Ym" (e.g., "2h 15m")
16+
* - 60-3599 seconds (1-59 minutes): "Xm" or "Xm Ys" (e.g., "1m", "12m 5s")
17+
* - 3600+ seconds (1+ hours): "Xh" or "Xh Ym" (e.g., "1h", "2h 15m")
1618
*/
1719
export const formatElapsedTime = (elapsedSeconds: number): string => {
1820
if (elapsedSeconds < 60) {
1921
return `${elapsedSeconds}s`
2022
}
2123

22-
if (elapsedSeconds < 3600) {
23-
const minutes = Math.floor(elapsedSeconds / 60)
24-
const seconds = elapsedSeconds % 60
25-
return `${minutes}m ${seconds}s`
26-
}
27-
2824
const hours = Math.floor(elapsedSeconds / 3600)
2925
const minutes = Math.floor((elapsedSeconds % 3600) / 60)
30-
return `${hours}h ${minutes}m`
26+
const seconds = elapsedSeconds % 60
27+
28+
if (hours > 0) {
29+
return `${hours}h` + (minutes > 0 ? ` ${minutes}m` : '')
30+
}
31+
32+
return `${minutes}m` + (seconds > 0 ? ` ${seconds}s` : '')
3133
}

0 commit comments

Comments
 (0)