Skip to content

Commit 53796a2

Browse files
committed
feat(cli): add GFM support with strikethrough, task lists, and tables
- Add remark-gfm and remark-breaks dependencies - Add tests for strikethrough, task lists, and table rendering - Refactor validation error blocks to inline format
1 parent edbf84c commit 53796a2

File tree

4 files changed

+106
-18
lines changed

4 files changed

+106
-18
lines changed

bun.lock

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
"string-width": "^7.2.0",
4545
"react": "^19.0.0",
4646
"react-reconciler": "^0.32.0",
47+
"remark-breaks": "^4.0.0",
48+
"remark-gfm": "^4.0.1",
4749
"remark-parse": "^11.0.0",
4850
"unified": "^11.0.0",
4951
"yoga-layout": "^3.2.1",

cli/src/utils/__tests__/markdown-renderer.test.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,61 @@ describe('markdown renderer', () => {
152152
expect(flattenChildren(boldNode!.props.children)).toEqual(['done'])
153153
expect(nodes[nodes.length - 1]).toBe('```js\nconsole.log(')
154154
})
155+
156+
test('renders strikethrough text with GFM', () => {
157+
const output = renderMarkdown('This is ~~deleted~~ text')
158+
const nodes = flattenNodes(output)
159+
160+
expect(nodes[0]).toBe('This is ')
161+
162+
const strikethrough = nodes[1] as React.ReactElement
163+
expect(strikethrough.props.attributes).toBe(TextAttributes.DIM)
164+
expect(flattenChildren(strikethrough.props.children)).toEqual(['deleted'])
165+
166+
expect(nodes[2]).toBe(' text')
167+
})
168+
169+
test('renders task lists with GFM', () => {
170+
const output = renderMarkdown('- [ ] Todo\n- [x] Done')
171+
const nodes = flattenNodes(output)
172+
173+
const checkboxSpans = nodes.filter(
174+
(node): node is React.ReactElement =>
175+
React.isValidElement(node) &&
176+
node.type === 'span' &&
177+
(flattenChildren(node.props.children).join('') === '[ ] ' ||
178+
flattenChildren(node.props.children).join('') === '[x] '),
179+
)
180+
181+
expect(checkboxSpans).toHaveLength(2)
182+
})
183+
184+
test('renders tables with GFM', () => {
185+
const markdown = `| Name | Age |
186+
| ---- | --- |
187+
| John | 30 |
188+
| Jane | 25 |`
189+
const output = renderMarkdown(markdown)
190+
const nodes = flattenNodes(output)
191+
192+
// Check that table structure is rendered (pipes and separators)
193+
const textContent = nodes
194+
.map((node) => {
195+
if (typeof node === 'string') return node
196+
if (React.isValidElement(node)) {
197+
return flattenChildren(node.props.children).join('')
198+
}
199+
return ''
200+
})
201+
.join('')
202+
203+
expect(textContent).toContain('Name')
204+
expect(textContent).toContain('Age')
205+
expect(textContent).toContain('John')
206+
expect(textContent).toContain('Jane')
207+
expect(textContent).toContain('30')
208+
expect(textContent).toContain('25')
209+
expect(textContent).toContain('|')
210+
expect(textContent).toContain('---')
211+
})
155212
})

cli/src/utils/create-validation-error-blocks.tsx

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,32 +59,21 @@ export function createValidationErrorBlocks(
5959
.replace(/\\/g, '/')
6060
const filePath = agentInfo.filePath
6161

62-
// Simple layout: file path first, then agent ID and error
62+
// Layout matching renderRepoPathInfo: agent ID, file path link, error message
6363
blocks.push({
6464
type: 'html',
6565
render: ({ textColor }) => (
6666
<box style={{ flexDirection: 'column', width: '100%' }}>
67-
<box style={{ flexDirection: 'row', gap: 0, width: '100%' }}>
67+
<text wrap={true} style={{ fg: textColor }}>
68+
{agentId} in{' '}
6869
<TerminalLink
6970
text={relativePathFromRoot}
70-
containerStyle={{
71-
width: 'auto',
72-
flexDirection: 'row',
73-
}}
74-
formatLines={(text) => [text]}
75-
underlineOnHover
71+
color="#3b82f6"
72+
inline={true}
7673
onActivate={() => openFileAtPath(filePath)}
7774
/>
78-
<text style={{ fg: textColor }} wrap={false}>
79-
{' '}
80-
{agentId}
81-
</text>
82-
</box>
83-
<box style={{ paddingLeft: 2, width: '100%' }}>
84-
<text style={{ fg: textColor }} wrap>
85-
{errorMsg}
86-
</text>
87-
</box>
75+
, {errorMsg}
76+
</text>
8877
</box>
8978
),
9079
})

0 commit comments

Comments
 (0)