Skip to content

Commit 185c618

Browse files
committed
feat(tui): add numbered list support to log line formatting
Add support for numbered list prefixes (e.g., "1. ", "2. ") in log line formatting to improve structured output readability. Also ensure proper newline formatting for reasoning items in Codex execution stream.
1 parent ed4b52d commit 185c618

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

src/cli/tui/routes/workflow/components/shared/log-line.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* - Colors: gray, green, red, orange, cyan, magenta, blue, yellow
77
* - Attributes: bold, dim, italic, underline, inverse, strikethrough
88
* - Combined markers: [GREEN:BOLD], [RED:UNDERLINE,BOLD], etc.
9-
* - Line prefix formatting: * for bold highlight, - for bullet points
9+
* - Line prefix formatting: * for bold highlight, - for bullet points, 1. 2. for numbered lists
1010
* - Markdown headings: # (cyan+bold), ## (bold), ### (bold+dim)
1111
*
1212
* Uses the enhanced parseMarker system for professional CLI output.
@@ -21,9 +21,9 @@ import { parseMarker, type ParsedMarker } from "../../../../../../shared/formatt
2121

2222
/**
2323
* Detect line prefix type for special formatting
24-
* Returns: 'star' for * prefix, 'bullet' for - prefix, null otherwise
24+
* Returns: 'star' for * prefix, 'bullet' for - prefix, 'numbered' for 1. 2. etc, null otherwise
2525
*/
26-
function detectLinePrefix(text: string): { type: 'star' | 'bullet' | null; content: string } {
26+
function detectLinePrefix(text: string): { type: 'star' | 'bullet' | 'numbered' | null; content: string; number?: string } {
2727
const trimmed = text.trimStart()
2828
const indent = text.length - trimmed.length
2929
const indentStr = text.slice(0, indent)
@@ -36,6 +36,11 @@ function detectLinePrefix(text: string): { type: 'star' | 'bullet' | null; conte
3636
if (trimmed.startsWith('- ')) {
3737
return { type: 'bullet', content: indentStr + trimmed.slice(2) }
3838
}
39+
// Check for numbered list prefix (e.g., "1. ", "12. ")
40+
const numberedMatch = trimmed.match(/^(\d+)\.\s+(.*)$/)
41+
if (numberedMatch) {
42+
return { type: 'numbered', content: indentStr + numberedMatch[2], number: numberedMatch[1] }
43+
}
3944
return { type: null, content: text }
4045
}
4146

@@ -238,9 +243,13 @@ export function LogLine(props: LogLineProps) {
238243
const bulletSymbol = () => prefixInfo().type === 'bullet' ? '• ' : ''
239244
const bulletWidth = () => prefixInfo().type === 'bullet' ? 2 : 0
240245

246+
// Get prefix for numbered lists (e.g., "1. ", "12. ")
247+
const numberedSymbol = () => prefixInfo().type === 'numbered' ? `${prefixInfo().number}. ` : ''
248+
const numberedWidth = () => prefixInfo().type === 'numbered' ? numberedSymbol().length : 0
249+
241250
// Word-wrapped lines (wrap the raw text, then parse segments per line)
242251
const wrappedLines = createMemo(() => {
243-
const width = maxWidth() - bulletWidth()
252+
const width = maxWidth() - bulletWidth() - numberedWidth()
244253
return wordWrap(displayText(), width)
245254
})
246255

@@ -264,6 +273,12 @@ export function LogLine(props: LogLineProps) {
264273
<Show when={prefixInfo().type === 'bullet' && index() > 0}>
265274
<text> </text>
266275
</Show>
276+
<Show when={prefixInfo().type === 'numbered' && index() === 0}>
277+
<text fg={themeCtx.theme.textMuted}>{numberedSymbol()}</text>
278+
</Show>
279+
<Show when={prefixInfo().type === 'numbered' && index() > 0}>
280+
<text>{' '.repeat(numberedWidth())}</text>
281+
</Show>
267282
<For each={lineSegments}>
268283
{(segment) => (
269284
<text
@@ -347,11 +362,17 @@ export function LogLineInline(props: { line: string }) {
347362
// Get prefix symbol for bullet points
348363
const bulletSymbol = () => prefixInfo().type === 'bullet' ? '• ' : ''
349364

365+
// Get prefix for numbered lists
366+
const numberedSymbol = () => prefixInfo().type === 'numbered' ? `${prefixInfo().number}. ` : ''
367+
350368
return (
351369
<box flexDirection="row">
352370
<Show when={prefixInfo().type === 'bullet'}>
353371
<text fg={themeCtx.theme.textMuted}>{bulletSymbol()}</text>
354372
</Show>
373+
<Show when={prefixInfo().type === 'numbered'}>
374+
<text fg={themeCtx.theme.textMuted}>{numberedSymbol()}</text>
375+
</Show>
355376
<For each={segments()}>
356377
{(segment) => (
357378
<text

src/infra/engines/providers/codex/execution/runner.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function formatCodexStreamJsonLine(line: string): string | null {
115115

116116
// Handle reasoning items (thinking)
117117
if (json.type === 'item.completed' && json.item?.type === 'reasoning') {
118-
return formatThinking(json.item.text);
118+
return formatThinking(json.item.text) + '\n';
119119
}
120120

121121
// Handle command execution

0 commit comments

Comments
 (0)