Skip to content

Commit bdc3b31

Browse files
committed
feat: add support for h1 sections in AGENTS.md parsing
1 parent e11db40 commit bdc3b31

3 files changed

Lines changed: 51 additions & 9 deletions

File tree

src/index.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -489,24 +489,30 @@ function readAgentsFile(filePath: string): string | null {
489489
*/
490490
function parseAgentsContent(
491491
content: string,
492-
): Record<string, { title: string; content: string }> {
493-
const sections: Record<string, { title: string; content: string }> = {};
492+
): Record<string, { title: string; content: string; level: number }> {
493+
const sections: Record<
494+
string,
495+
{ title: string; content: string; level: number }
496+
> = {};
494497
const lines = content.split('\n');
495498
let currentKey = '';
496499
let currentTitle = '';
500+
let currentLevel = 0;
497501
let currentContent: string[] = [];
498502

499503
for (const line of lines) {
500-
const sectionMatch = line.match(/^##\s+(.+)$/);
504+
const sectionMatch = line.match(/^(#{1,2})\s+(.+)$/);
501505
if (sectionMatch) {
502506
if (currentKey) {
503507
sections[currentKey] = {
504508
title: currentTitle,
509+
level: currentLevel,
505510
content: currentContent.join('\n').trim(),
506511
};
507512
}
508-
currentTitle = sectionMatch[1];
509-
currentKey = sectionMatch[1].toLowerCase();
513+
currentLevel = sectionMatch[1].length;
514+
currentTitle = sectionMatch[2].trim();
515+
currentKey = `${currentLevel}-${currentTitle.toLowerCase()}`;
510516
currentContent = [];
511517
} else if (currentKey) {
512518
currentContent.push(line);
@@ -516,6 +522,7 @@ function parseAgentsContent(
516522
if (currentKey) {
517523
sections[currentKey] = {
518524
title: currentTitle,
525+
level: currentLevel,
519526
content: currentContent.join('\n').trim(),
520527
};
521528
}
@@ -527,15 +534,22 @@ function parseAgentsContent(
527534
* Merge AGENTS.md files from multiple sources
528535
*/
529536
function mergeAgentsFiles(agentsFiles: string[]): string {
530-
const allSections: Record<string, { title: string; contents: string[] }> = {};
537+
const allSections: Record<
538+
string,
539+
{ title: string; level: number; contents: string[] }
540+
> = {};
531541

532542
for (const fileContent of agentsFiles) {
533543
if (!fileContent) continue;
534544
const sections = parseAgentsContent(fileContent);
535545

536546
for (const [key, section] of Object.entries(sections)) {
537547
if (!allSections[key]) {
538-
allSections[key] = { title: section.title, contents: [] };
548+
allSections[key] = {
549+
title: section.title,
550+
level: section.level,
551+
contents: [],
552+
};
539553
}
540554
if (
541555
section.content &&
@@ -549,7 +563,7 @@ function mergeAgentsFiles(agentsFiles: string[]): string {
549563
const result: string[] = [];
550564

551565
for (const [, section] of Object.entries(allSections)) {
552-
result.push(`## ${section.title}`);
566+
result.push(`${'#'.repeat(section.level)} ${section.title}`);
553567
result.push('');
554568
for (const content of section.contents) {
555569
result.push(content);

test/agents.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,27 @@ test('should generate AGENTS.md with eslint tool and template mapping', async ()
116116
assert.match(content, /## Tools/);
117117
assert.match(content, /### ESLint/); // from template-eslint/AGENTS.md
118118
});
119+
120+
test('should merge top-level sections from AGENTS.md files', async () => {
121+
const projectDir = path.join(testDir, 'h1-support');
122+
process.argv = ['node', 'test', '--dir', projectDir, '--template', 'vanilla'];
123+
124+
await create({
125+
name: 'test',
126+
root: fixturesDir,
127+
templates: ['vanilla'],
128+
getTemplateName: async () => 'vanilla',
129+
mapESLintTemplate: () => null,
130+
});
131+
132+
const agentsPath = path.join(projectDir, 'AGENTS.md');
133+
assert.strictEqual(fs.existsSync(agentsPath), true);
134+
135+
const content = fs.readFileSync(agentsPath, 'utf-8');
136+
const h1Matches = content.match(/^# Project Overview$/gm) ?? [];
137+
assert.strictEqual(h1Matches.length, 1);
138+
assert.match(
139+
content,
140+
/This section provides common guidance for all templates./,
141+
);
142+
});

test/fixtures/agents-md/template-common/AGENTS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Project Overview
2+
3+
This section provides common guidance for all templates.
4+
15
## Development
26

37
### Common Development
@@ -7,4 +11,4 @@
711
## Tools
812

913
### Common Tools
10-
- Tools that apply to all templates
14+
- Tools that apply to all templates

0 commit comments

Comments
 (0)