Repository: yamadashy/repomix
Pull request #556: feat: --no-file-summary now also suppresses generationHeader; doesn't suppress headerText (fixes #554)
Author: login: joshwand
Created: 2025-05-15T16:32:29Z | Merged: 2025-05-17T07:47:44Z

--no-file-summary should also suppress generationHeader; should not suppress user-specified headerText ( fixes #554 )

## Checklist

- [x] Run `npm run test`
- [x] Run `npm run lint`


Linked issue #554: Feature Request: `--no-file-summary` should also suppress `generationHeader`; should not suppress user-specified `headerText`
Repomix's output has a [summary/usage guidelines section](https://github.com/yamadashy/repomix/blob/fbad7c9ae364e52eb0cd153c451fc54f1606850a/src/core/output/outputGenerate.ts#L61), which can be suppressed with `--no-file-summary`,  but it also has a [generationHeader](https://github.com/yamadashy/repomix/blob/fbad7c9ae364e52eb0cd153c451fc54f1606850a/src/core/output/outputGenerate.ts#L60) section which cannot be suppressed. 

My use case is for packing files other than source code (project documentation, code guidelines, etc), but the text in the unsuppressable [generationHeader](https://github.com/yamadashy/repomix/blob/fbad7c9ae364e52eb0cd153c451fc54f1606850a/src/core/output/outputStyleDecorate.ts#L50) has static references to "the codebase", which may mislead the reader of the file (especially since I'm lazy and just pass the directory name in argv instead of using `--include`, so the output says it's "the entire codebase"). 

Additionally, the `--header-text` config item adds its contents to the [summary/usage guidelines section](https://github.com/yamadashy/repomix/blob/7d1aa52697e2fe4342a21a4607254e5d84e043f8/src/core/output/outputStyleDecorate.ts#L118). When that section is suppressed with `--no-file-summary`, the custom `--header-text` is suppressed along with it. 

Desired behavior:

- `--no-file-summary` should suppress both the summary/usage guidelines section and the `generationHeader`
- `--header-text`, if provided, should be included in the output, regardless of the `--no-file-summary` flag
Linked issue comments: user: login: yamadashy
created_at: 2025-05-17T05:50:22Z
body: Hi, @joshwand 
Thanks for pointing that out!

You’re right—I hadn’t thought of it that way.
`fileSummary` should be removable via `--no-file-summary`, and `headerText`, being user-specified, shouldn’t be suppressed. Though it’s a breaking change, it makes Repomix more flexible for different use cases.
I’ll review the PR soon.

author_association: OWNER
user: login: yamadashy
created_at: 2025-05-21T15:18:11Z
body: Hi, @joshwand !
This implementation has been released in version 0.3.6!
https://github.com/yamadashy/repomix/releases/tag/v0.3.6

Thank you very much for your contribution!
Please feel free to reach out if you have any other suggestions in the future!
author_association: OWNER

Diff:
diff --git a/src/core/output/outputGenerate.ts b/src/core/output/outputGenerate.ts
index bca61bb01..2a47c71bb 100644
--- a/src/core/output/outputGenerate.ts
+++ b/src/core/output/outputGenerate.ts
@@ -57,22 +57,19 @@ const generateParsableXmlOutput = async (renderContext: RenderContext): Promise<
   const xmlBuilder = new XMLBuilder({ ignoreAttributes: false });
   const xmlDocument = {
     repomix: {
-      '#text': renderContext.generationHeader,
       file_summary: renderContext.fileSummaryEnabled
         ? {
-            '#text': 'This section contains a summary of this file.',
+            '#text': renderContext.generationHeader,
             purpose: renderContext.summaryPurpose,
             file_format: `${renderContext.summaryFileFormat}
-4. Repository files, each consisting of:
+5. Repository files, each consisting of:
   - File path as an attribute
   - Full contents of the file`,
             usage_guidelines: renderContext.summaryUsageGuidelines,
             notes: renderContext.summaryNotes,
-            additional_info: {
-              user_provided_header: renderContext.headerText,
-            },
           }
         : undefined,
+      user_provided_header: renderContext.headerText,
       directory_structure: renderContext.directoryStructureEnabled ? renderContext.treeString : undefined,
       files: renderContext.filesEnabled
         ? {
diff --git a/src/core/output/outputStyles/markdownStyle.ts b/src/core/output/outputStyles/markdownStyle.ts
index e892d3091..27a361c73 100644
--- a/src/core/output/outputStyles/markdownStyle.ts
+++ b/src/core/output/outputStyles/markdownStyle.ts
@@ -2,9 +2,9 @@ import Handlebars from 'handlebars';
 
 export const getMarkdownTemplate = () => {
   return /* md */ `
+{{#if fileSummaryEnabled}}
 {{{generationHeader}}}
 
-{{#if fileSummaryEnabled}}
 # File Summary
 
 ## Purpose
@@ -12,7 +12,7 @@ export const getMarkdownTemplate = () => {
 
 ## File Format
 {{{summaryFileFormat}}}
-4. Multiple file entries, each consisting of:
+5. Multiple file entries, each consisting of:
   a. A header with the file path (## File: path/to/file)
   b. The full contents of the file in a code block
 
@@ -22,11 +22,10 @@ export const getMarkdownTemplate = () => {
 ## Notes
 {{{summaryNotes}}}
 
-## Additional Info
+{{/if}}
 {{#if headerText}}
-### User Provided Header
+# User Provided Header
 {{{headerText}}}
-{{/if}}
 
 {{/if}}
 {{#if directoryStructureEnabled}}
diff --git a/src/core/output/outputStyles/plainStyle.ts b/src/core/output/outputStyles/plainStyle.ts
index 8917abba7..7c6bea924 100644
--- a/src/core/output/outputStyles/plainStyle.ts
+++ b/src/core/output/outputStyles/plainStyle.ts
@@ -3,9 +3,9 @@ const PLAIN_LONG_SEPARATOR = '='.repeat(64);
 
 export const getPlainTemplate = () => {
   return `
+{{#if fileSummaryEnabled}}
 {{{generationHeader}}}
 
-{{#if fileSummaryEnabled}}
 ${PLAIN_LONG_SEPARATOR}
 File Summary
 ${PLAIN_LONG_SEPARATOR}
@@ -17,7 +17,7 @@ Purpose:
 File Format:
 ------------
 {{{summaryFileFormat}}}
-4. Multiple file entries, each consisting of:
+5. Multiple file entries, each consisting of:
   a. A separator line (================)
   b. The file path (File: path/to/file)
   c. Another separator line
@@ -32,13 +32,13 @@ Notes:
 ------
 {{{summaryNotes}}}
 
-Additional Info:
-----------------
+{{/if}}
+
 {{#if headerText}}
-User Provided Header:
------------------------
+${PLAIN_LONG_SEPARATOR}
+User Provided Header
+${PLAIN_LONG_SEPARATOR}
 {{{headerText}}}
-{{/if}}
 
 {{/if}}
 {{#if directoryStructureEnabled}}
diff --git a/src/core/output/outputStyles/xmlStyle.ts b/src/core/output/outputStyles/xmlStyle.ts
index 940a89738..4ae22d174 100644
--- a/src/core/output/outputStyles/xmlStyle.ts
+++ b/src/core/output/outputStyles/xmlStyle.ts
@@ -1,8 +1,8 @@
 export const getXmlTemplate = () => {
   return /* xml */ `
+{{#if fileSummaryEnabled}}
 {{{generationHeader}}}
 
-{{#if fileSummaryEnabled}}
 <file_summary>
 This section contains a summary of this file.
 
@@ -12,7 +12,7 @@ This section contains a summary of this file.
 
 <file_format>
 {{{summaryFileFormat}}}
-4. Repository files, each consisting of:
+5. Multiple file entries, each consisting of:
   - File path as an attribute
   - Full contents of the file
 </file_format>
@@ -25,16 +25,13 @@ This section contains a summary of this file.
 {{{summaryNotes}}}
 </notes>
 
-<additional_info>
+</file_summary>
+
+{{/if}}
 {{#if headerText}}
 <user_provided_header>
 {{{headerText}}}
 </user_provided_header>
-{{/if}}
-
-</additional_info>
-
-</file_summary>
 
 {{/if}}
 {{#if directoryStructureEnabled}}
diff --git a/tests/core/output/outputGenerate.test.ts b/tests/core/output/outputGenerate.test.ts
index 82a3fab9c..4749e8143 100644
--- a/tests/core/output/outputGenerate.test.ts
+++ b/tests/core/output/outputGenerate.test.ts
@@ -138,4 +138,53 @@ describe('outputGenerate', () => {
     expect(output).toContain('## File: dir/file2.txt');
     expect(output).toContain('````\n```\ncontent2\n```\n````');
   });
+
+  test('generateOutput (txt) should omit generationHeader when fileSummaryEnabled is false, but always include headerText if provided', async () => {
+    const mockConfig = createMockConfig({
+      output: {
+        filePath: 'output.txt',
+        style: 'plain',
+        fileSummary: false,
+        headerText: 'ALWAYS SHOW THIS HEADER',
+      },
+    });
+    const mockProcessedFiles: ProcessedFile[] = [{ path: 'file1.txt', content: 'content1' }];
+    const output = await generateOutput([process.cwd()], mockConfig, mockProcessedFiles, []);
+    expect(output).not.toContain('This file is a merged representation'); // generationHeader
+    expect(output).toContain('ALWAYS SHOW THIS HEADER');
+  });
+
+  test('generateOutput (xml) omits generationHeader when fileSummaryEnabled is false, but always includes headerText', async () => {
+    const mockConfig = createMockConfig({
+      output: {
+        filePath: 'output.xml',
+        style: 'xml',
+        fileSummary: false,
+        headerText: 'XML HEADER',
+        parsableStyle: true,
+      },
+    });
+    const mockProcessedFiles: ProcessedFile[] = [{ path: 'file1.txt', content: '<div>foo</div>' }];
+    const output = await generateOutput([process.cwd()], mockConfig, mockProcessedFiles, []);
+    const parser = new XMLParser({ ignoreAttributes: false });
+    const parsedOutput = parser.parse(output);
+    expect(parsedOutput.repomix['#text']).toBeUndefined();
+    expect(parsedOutput.repomix.user_provided_header).toBe('XML HEADER');
+  });
+
+  test('generateOutput (markdown) omits generationHeader when fileSummaryEnabled is false, but always includes headerText', async () => {
+    const mockConfig = createMockConfig({
+      output: {
+        filePath: 'output.md',
+        style: 'markdown',
+        fileSummary: false,
+        headerText: 'MARKDOWN HEADER',
+        parsableStyle: false,
+      },
+    });
+    const mockProcessedFiles: ProcessedFile[] = [{ path: 'file1.txt', content: 'content1' }];
+    const output = await generateOutput([process.cwd()], mockConfig, mockProcessedFiles, []);
+    expect(output).not.toContain('This file is a merged representation');
+    expect(output).toContain('MARKDOWN HEADER');
+  });
 });
diff --git a/tests/core/output/outputStyles/markdownStyle.test.ts b/tests/core/output/outputStyles/markdownStyle.test.ts
index 54fdf1453..5e485deb9 100644
--- a/tests/core/output/outputStyles/markdownStyle.test.ts
+++ b/tests/core/output/outputStyles/markdownStyle.test.ts
@@ -1,6 +1,8 @@
 import Handlebars from 'handlebars';
 import { describe, expect, test } from 'vitest';
+import { generateOutput } from '../../../../src/core/output/outputGenerate.js';
 import { getMarkdownTemplate } from '../../../../src/core/output/outputStyles/markdownStyle.js';
+import { createMockConfig } from '../../../testing/testUtils.js';
 
 describe('markdownStyle', () => {
   describe('getMarkdownTemplate', () => {
@@ -59,7 +61,7 @@ describe('markdownStyle', () => {
 
       const result = compiledTemplate(data);
 
-      expect(result).toContain('### User Provided Header');
+      expect(result).toContain('# User Provided Header');
       expect(result).toContain('Custom Header Text');
     });
 
@@ -74,7 +76,7 @@ describe('markdownStyle', () => {
 
       const result = compiledTemplate(data);
 
-      expect(result).not.toContain('### User Provided Header');
+      expect(result).not.toContain('# User Provided Header');
     });
 
     test('should render instruction section when provided', () => {
@@ -92,6 +94,35 @@ describe('markdownStyle', () => {
       expect(result).toContain('# Instruction');
       expect(result).toContain('Custom Instruction Text');
     });
+
+    test('should display headerText if specified even if fileSummary is disabled', () => {
+      const template = getMarkdownTemplate();
+      const compiledTemplate = Handlebars.compile(template);
+      const data = {
+        headerText: 'MARKDOWN HEADER',
+        fileSummaryEnabled: false,
+        directoryStructureEnabled: true,
+        processedFiles: [],
+      };
+      const result = compiledTemplate(data);
+      expect(result).not.toContain('This file is a merged representation');
+      expect(result).toContain('MARKDOWN HEADER');
+    });
+
+    test('should not display generationHeader if fileSummary is disabled', () => {
+      const template = getMarkdownTemplate();
+      const compiledTemplate = Handlebars.compile(template);
+      const data = {
+        generationHeader: 'Generated Test Header',
+        fileSummaryEnabled: false,
+        directoryStructureEnabled: true,
+        processedFiles: [],
+      };
+      const result = compiledTemplate(data);
+      expect(result).not.toContain('This file is a merged representation');
+      expect(result).not.toContain('Generated Test Header');
+      expect(result).toContain('# Directory Structure');
+    });
   });
 
   describe('getFileExtension helper', () => {
diff --git a/tests/core/output/outputStyles/plainStyle.test.ts b/tests/core/output/outputStyles/plainStyle.test.ts
index 63a9c1cfd..006289524 100644
--- a/tests/core/output/outputStyles/plainStyle.test.ts
+++ b/tests/core/output/outputStyles/plainStyle.test.ts
@@ -30,4 +30,18 @@ describe('plainStyle', () => {
     expect(output).toContain('Custom header text');
     expect(output).toContain('Files');
   });
+
+  test('plain style: headerText always present, generationHeader only if fileSummaryEnabled', async () => {
+    const mockConfig = createMockConfig({
+      output: {
+        filePath: 'output.txt',
+        style: 'plain',
+        fileSummary: false,
+        headerText: 'PLAIN HEADER',
+      },
+    });
+    const output = await generateOutput([process.cwd()], mockConfig, [], []);
+    expect(output).not.toContain('This file is a merged representation');
+    expect(output).toContain('PLAIN HEADER');
+  });
 });
diff --git a/tests/core/output/outputStyles/xmlStyle.test.ts b/tests/core/output/outputStyles/xmlStyle.test.ts
index 3545c1e97..feeb1d01a 100644
--- a/tests/core/output/outputStyles/xmlStyle.test.ts
+++ b/tests/core/output/outputStyles/xmlStyle.test.ts
@@ -30,4 +30,19 @@ describe('xmlStyle', () => {
     expect(output).toContain('Custom header text');
     expect(output).toContain('files');
   });
+
+  test('xml style: headerText always present, generationHeader only if fileSummaryEnabled', async () => {
+    const mockConfig = createMockConfig({
+      output: {
+        filePath: 'output.xml',
+        style: 'xml',
+        fileSummary: false,
+        headerText: 'XML HEADER',
+        parsableStyle: false,
+      },
+    });
+    const output = await generateOutput([process.cwd()], mockConfig, [], []);
+    expect(output).not.toContain('This file is a merged representation');
+    expect(output).toContain('XML HEADER');
+  });
 });
diff --git a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.md b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.md
new file mode 100644
index 000000000..0db8b0426
--- /dev/null
+++ b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.md
@@ -0,0 +1,141 @@
+This file is a merged representation of the entire codebase, combined into a single document by Repomix.
+
+# File Summary
+
+## Purpose
+This file contains a packed representation of the entire repository's contents.
+It is designed to be easily consumable by AI systems for analysis, code review,
+or other automated processes.
+
+## File Format
+The content is organized as follows:
+1. This summary section
+2. Repository information
+3. Directory structure
+4. Repository files (if enabled)
+5. Multiple file entries, each consisting of:
+  a. A header with the file path (## File: path/to/file)
+  b. The full contents of the file in a code block
+
+## Usage Guidelines
+- This file should be treated as read-only. Any changes should be made to the
+  original repository files, not this packed version.
+- When processing this file, use the file path to distinguish
+  between different files in the repository.
+- Be aware that this file may contain sensitive information. Handle it with
+  the same level of security as you would the original repository.
+- Pay special attention to the Repository Description. These contain important context and guidelines specific to this project.
+
+## Notes
+- Some files may have been excluded based on .gitignore rules and Repomix's configuration
+- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
+- Files matching patterns in .gitignore are excluded
+- Files matching default ignore patterns are excluded
+
+# User Provided Header
+This repository is simple-project
+
+# Directory Structure
+```
+resources/
+  .repomixignore
+  data.txt
+src/
+  index.js
+  utils.js
+.repomixignore
+package.json
+README.md
+repomix.config.json
+```
+
+# Files
+
+## File: resources/.repomixignore
+````
+ignored-data.txt
+````
+
+## File: resources/data.txt
+````
+dummy data
+````
+
+## File: src/index.js
+````javascript
+const { greet } = require('./utils');
+
+function main() {
+  console.log(greet('World'));
+}
+
+main();
+````
+
+## File: src/utils.js
+````javascript
+function greet(name) {
+  return `Hello, ${name}!`;
+}
+
+module.exports = {
+  greet,
+};
+````
+
+## File: .repomixignore
+````
+**/build/**
+````
+
+## File: package.json
+````json
+{
+  "name": "simple-project",
+  "version": "1.0.0",
+  "description": "A simple project for testing Repomix",
+  "main": "src/index.js",
+  "scripts": {
+    "start": "node src/index.js"
+  },
+  "keywords": ["simple", "test"],
+  "author": "Test Author",
+  "license": "MIT"
+}
+````
+
+## File: README.md
+````markdown
+# Simple Project
+
+This is a simple project used for testing Repomix.
+
+## Usage
+
+To run the project:
+
+```
+npm start
+```
+
+This will output a greeting message to the console.
+````
+
+## File: repomix.config.json
+````json
+{
+  "output": {
+    "filePath": "repomix-output.txt",
+    "headerText": "This repository is simple-project",
+    "removeComments": false,
+    "removeEmptyLines": false,
+    "topFilesLength": 5,
+    "showLineNumbers": false
+  },
+  "ignore": {
+    "useGitignore": true,
+    "useDefaultPatterns": true,
+    "customPatterns": []
+  }
+}
+````
diff --git a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt
index 3ea525d1d..5efa3320b 100644
--- a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt
+++ b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt
@@ -16,7 +16,8 @@ The content is organized as follows:
 1. This summary section
 2. Repository information
 3. Directory structure
-4. Multiple file entries, each consisting of:
+4. Repository files (if enabled)
+5. Multiple file entries, each consisting of:
   a. A separator line (================)
   b. The file path (File: path/to/file)
   c. Another separator line
@@ -40,10 +41,10 @@ Notes:
 - Files matching patterns in .gitignore are excluded
 - Files matching default ignore patterns are excluded
 
-Additional Info:
-----------------
-User Provided Header:
------------------------
+
+================================================================
+User Provided Header
+================================================================
 This repository is simple-project
 
 ================================================================
@@ -155,6 +156,7 @@ File: repomix.config.json
 
 
 
+
 ================================================================
 End of Codebase
 ================================================================
diff --git a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml
index 48ad7c6c0..ba5a61d37 100644
--- a/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml
+++ b/tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml
@@ -14,7 +14,8 @@ The content is organized as follows:
 1. This summary section
 2. Repository information
 3. Directory structure
-4. Repository files, each consisting of:
+4. Repository files (if enabled)
+5. Multiple file entries, each consisting of:
   - File path as an attribute
   - Full contents of the file
 </file_format>
@@ -36,15 +37,12 @@ The content is organized as follows:
 - Files matching default ignore patterns are excluded
 </notes>
 
-<additional_info>
+</file_summary>
+
 <user_provided_header>
 This repository is simple-project
 </user_provided_header>
 
-</additional_info>
-
-</file_summary>
-
 <directory_structure>
 resources/
   .repomixignore
diff --git a/tests/integration-tests/packager.test.ts b/tests/integration-tests/packager.test.ts
index a6392eab8..3a12b4f34 100644
--- a/tests/integration-tests/packager.test.ts
+++ b/tests/integration-tests/packager.test.ts
@@ -36,7 +36,9 @@ describe.runIf(!isWindows)('packager integration', () => {
       desc: 'simple plain style',
       input: 'simple-project',
       output: 'simple-project-output.txt',
-      config: {},
+      config: {
+        output: { style: 'plain', filePath: 'simple-project-output.txt' },
+      },
     },
     {
       desc: 'simple xml style',
@@ -46,6 +48,14 @@ describe.runIf(!isWindows)('packager integration', () => {
         output: { style: 'xml', filePath: 'simple-project-output.xml' },
       },
     },
+    {
+      desc: 'simple markdown style',
+      input: 'simple-project',
+      output: 'simple-project-output.md',
+      config: {
+        output: { style: 'markdown', filePath: 'simple-project-output.md' },
+      },
+    },
   ];
 
   let tempDir: string;
@@ -134,29 +144,48 @@ describe.runIf(!isWindows)('packager integration', () => {
       const actualOutput = await fs.readFile(actualOutputPath, 'utf-8');
       const expectedOutput = await fs.readFile(expectedOutputPath, 'utf-8');
 
-      // Compare the outputs - XMLとプレーンテキストで異なる場合は条件分岐
+      // Compare the outputs - styles (e.g., XML, plain, markdown) may differ
       expect(actualOutput).toContain('This file is a merged representation of the entire codebase');
 
-      if (config.output?.style === 'xml') {
-        // XML形式のテスト
-        expect(actualOutput).toContain('<file_summary>');
-        expect(actualOutput).toContain('<directory_structure>');
-        expect(actualOutput).toContain('resources/');
-        expect(actualOutput).toContain('src/');
-        expect(actualOutput).toContain('<file path="src/index.js">');
-        expect(actualOutput).toContain('function main() {');
-        expect(actualOutput).toContain('<file path="src/utils.js">');
-        expect(actualOutput).toContain('function greet(name) {');
-      } else {
-        // プレーンテキスト形式のテスト
-        expect(actualOutput).toContain('File Summary');
-        expect(actualOutput).toContain('Directory Structure');
-        expect(actualOutput).toContain('resources/');
-        expect(actualOutput).toContain('src/');
-        expect(actualOutput).toContain('File: src/index.js');
-        expect(actualOutput).toContain('function main() {');
-        expect(actualOutput).toContain('File: src/utils.js');
-        expect(actualOutput).toContain('function greet(name) {');
+      // Common assertions for all styles
+      expect(actualOutput).toContain('resources/');
+      expect(actualOutput).toContain('src/');
+      expect(actualOutput).toContain('This repository is simple-project');
+
+      switch (config.output?.style) {
+        case 'xml':
+          expect(actualOutput).toContain('<file_summary>');
+          expect(actualOutput).toContain('<user_provided_header>');
+          expect(actualOutput).toContain('</user_provided_header>');
+          expect(actualOutput).toContain('<directory_structure>');
+          expect(actualOutput).toContain('<file path="src/index.js">');
+          expect(actualOutput).toContain('function main() {');
+          expect(actualOutput).toContain('<file path="src/utils.js">');
+          expect(actualOutput).toContain('function greet(name) {');
+          break;
+
+        case 'markdown':
+          expect(actualOutput).toContain('# File Summary');
+          expect(actualOutput).toContain('# User Provided Header');
+          expect(actualOutput).toContain('# Directory Structure');
+          expect(actualOutput).toContain('## File: src/index.js');
+          expect(actualOutput).toContain('````javascript\nconst { greet }');
+          expect(actualOutput).toContain('## File: src/utils.js');
+          expect(actualOutput).toContain('````javascript\nfunction greet(name) {');
+          break;
+
+        case 'plain':
+          expect(actualOutput).toContain('File Summary');
+          expect(actualOutput).toContain('User Provided Header');
+          expect(actualOutput).toContain('Directory Structure');
+          expect(actualOutput).toContain('File: src/index.js');
+          expect(actualOutput).toContain('function main() {');
+          expect(actualOutput).toContain('File: src/utils.js');
+          expect(actualOutput).toContain('function greet(name) {');
+          break;
+
+        default:
+          throw new Error(`Unsupported style: ${config.output?.style}`);
       }
 
       // Optionally, update the expected output if explicitly requested


Reviews:
user: login: gemini-code-assist[bot]
body: Hello @joshwand, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

## Summary of Changes
Hello team, gemini-code-assist here with a summary of this pull request. This PR implements a feature requested in the title: modifying the behavior of the `--no-file-summary` flag. Previously, this flag would suppress the file summary section but still include the automatically generated `generationHeader` and the user-provided `headerText`. With this change, `--no-file-summary` (or `fileSummaryEnabled: false` in the configuration) will now correctly suppress the `generationHeader` as well, while ensuring that the user-provided `headerText` is *always* included if specified, regardless of whether the file summary is enabled. This change affects the output generation logic and the templates for Markdown, Plain, and XML styles. New tests have been added to verify this updated behavior across the different output formats.

### Highlights
* **Feature Implementation**: Modifies the behavior of the `--no-file-summary` flag to align with the requested functionality.
* **Conditional Output**: The automatically generated `generationHeader` is now only included in the output when the file summary is enabled (`fileSummaryEnabled: true`).
* **Unconditional Output**: The user-provided `headerText` is now always included in the output if it is specified, regardless of the `fileSummaryEnabled` setting.
* **Template Updates**: The Handlebars templates for Markdown, Plain, and XML output styles have been updated to reflect the new conditional logic for the `generationHeader` and `headerText`.
* **New Tests**: Adds comprehensive tests to `outputGenerate.test.ts` and the style-specific test files (`markdownStyle.test.ts`, `plainStyle.test.ts`, `xmlStyle.test.ts`) to ensure the correct header behavior when the file summary is disabled.

### Changelog
<details>
<summary>Click here to see the changelog</summary>

* **src/core/output/outputGenerate.ts**
  * Adjusted the XML output structure (`xmlDocument`) to place the `generationHeader` inside the `file_summary` element (making it conditional on `fileSummaryEnabled`) and move the `user_provided_header` outside the `file_summary` element (making it unconditional).
* **src/core/output/outputStyles/markdownStyle.ts**
  * Moved the `{{{generationHeader}}}` helper call inside the `{{#if fileSummaryEnabled}}` block.
  * Moved the `{{#if headerText}}...{{/if}}` block outside the `{{#if fileSummaryEnabled}}...{{/if}}` block.
  * Added necessary imports for testing utilities.
* **src/core/output/outputStyles/plainStyle.ts**
  * Moved the `{{{generationHeader}}}` helper call inside the `{{#if fileSummaryEnabled}}` block.
  * Moved the `{{#if headerText}}...{{/if}}` block outside the `{{#if fileSummaryEnabled}}...{{/if}}` block.
* **src/core/output/outputStyles/xmlStyle.ts**
  * Moved the `{{{generationHeader}}}` helper call inside the `{{#if fileSummaryEnabled}}` block.
  * Moved the `{{#if headerText}}...{{/if}}` block outside the `{{#if fileSummaryEnabled}}...{{/if}}` block.
  * Adjusted XML element nesting to accommodate the moved `headerText`.
* **tests/core/output/outputGenerate.test.ts**
  * Added new tests to `generateOutput` for plain, XML, and markdown styles to verify that the `generationHeader` is omitted and `headerText` is included when `fileSummaryEnabled` is false.
* **tests/core/output/outputStyles/markdownStyle.test.ts**
  * Added template-specific tests for the markdown style to confirm that `headerText` is displayed and `generationHeader` is not displayed when `fileSummaryEnabled` is false.
  * Added imports for `generateOutput` and `createMockConfig`.
* **tests/core/output/outputStyles/plainStyle.test.ts**
  * Added a template-specific test for the plain style to confirm the header behavior when `fileSummaryEnabled` is false.
* **tests/core/output/outputStyles/xmlStyle.test.ts**
  * Added a template-specific test for the xml style to confirm the header behavior when `fileSummaryEnabled` is false.

</details>


<details>

<summary><b>Using Gemini Code Assist</b></summary>
<br>

The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips.

<b>Invoking Gemini</b>

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either `/gemini <command>` or `@gemini-code-assist <command>`. Below is a summary of the supported commands.

Feature | Command | Description
--- | --- | ---
Code Review | `/gemini review` | Performs a code review for the current pull request in its current state.
Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state.
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments.
Help | `/gemini help` | Displays a list of available commands.

<b>Customization</b>

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a `.gemini/` folder in the base of the repository. Detailed instructions can be found [here](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github).

<b>Limitations & Feedback</b>

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments to provide feedback.

</details>

<b>You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the [Gemini Code Assist IDE Extension](https://cloud.google.com/products/gemini/code-assist).</b>


[^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/review-github-code). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).

---

> A flag flips its state,
> Header logic shifts its fate,
> User text stays true.


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:32:57Z
user: login: gemini-code-assist[bot]
body: ## Code Review
This pull request effectively addresses issue #554 by ensuring that `--no-file-summary` (or `fileSummaryEnabled: false`) suppresses the `generationHeader` across all output formats, while correctly preserving `headerText` if provided. The changes are well-localized to the output generation and templating logic.

The addition of new test cases for various output styles (plain, XML, Markdown) and for both parsable and template-based XML is commendable, ensuring good coverage for the modified behavior. The tests clearly verify the suppression of `generationHeader` and the persistence of `headerText` under the specified conditions.

One area for clarification is the structural change in the parsable XML output when `fileSummaryEnabled` is `true`, which I've detailed in a specific comment.

### Summary of Findings
* **Parsable XML Structure Change**: When `fileSummaryEnabled` is true, the `generationHeader` in parsable XML output has moved from being the text content of the root `<repomix>` element to being the text content of the `<file_summary>` element. This also overwrites the previous default text of `<file_summary>`. This is a structural change that might affect existing consumers of the parsable XML format and warrants confirmation.
* **Test Coverage**: The PR includes good test coverage for the new behavior, especially for the suppression of `generationHeader` when `fileSummaryEnabled` is false.
* **Consistency Across Formats**: The change makes the placement of `generationHeader` (as part of the summary section, if enabled) consistent across different output formats (Markdown, plain, template XML, and parsable XML).

### Merge Readiness
The pull request correctly implements the primary goal of suppressing `generationHeader` when `--no-file-summary` is used. The added tests are valuable.

However, there's a structural change to the parsable XML output when the file summary *is* enabled, which could be a breaking change for existing consumers. I've raised a `medium` severity comment regarding this. It would be beneficial to clarify the intent behind this specific structural change before merging.

I am unable to approve pull requests myself, but I recommend addressing or acknowledging the point raised about the parsable XML structure to ensure clarity and avoid unintended consequences for users of that format. Once that's clarified, the PR should be in good shape.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:35:43Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR updates output generation templates and tests to ensure that the generationHeader is suppressed when fileSummary is disabled while still displaying the headerText regardless of fileSummary configuration.
- Added tests across xml, plain, and markdown styles for the new behavior
- Updated templates in XML, plain, and markdown output generators to conditionally render generationHeader inside fileSummary blocks and always render headerText

### Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                                             | Description                                                                    |
|------------------------------------------------------------------|--------------------------------------------------------------------------------|
| tests/core/output/outputStyles/xmlStyle.test.ts                  | Added new test to check xml style behavior with fileSummary disabled           |
| tests/core/output/outputStyles/plainStyle.test.ts                | Added new test to verify plain style displays headerText while suppressing generationHeader |
| tests/core/output/outputStyles/markdownStyle.test.ts             | Added new tests for markdown style ensuring proper headerText and suppression of generationHeader |
| tests/core/output/outputGenerate.test.ts                         | Added new tests for output generation for txt, xml, and markdown styles          |
| src/core/output/outputStyles/xmlStyle.ts                           | Updated XML template to conditionally render generationHeader and always render headerText |
| src/core/output/outputStyles/plainStyle.ts                         | Updated plain template to conditionally render generationHeader and consistently display headerText |
| src/core/output/outputStyles/markdownStyle.ts                        | Updated markdown template to conditionally render generationHeader and move headerText block |
| src/core/output/outputGenerate.ts                                  | Adjusted XML output generation to remove extra header wrapping and ensure headerText is top-level |
</details>





state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T06:38:27Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR ensures that disabling file summaries (`--no-file-summary`) suppresses only the automatically generated header, while still showing any user-specified `headerText`.

- Added and updated integration and unit tests for XML, plain, and Markdown styles to cover the new behavior.
- Modified Handlebars templates (`xmlStyle`, `plainStyle`, `markdownStyle`) and the XML builder (`generateParsableXmlOutput`) to conditionally wrap generation headers and always include `headerText`.

### Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

<details>
<summary>Show a summary per file</summary>

| File                                                                                     | Description                                                                            |
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| tests/integration-tests/packager.test.ts                                                 | Updated `config` shape, added Markdown style case, and clarified assertions.           |
| tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml              | Added a "Repository files" entry and relocated closing tags for user-provided header.  |
| tests/integration-tests/fixtures/packager/outputs/simple-project-output.txt              | Inserted user-provided header section into plain-text fixture.                         |
| tests/integration-tests/fixtures/packager/outputs/simple-project-output.md               | Added the expected Markdown output fixture.                                           |
| tests/core/output/outputStyles/xmlStyle.test.ts                                         | New test verifying XML header behavior when file summaries are disabled.               |
| tests/core/output/outputStyles/plainStyle.test.ts                                       | New test verifying plain text header behavior when file summaries are disabled.        |
| tests/core/output/outputStyles/markdownStyle.test.ts                                    | Updated expectations and added tests for Markdown header/generation-header logic.      |
| tests/core/output/outputGenerate.test.ts                                                | Added integration tests for `generateOutput` across all three styles and flags.        |
| src/core/output/outputStyles/xmlStyle.ts                                                | Wrapped generation header & file summary in `if fileSummaryEnabled`; moved headerText.|
| src/core/output/outputStyles/plainStyle.ts                                              | Wrapped generation header & summary in `if fileSummaryEnabled`; moved headerText.      |
| src/core/output/outputStyles/markdownStyle.ts                                           | Wrapped generation header & summary in `if fileSummaryEnabled`; moved headerText.      |
| src/core/output/outputGenerate.ts                                                       | Moved `generationHeader` into `file_summary` and always include `user_provided_header`.|
</details>





state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T07:35:27Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR ensures that the `--no-file-summary` option suppresses the auto-generated header but still includes any user-provided header text.  
- Wrapped `generationHeader` in `fileSummaryEnabled` guards and moved the `headerText` block outside that guard in all output templates (XML, plain, markdown).  
- Added new unit tests for each style to verify that `headerText` always appears and `generationHeader` is conditional, plus updated integration tests and fixtures for markdown and plain outputs.

### Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                                       | Description                                                                                   |
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| tests/integration-tests/packager.test.ts                   | Expanded the integration matrix to cover markdown style and updated assertions for headers.   |
| tests/integration-tests/fixtures/packager/outputs/*.xml    | Adjusted numbering and removed `<additional_info>` wrapper around `<user_provided_header>`.   |
| tests/integration-tests/fixtures/packager/outputs/*.txt    | Updated separators and block for “User Provided Header” to match plain template changes.      |
| tests/integration-tests/fixtures/packager/outputs/*.md     | Added a full markdown output fixture including user header and code blocks.                  |
| tests/core/output/outputStyles/xmlStyle.test.ts            | Added a test for XML style to check `headerText` vs. `generationHeader` behavior.            |
| tests/core/output/outputStyles/plainStyle.test.ts          | Added a similar test for plain style.                                                         |
| tests/core/output/outputStyles/markdownStyle.test.ts       | Updated expectations to match the new single-`#` header for user-provided text.             |
| tests/core/output/outputGenerate.test.ts                   | New tests to verify `generateOutput` behavior across all three styles.                        |
| src/core/output/outputStyles/xmlStyle.ts                   | Wrapped `generationHeader` in `fileSummaryEnabled` and moved `headerText` out.                |
| src/core/output/outputStyles/plainStyle.ts                 | Same wrap/move logic applied for plain text template.                                         |
| src/core/output/outputStyles/markdownStyle.ts              | Applied the same pattern in the markdown template.                                            |
| src/core/output/outputGenerate.ts                          | Updated XML builder to only set `#text` for file summary when enabled and always include `headerText`. |
</details>



<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**tests/core/output/outputStyles/xmlStyle.test.ts:35**
* This test uses `createMockConfig` and `generateOutput` but neither is imported in this file. Please add:
```js
import { generateOutput } from '../../../../src/core/output/outputGenerate.js';
import { createMockConfig } from '../../../testing/testUtils.js';
```
```
const mockConfig = createMockConfig({
```
**tests/core/output/outputStyles/plainStyle.test.ts:35**
* This test uses `createMockConfig` and `generateOutput` but neither is imported in this file. Please add:
```js
import { generateOutput } from '../../../../src/core/output/outputGenerate.js';
import { createMockConfig } from '../../../testing/testUtils.js';
```
```
const mockConfig = createMockConfig({
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T07:46:32Z
user: login: yamadashy
state: APPROVED
author_association: OWNER
submitted_at: 2025-05-17T07:47:36Z

Review comments:
diff_hunk: @@ -57,22 +57,19 @@ const generateParsableXmlOutput = async (renderContext: RenderContext): Promise<
   const xmlBuilder = new XMLBuilder({ ignoreAttributes: false });
   const xmlDocument = {
     repomix: {
-      '#text': renderContext.generationHeader,
       file_summary: renderContext.fileSummaryEnabled
         ? {
-            '#text': 'This section contains a summary of this file.',
+            '#text': renderContext.generationHeader,
path: src/core/output/outputGenerate.ts
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

This change moves `renderContext.generationHeader` to be the `#text` content of the `file_summary` element when `fileSummaryEnabled` is true. Previously, `generationHeader` was the `#text` content of the root `repomix` element, and `file_summary` had its own `#text` content ('This section contains a summary of this file.').

This means:
1.  If `fileSummaryEnabled` is `true`, the `generationHeader` is no longer at `repomix['#text']`. Consumers of the parsable XML expecting it there will find it `undefined`. It's now at `repomix.file_summary['#text']`.
2.  The original descriptive text of `file_summary` ('This section contains a summary of this file.') is now replaced by `generationHeader`.

While this makes `generationHeader` consistently part of the summary section (similar to how it's handled in template-based outputs now), this is a structural change to the parsable XML output for the case when `fileSummaryEnabled` is `true`. 

Could you confirm if this structural modification for the `fileSummaryEnabled: true` scenario in parsable XML is intended? If so, it might be worth noting as a potential breaking change for existing parsers that rely on the previous structure. 

An alternative to maintain the `generationHeader` at the root for parsable XML when `fileSummaryEnabled` is true could have been:
```typescript
// In repomix object:
'#text': renderContext.fileSummaryEnabled ? renderContext.generationHeader : undefined,
file_summary: renderContext.fileSummaryEnabled
  ? {
      '#text': 'This section contains a summary of this file.', // Retain original text
      // ... other file_summary properties
    }
  : undefined,
```
This would achieve suppression when `fileSummaryEnabled` is false without altering the location of `generationHeader` or overwriting `file_summary`'s original text when `fileSummaryEnabled` is true.
created_at: 2025-05-15T16:35:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,29 +144,48 @@ describe.runIf(!isWindows)('packager integration', () => {
       const actualOutput = await fs.readFile(actualOutputPath, 'utf-8');
       const expectedOutput = await fs.readFile(expectedOutputPath, 'utf-8');
 
-      // Compare the outputs - XMLとプレーンテキストで異なる場合は条件分岐
+      // Compare the outputs - XML and plain style are different
path: tests/integration-tests/packager.test.ts
user: login: Copilot
body: This comment refers only to XML and plain styles, but Markdown is also tested. Consider updating it to reflect all supported styles or changing it to a more generic description.
```suggestion
      // Compare the outputs - styles (e.g., XML, plain, markdown) may differ
```
created_at: 2025-05-17T07:35:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,6 +14,7 @@ The content is organized as follows:
 1. This summary section
 2. Repository information
 3. Directory structure
+4. Repository files (if enabled)
 4. Repository files, each consisting of:
path: tests/integration-tests/fixtures/packager/outputs/simple-project-output.xml
user: login: Copilot
body: The next line is also numbered "4." which duplicates this section number. Adjust the second line to "5." (or renumber both) for clarity.
```suggestion
5. Repository files, each consisting of:
```
created_at: 2025-05-17T07:35:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+This file is a merged representation of the entire codebase, combined into a single document by Repomix.
+
+# File Summary
+
+## Purpose
+This file contains a packed representation of the entire repository's contents.
+It is designed to be easily consumable by AI systems for analysis, code review,
+or other automated processes.
+
+## File Format
+The content is organized as follows:
+1. This summary section
+2. Repository information
+3. Directory structure
+4. Repository files (if enabled)
+4. Multiple file entries, each consisting of:
path: tests/integration-tests/fixtures/packager/outputs/simple-project-output.md
user: login: Copilot
body: This list item is numbered "4." but the following item is also "4.". Consider renumbering to maintain a correct ordered list.
```suggestion
5. Multiple file entries, each consisting of:
```
created_at: 2025-05-17T07:35:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,22 +57,19 @@ const generateParsableXmlOutput = async (renderContext: RenderContext): Promise<
   const xmlBuilder = new XMLBuilder({ ignoreAttributes: false });
   const xmlDocument = {
     repomix: {
-      '#text': renderContext.generationHeader,
       file_summary: renderContext.fileSummaryEnabled
         ? {
-            '#text': 'This section contains a summary of this file.',
+            '#text': renderContext.generationHeader,
             purpose: renderContext.summaryPurpose,
             file_format: `${renderContext.summaryFileFormat}
 4. Repository files, each consisting of:
   - File path as an attribute
   - Full contents of the file`,
             usage_guidelines: renderContext.summaryUsageGuidelines,
             notes: renderContext.summaryNotes,
-            additional_info: {
-              user_provided_header: renderContext.headerText,
-            },
           }
         : undefined,
+      user_provided_header: renderContext.headerText,
path: src/core/output/outputGenerate.ts
user: login: Copilot
body: Currently `user_provided_header` is always added (even if `headerText` is undefined). It’s safer to conditionally include this property only when `renderContext.headerText` is truthy to avoid generating empty XML nodes.
```suggestion
      user_provided_header: renderContext.headerText ? renderContext.headerText : undefined,
```
created_at: 2025-05-17T07:35:27Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-05-17T05:22:58Z
body: ## [Codecov](https://app.codecov.io/gh/yamadashy/repomix/pull/556?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kazuki+Yamada) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 88.41%. Comparing base [(`fbad7c9`)](https://app.codecov.io/gh/yamadashy/repomix/commit/fbad7c9ae364e52eb0cd153c451fc54f1606850a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kazuki+Yamada) to head [(`ce3d025`)](https://app.codecov.io/gh/yamadashy/repomix/commit/ce3d025e23abf17d6bba98b47782726a7ca3ff52?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kazuki+Yamada).
> Report is 5 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #556      +/-   ##
==========================================
+ Coverage   88.39%   88.41%   +0.01%     
==========================================
  Files          91       91              
  Lines        4679     4678       -1     
  Branches      935      937       +2     
==========================================
  Hits         4136     4136              
+ Misses        543      542       -1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/yamadashy/repomix/pull/556?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kazuki+Yamada).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kazuki+Yamada).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: yamadashy
created_at: 2025-05-17T07:46:50Z
body: @joshwand 
Thank you for addressing this!

I made a few minor tweaks, and everything looks good!
I’ll merge this now.

Please let me know if there’s anything else.
author_association: OWNER