Skip to content

Commit ad91332

Browse files
committed
fix(post-compaction): support H1 headings in extractSections
1 parent 3ceba44 commit ad91332

2 files changed

Lines changed: 86 additions & 4 deletions

File tree

src/auto-reply/reply/post-compaction-context.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,88 @@ Read these files.
150150
expect(result).toContain("Read these files");
151151
});
152152

153+
it("matches H1 headings (top-level section)", async () => {
154+
// Regression: extractSections previously used /^(#{2,3})/ and silently
155+
// skipped H1 headings, causing post-compaction injection to fail when users
156+
// wrote "# Session Startup" instead of "## Session Startup".
157+
const content = `# Session Startup
158+
159+
Read WORKFLOW_AUTO.md first.
160+
161+
# Other Section
162+
163+
Not relevant.
164+
`;
165+
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
166+
const result = await readPostCompactionContext(tmpDir);
167+
expect(result).not.toBeNull();
168+
expect(result).toContain("Session Startup");
169+
expect(result).toContain("WORKFLOW_AUTO.md");
170+
expect(result).not.toContain("Other Section");
171+
});
172+
173+
it("matches H4 headings", async () => {
174+
const content = `#### Session Startup
175+
176+
H4 startup instructions.
177+
178+
#### Other
179+
`;
180+
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
181+
const result = await readPostCompactionContext(tmpDir);
182+
expect(result).not.toBeNull();
183+
expect(result).toContain("H4 startup instructions");
184+
});
185+
186+
it("H1 section is terminated by the next H1", async () => {
187+
// A same-level H1 should terminate the current H1 section.
188+
const content = `# Session Startup
189+
190+
Critical startup content.
191+
192+
# Red Lines
193+
194+
Do not break rules.
195+
196+
# Unrelated
197+
198+
Ignore this.
199+
`;
200+
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
201+
const result = await readPostCompactionContext(tmpDir);
202+
expect(result).not.toBeNull();
203+
expect(result).toContain("Critical startup content");
204+
expect(result).toContain("Do not break rules");
205+
expect(result).not.toContain("Unrelated");
206+
});
207+
208+
it("H1 section includes lower-level sub-headings (H2/H3)", async () => {
209+
// Sub-headings inside an H1 section must be captured as part of the section.
210+
const content = `# Session Startup
211+
212+
## Step 1
213+
214+
Do step one.
215+
216+
### Step 1a
217+
218+
Detail for step 1a.
219+
220+
## Step 2
221+
222+
Do step two.
223+
224+
# Other
225+
`;
226+
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
227+
const result = await readPostCompactionContext(tmpDir);
228+
expect(result).not.toBeNull();
229+
expect(result).toContain("Step 1");
230+
expect(result).toContain("Step 1a");
231+
expect(result).toContain("Step 2");
232+
expect(result).not.toContain("Other");
233+
});
234+
153235
it("skips sections inside code blocks", async () => {
154236
const content = `# Rules
155237

src/auto-reply/reply/post-compaction-context.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export async function readPostCompactionContext(
157157

158158
/**
159159
* Extract named sections from markdown content.
160-
* Matches H2 (##) or H3 (###) headings case-insensitively.
160+
* Matches H1 (#) through H4 (####) headings case-insensitively.
161161
* Skips content inside fenced code blocks.
162162
* Captures until the next heading of same or higher level, or end of string.
163163
*/
@@ -193,11 +193,11 @@ export function extractSections(
193193
continue;
194194
}
195195

196-
// Check if this line is a heading
197-
const headingMatch = line.match(/^(#{2,3})\s+(.+?)\s*$/);
196+
// Check if this line is a heading (H1 through H4)
197+
const headingMatch = line.match(/^(#{1,4})\s+(.+?)\s*$/);
198198

199199
if (headingMatch) {
200-
const level = headingMatch[1].length; // 2 or 3
200+
const level = headingMatch[1].length; // 1 to 4
201201
const headingText = headingMatch[2];
202202

203203
if (!inSection) {

0 commit comments

Comments
 (0)