Skip to content

Conversation

@bramburn
Copy link

@bramburn bramburn commented Nov 3, 2025

This pull request introduces a new line limiting feature to Repomix, allowing users to control the number of lines included from each file in the output. This is particularly useful for managing AI context windows, reducing processing costs, and focusing on the most relevant code sections in large repositories.

Key Features

  • Intelligent Line Selection: A new algorithm preserves code structure by applying a 30/60/10 distribution strategy (header/core/footer), retaining imports, function signatures, and key logic.
  • Multi-Language Support: Language-specific strategies have been implemented for TypeScript/JavaScript, Python, Java, Go, C/C++, C#, Rust, PHP, Ruby, Swift, and Dart.
  • Flexible Configuration: The line limit can be configured via a new --line CLI option, the repomix.config.json file, or the REPOMIX_LINE_LIMIT environment variable.
  • Comprehensive Reporting: The CLI now reports detailed truncation statistics, including the number of truncated files and the reduction in line and token counts. Verbose mode provides per-file truncation details.
  • Extensive Testing: The feature is supported by a full suite of unit, integration, performance, and regression tests to ensure functionality and backward compatibility.
  • Documentation: The README.md and website documentation have been updated with a comprehensive guide on how to use the new line limiting feature.

How to Use

CLI:

# Limit each file to 100 lines
repomix --line 100 ./src

Configuration File (repomix.config.json):

{
  "output": {
    "lineLimit": 100
  }
}

Environment Variable:

export REPOMIX_LINE_LIMIT=100
repomix ./src

Checklist

  • Run npm run test
  • Run npm run lint

@bramburn bramburn requested a review from yamadashy as a code owner November 3, 2025 16:58
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a comprehensive line-limiting feature enabling per-file line reduction through language-specific parsing and content selection. Includes 11 language-specific strategies, configuration/CLI integration, truncation tracking, performance benchmarking tool, and extensive test coverage.

Changes

Cohort / File(s) Summary
Documentation & Performance
README.md, docs/performance-testing.md, repomix-instruction.md (deleted)
Added extensive line-limiting feature documentation to README with CLI examples and config schemas; introduced new performance testing guide; removed legacy instruction file.
Performance Benchmarking
scripts/performance-benchmark.ts
New CLI utility for running, comparing, and trending performance benchmarks with HTML/JSON reporting and regression detection.
CLI Configuration & Options
src/cli/cliRun.ts, src/cli/types.ts, src/cli/actions/defaultAction.ts, src/cli/actions/workers/defaultActionWorker.ts
Added -l/--line-limit options with validation; propagated line-limit config through CLI pipeline and to pack() function.
Core Configuration & Loading
src/config/configSchema.ts, src/config/configLoad.ts
Added lineLimit option to config schema; implemented REPOMIX_LINE_LIMIT environment variable parsing with priority handling.
Line Limit Processor & Strategies
src/core/file/lineLimitProcessor.ts, src/core/file/lineLimitTypes.ts, src/core/file/lineLimitStrategies/*
Core line-limiting engine with 30/60/10 header/core/footer distribution; 11 language-specific strategies (TypeScript, Python, Java, Go, C, C++, C#, Rust, PHP, Ruby, Swift, Kotlin, Dart) and a registry; error handling with fallback heuristics.
File Processing & Types
src/core/file/fileProcessContent.ts, src/core/file/fileProcess.ts, src/core/file/fileTypes.ts, src/core/file/workers/fileProcessWorker.ts
Updated processContent return type to include originalContent and truncation metadata; integrated line-limit application; added truncation tracking; exported worker cleanup hook.
Truncation & Metrics
src/core/file/truncationMetrics.ts, src/core/packager.ts, src/core/metrics/TokenCounter.ts, src/core/metrics/calculateMetrics.ts, src/core/metrics/calculateSelectiveFileMetrics.ts, src/core/metrics/workers/calculateMetricsWorker.ts
Added truncation metrics calculation, progress formatting, and reporting helpers; integrated dual token counting (original/truncated); extended metrics pipeline to track fileOriginalTokenCounts.
Reporting & Output
src/cli/cliReport.ts, src/cli/reporters/tokenCountTreeReporter.ts, src/core/tokenCount/buildTokenCountStructure.ts, src/core/tokenCount/types.ts
Enhanced reporting to display truncation statistics and per-file details; extended token tree reporter to show original counts and truncation indicators.
Output Generation
src/core/output/outputGenerate.ts, src/core/output/outputStyles/markdownStyle.ts, src/core/output/outputStyles/plainStyle.ts, src/core/output/outputStyles/xmlStyle.ts
Updated output generators (XML, JSON, Markdown, Plain) to include truncation metadata and indicators for truncated files.
File Processing Tests
tests/core/file/fileProcess.test.ts, tests/core/file/fileProcessContent.test.ts
Updated tests to reflect processContent return shape change; expanded fileProcessContent tests with comprehensive mock setup and line-limit/compression/comment-removal scenarios.
Line Limit Feature Tests
tests/core/file/lineLimitConfig.test.ts, tests/core/file/lineLimitEdgeCases.test.ts, tests/core/file/lineLimitIntegration.test.ts, tests/core/file/lineLimitProcessor.test.ts, tests/core/file/lineLimitTypes.test.ts
Comprehensive unit and integration tests covering processor behavior, error handling, configuration combinations, edge cases, type validation, and resource management.
Language Strategy Tests
tests/core/file/lineLimitStrategies/*
Test suites for each language strategy covering header/footer identification, function analysis, complexity calculation, fallback heuristics, and integration scenarios.
Truncation & Metrics Tests
tests/core/file/truncationMetrics.test.ts, tests/core/output/truncationIndicators.test.ts, tests/core/output/outputGenerate.test.ts, tests/core/output/outputStyles/jsonStyle.test.ts
Tests for truncation metrics calculations, progress formatting, summary generation, and truncation indicator rendering across all output styles.
Integration Tests
tests/integration-tests/cliLineLimit.test.ts, tests/integration-tests/configLineLimit.test.ts
End-to-end tests verifying CLI line-limit option parsing, config file loading, environment variable precedence, and output style compatibility.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI Handler
    participant Config as Config Loader
    participant Pack as Packager
    participant FileProc as File Processor
    participant LineLim as LineLimitProcessor
    participant Strategy as Language Strategy
    participant Output as Output Generator

    CLI->>Config: Load config with lineLimit
    Config->>Config: Check env var REPOMIX_LINE_LIMIT
    Config->>Config: Apply priority: CLI > Config > Env
    
    CLI->>Pack: pack(files, config, verbose)
    
    Pack->>FileProc: processFile(file)
    FileProc->>FileProc: Remove comments/empty lines
    
    alt lineLimit enabled
        FileProc->>LineLim: applyLineLimit(content, path, limit)
        LineLim->>Strategy: Initialize strategy for language
        Strategy->>Strategy: Parse AST with tree-sitter
        LineLim->>Strategy: identifyHeaderLines()
        LineLim->>Strategy: identifyFooterLines()
        LineLim->>Strategy: analyzeFunctions()
        
        LineLim->>LineLim: Allocate lines (30% header, 60% core, 10% footer)
        LineLim->>LineLim: Select important functions from core
        LineLim->>LineLim: Build limited content + truncation metadata
        
        LineLim-->>FileProc: {content, truncation, originalContent}
    else lineLimit disabled
        FileProc-->>FileProc: Return content only
    end
    
    FileProc-->>Pack: ProcessedFile with truncation data
    
    Pack->>Pack: calculateTruncationMetrics()
    Pack->>Output: generateOutput(files, truncationMetrics)
    
    Output->>Output: Add truncation indicators to output
    Output-->>CLI: Rendered output with truncation info
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • Language-specific strategies (src/core/file/lineLimitStrategies/*): 11 similar but distinct strategy implementations with tree-sitter queries, complexity calculations, and fallback heuristics—each requires understanding of language-specific AST patterns. High logic density across multiple files.
  • Line limit processor (src/core/file/lineLimitProcessor.ts): Core engine managing caching, language detection, strategy dispatch, line allocation logic, and truncation tracking. Dense with interconnected logic.
  • Integration points (fileProcessContent.ts, packager.ts, calculateMetrics.ts): Return type changes and pipeline modifications require tracing impacts across multiple layers.
  • Dual token counting (calculateMetrics.ts, calculateSelectiveFileMetrics.ts, calculateMetricsWorker.ts): New pairTaskRunner wiring adds complexity to metrics pipeline.
  • Test coverage: 25+ new test files with diverse scenarios help mitigate risk but require validation of edge cases and integration behavior.

Areas requiring extra attention:

  • Tree-sitter query correctness for each language and fallback heuristic behavior
  • Line allocation distribution algorithm (30/60/10) and edge cases (very small limits)
  • Truncation metadata propagation through output generators (XML, JSON, Markdown, Plain)
  • Token counting with original/truncated pair logic and task runner cleanup
  • Configuration priority resolution (CLI > config file > env var)

Possibly related PRs

Suggested labels

enhancement, feature, line-limiting, parser, performance

Suggested reviewers

  • yamadashy

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat(core): Introduce Intelligent Line Limiting Feature' directly and clearly summarizes the main change. It uses a standard commit convention (feat scope) and concisely describes the primary feature being introduced—an intelligent line limiting capability for the Repomix tool. The title is specific, descriptive, and accurately reflects the substantial feature addition evident in the changeset.
Description check ✅ Passed The pull request description is comprehensive and well-structured. It includes key features with bullet points, usage examples across three configuration methods (CLI, config file, environment variable), and a completed checklist verifying that npm run test and npm run lint were executed. The description clearly explains the purpose, implementation approach, and testing coverage, going well beyond the minimal template requirements.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @bramburn, I'm Gemini Code Assist1! 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!

This pull request significantly enhances Repomix by introducing an intelligent line limiting feature. This functionality is designed to optimize output size, making it particularly useful for managing AI context windows and reducing processing costs in large codebases. It intelligently selects the most relevant code sections while preserving structural integrity across various programming languages.

Highlights

  • Intelligent Line Limiting: Introduces a new feature to control the number of lines included from each file, using a 30/60/10 distribution strategy (header/core/footer) to preserve code structure.
  • Multi-Language Support: Language-specific strategies are implemented for TypeScript/JavaScript, Python, Java, Go, C/C++, C#, Rust, PHP, Ruby, Swift, and Dart.
  • Flexible Configuration: The line limit can be configured via a new --line CLI option, the repomix.config.json file, or the REPOMIX_LINE_LIMIT environment variable, with a clear priority order.
  • Comprehensive Reporting: The CLI now provides detailed truncation statistics, including the number of truncated files, and reduction in line and token counts. A verbose mode offers per-file truncation details.
  • Extensive Testing & Documentation: The feature is supported by a full suite of unit, integration, performance, and regression tests, and the README.md and website documentation have been updated.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

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.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

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.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an impressive and well-documented line limiting feature. The implementation is thorough, covering CLI options, configuration files, environment variables, and detailed reporting. The addition of language-specific strategies and a comprehensive performance testing suite is particularly noteworthy. I've identified a few issues, primarily related to configuration priority and script execution, which should be addressed to ensure the feature behaves as specified and is fully robust. Overall, this is a high-quality contribution.

Comment on lines +522 to +524
if (require.main === module) {
program.parse();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script uses require.main === module to make it executable. However, this is a CommonJS pattern and will not work in an ES module context, which this file appears to be (using import/export). This will cause the script to fail when run directly from the command line.

You should use the ES module equivalent. You'll also need to add import { pathToFileURL } from 'node:url'; at the top of the file.

if (import.meta.url === (await import('node:url')).pathToFileURL(process.argv[1]).href) {
  program.parse();
}

Comment on lines +211 to +214
// Apply environment variable line limit if set and not already overridden by CLI
if (envLineLimitValue !== undefined && !cliConfig.output?.lineLimit) {
mergedOutput.lineLimit = envLineLimitValue;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current logic for merging the lineLimit configuration does not follow the specified priority order of CLI > file > env. The current implementation results in CLI > env > file, meaning the environment variable incorrectly overrides the value from the configuration file.

To fix this, you should apply the environment variable with the lowest precedence. You can achieve this by changing the merge order when creating mergedOutput around line 208 and removing this if block.

For example:

const mergedOutput = {
  ...baseConfig.output,
  ...(envLineLimitValue !== undefined && { lineLimit: envLineLimitValue }),
  ...fileConfig?.output,
  ...cliConfig.output,
};

This ensures the correct CLI > file > env > default priority.

Comment on lines +378 to +384
# Use in package.json scripts
{
"scripts": {
"pack:small": "repomix --line 25 ./src",
"pack:medium": "repomix --line 100 ./src"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example for package.json scripts is incorrectly placed inside a bash code block, which is meant for shell commands. This should be in its own json code block for correct syntax highlighting and to avoid confusion. Additionally, the descriptive comment is inside the code block, which is not ideal.

Consider structuring it like this for better clarity:

...
repomix --line 25 ./src  # Uses 25, not 100
```

And in `package.json` scripts:

```json
{
  "scripts": {
    "pack:small": "repomix --line 25 ./src",
    "pack:medium": "repomix --line 100 ./src"
  }
}
```

Comment on lines +120 to +125
(v: string) => {
if (!/^\d+$/.test(v)) {
throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
}
return Number(v);
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The validation for the --line option allows 0 as a valid value because /^\d+$/ matches '0'. However, the configuration schema requires a positive integer. This will lead to a less user-friendly Zod validation error later, instead of your custom error message. To provide a better user experience, the validation should also check if the value is greater than zero.

(v: string) => {
          const num = Number(v);
          if (!Number.isInteger(num) || num <= 0) {
            throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
          }
          return num;
        }

Comment on lines +130 to +135
(v: string) => {
if (!/^\d+$/.test(v)) {
throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
}
return Number(v);
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the --line option, the validation for the --line-limit alias allows 0 as a valid value, while the schema requires a positive integer. This should be updated to check for positive integers to provide a more immediate and specific error message.

(v: string) => {
          const num = Number(v);
          if (!Number.isInteger(num) || num <= 0) {
            throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
          }
          return num;
        }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 32

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/config/configLoad.ts (1)

179-214: Fix environment variable precedence logic.

The current implementation has a critical bug in configuration precedence. The environment variable REPOMIX_LINE_LIMIT will override values set in the config file, which violates the expected precedence order.

Current behavior: CLI > Env Var > File Config > Default
Expected behavior: CLI > File Config > Env Var > Default

The condition at line 212 only checks if the CLI set the value (!cliConfig.output?.lineLimit), but after the spread operations, if fileConfig had lineLimit set, it's already in mergedOutput.lineLimit. The environment variable then unconditionally overwrites it.

Apply this fix to respect file config precedence:

     // Apply environment variable line limit if set and not already overridden by CLI
-    if (envLineLimitValue !== undefined && !cliConfig.output?.lineLimit) {
+    if (envLineLimitValue !== undefined && mergedOutput.lineLimit === undefined) {
       mergedOutput.lineLimit = envLineLimitValue;
     }

This ensures the environment variable only applies when neither CLI nor file config has set a value.

src/core/file/fileProcessContent.ts (1)

60-108: Reorder line numbering relative to line limiting

Line 60 onwards currently prepends line numbers before calling applyLineLimit. That means Python, Ruby, etc. hit the line limiter with strings like 1: import os, which tree-sitter cannot parse. The call throws, the catch block at Line 96 logs and marks truncated: false, and the feature silently skips truncation whenever showLineNumbers is enabled—effectively disabling line limiting for a very common configuration. Please apply the limiter to the raw content first and only add numbering afterwards so we always feed valid source into the parser.

[suggested fix]

@@
-  if (config.output.compress) {
+  const shouldAddLineNumbers = config.output.showLineNumbers && !config.output.compress;
+  let lineNumbersApplied = false;
+
+  if (config.output.compress) {
@@
-  } else if (config.output.showLineNumbers) {
-    const lines = processedContent.split('\n');
-    const padding = lines.length.toString().length;
-    const numberedLines = lines.map((line, i) => `${(i + 1).toString().padStart(padding)}: ${line}`);
-    processedContent = numberedLines.join('\n');
-  }
+  }
@@
       const lineLimitResult = await applyLineLimit(processedContent, rawFile.path, config.output.lineLimit, {
         preserveStructure: true,
         showTruncationIndicators: false, // We'll handle indicators in output styles
         enableCaching: true,
       });
 
       processedContent = lineLimitResult.content;
+
+      if (shouldAddLineNumbers) {
+        const lines = processedContent.split('\n');
+        const padding = lines.length.toString().length;
+        const numberedLines = lines.map((line, i) => `${(i + 1).toString().padStart(padding)}: ${line}`);
+        processedContent = numberedLines.join('\n');
+        lineNumbersApplied = true;
+      }
@@
   }
+
+  if (shouldAddLineNumbers && !lineNumbersApplied) {
+    const lines = processedContent.split('\n');
+    const padding = lines.length.toString().length;
+    const numberedLines = lines.map((line, i) => `${(i + 1).toString().padStart(padding)}: ${line}`);
+    processedContent = numberedLines.join('\n');
+  }
src/cli/cliReport.ts (1)

43-85: Avoid double-reporting truncation stats

We currently emit the truncation summary twice: first via the inline block (Lines 43-58) and then immediately via reportTruncationSummary (Lines 76-85). That produces duplicate sections in the CLI output, which is confusing and breaks the “single source of truth” intent behind the helper. Please remove the ad-hoc block and let the helper own the rendering (augment the helper to log the token info if needed), e.g.:

-  if (packResult.truncationMetrics) {
-    const stats = getTruncationStats(packResult.truncationMetrics);
-    logger.log('📊 Truncation Statistics:');
-    logger.log(pc.dim('────────────────────'));
-    logger.log(stats.summary);
-    if (stats.reductionInfo) {
-      logger.log(stats.reductionInfo);
-    }
-    if (stats.lineLimitInfo) {
-      logger.log(stats.lineLimitInfo);
-    }
-    if (stats.tokenInfo) {
-      logger.log(stats.tokenInfo);
-    }
-    logger.log('');
-  }
+  if (packResult.truncationMetrics) {
+    reportTruncationSummary(packResult.truncationMetrics);
+    logger.log('');
+    if (verbose && packResult.truncationMetrics.perFileTruncation?.length) {
+      reportVerboseTruncationDetails(packResult.truncationMetrics.perFileTruncation);
+      logger.log('');
+    }
+  }

…and extend reportTruncationSummary so it logs tokenInfo alongside the other fields. This keeps the output clean and avoids diverging implementations.

🧹 Nitpick comments (2)
src/core/output/outputStyles/plainStyle.ts (1)

60-62: Consider adding explicit newline before truncation notice.

The truncation notice is appended directly after {{{this.content}}} without a guaranteed newline separator. If the file content doesn't end with a newline, the truncation message will appear on the same line as the last line of content, which may look awkward.

Apply this diff to ensure proper spacing:

-{{{this.content}}}{{#if this.truncation.truncated}}
-
-... (truncated: showing {{this.truncation.truncatedLineCount}} of {{this.truncation.originalLineCount}} lines){{/if}}
+{{{this.content}}}{{#if this.truncation.truncated}}
+
+... (truncated: showing {{this.truncation.truncatedLineCount}} of {{this.truncation.originalLineCount}} lines)
+{{/if}}
src/cli/cliRun.ts (1)

117-136: Reduce duplication: consolidate validation logic.

Both --line and --line-limit options have identical validation logic. This creates a maintenance burden where fixes need to be applied in two places.

Consider extracting the validation to a shared function:

+    const parseLineLimit = (v: string): number => {
+      if (!/^[1-9]\d*$/.test(v)) {
+        throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
+      }
+      return Number(v);
+    };
+
     .option(
       '-l, --line <number>',
       'Maximum number of lines per file. Limits each file to specified number of lines using intelligent selection. Alias: --line-limit',
-      (v: string) => {
-        if (!/^\d+$/.test(v)) {
-          throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
-        }
-        return Number(v);
-      },
+      parseLineLimit,
     )
     .option(
       '--line-limit <number>',
       'Alias for --line option. Maximum number of lines per file using intelligent selection',
-      (v: string) => {
-        if (!/^\d+$/.test(v)) {
-          throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
-        }
-        return Number(v);
-      },
+      parseLineLimit,
     )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68c3c4b and fcecd48.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (68)
  • README.md (5 hunks)
  • docs/performance-testing.md (1 hunks)
  • repomix-instruction.md (0 hunks)
  • scripts/performance-benchmark.ts (1 hunks)
  • src/cli/actions/defaultAction.ts (2 hunks)
  • src/cli/actions/workers/defaultActionWorker.ts (1 hunks)
  • src/cli/cliReport.ts (5 hunks)
  • src/cli/cliRun.ts (1 hunks)
  • src/cli/reporters/tokenCountTreeReporter.ts (2 hunks)
  • src/cli/types.ts (1 hunks)
  • src/config/configLoad.ts (2 hunks)
  • src/config/configSchema.ts (2 hunks)
  • src/core/file/fileProcess.ts (2 hunks)
  • src/core/file/fileProcessContent.ts (3 hunks)
  • src/core/file/fileTypes.ts (1 hunks)
  • src/core/file/lineLimitProcessor.ts (1 hunks)
  • src/core/file/lineLimitStrategies/CLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/CSharpLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/DartLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/GoLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/JavaLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/KotlinLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (1 hunks)
  • src/core/file/lineLimitStrategies/PhpLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/PythonLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/RubyLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/RustLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/SwiftLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitStrategies/TypeScriptLineLimitStrategy.ts (1 hunks)
  • src/core/file/lineLimitTypes.ts (1 hunks)
  • src/core/file/truncationMetrics.ts (1 hunks)
  • src/core/file/workers/fileProcessWorker.ts (1 hunks)
  • src/core/metrics/TokenCounter.ts (1 hunks)
  • src/core/metrics/calculateMetrics.ts (6 hunks)
  • src/core/metrics/calculateSelectiveFileMetrics.ts (2 hunks)
  • src/core/metrics/workers/calculateMetricsWorker.ts (2 hunks)
  • src/core/metrics/workers/types.ts (1 hunks)
  • src/core/output/outputGenerate.ts (2 hunks)
  • src/core/output/outputStyles/markdownStyle.ts (1 hunks)
  • src/core/output/outputStyles/plainStyle.ts (1 hunks)
  • src/core/output/outputStyles/xmlStyle.ts (1 hunks)
  • src/core/packager.ts (6 hunks)
  • src/core/tokenCount/buildTokenCountStructure.ts (2 hunks)
  • src/core/tokenCount/types.ts (1 hunks)
  • tests/core/file/fileProcess.test.ts (7 hunks)
  • tests/core/file/fileProcessContent.test.ts (1 hunks)
  • tests/core/file/lineLimitConfig.test.ts (1 hunks)
  • tests/core/file/lineLimitEdgeCases.test.ts (1 hunks)
  • tests/core/file/lineLimitIntegration.test.ts (1 hunks)
  • tests/core/file/lineLimitProcessor.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/AllLineLimitStrategies.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/CLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/CSharpLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/GoLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/JavaLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/LineLimitStrategyRegistry.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/PhpLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/PythonLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/RubyLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/RustLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitStrategies/TypeScriptLineLimitStrategy.test.ts (1 hunks)
  • tests/core/file/lineLimitTypes.test.ts (1 hunks)
  • tests/core/file/truncationMetrics.test.ts (1 hunks)
  • tests/core/output/outputGenerate.test.ts (1 hunks)
  • tests/core/output/outputStyles/jsonStyle.test.ts (2 hunks)
  • tests/core/output/truncationIndicators.test.ts (1 hunks)
  • tests/integration-tests/cliLineLimit.test.ts (1 hunks)
  • tests/integration-tests/configLineLimit.test.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • repomix-instruction.md
🧰 Additional context used
🧬 Code graph analysis (50)
src/cli/actions/defaultAction.ts (1)
src/cli/cliReport.ts (1)
  • reportResults (15-88)
src/cli/actions/workers/defaultActionWorker.ts (1)
src/core/packager.ts (1)
  • pack (51-164)
tests/core/file/lineLimitStrategies/LineLimitStrategyRegistry.test.ts (2)
src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (1)
  • LineLimitStrategyRegistry (19-134)
src/core/file/lineLimitTypes.ts (1)
  • LanguageStrategy (80-85)
src/core/file/workers/fileProcessWorker.ts (1)
src/core/file/fileProcessContent.ts (1)
  • processContent (22-113)
tests/core/file/lineLimitEdgeCases.test.ts (2)
src/core/file/lineLimitProcessor.ts (1)
  • LineLimitProcessor (19-412)
src/core/file/lineLimitTypes.ts (3)
  • LineLimitTooSmallError (135-144)
  • LineLimitError (120-133)
  • LanguageStrategy (80-85)
tests/core/file/lineLimitConfig.test.ts (2)
src/core/file/lineLimitProcessor.ts (1)
  • LineLimitProcessor (19-412)
src/core/file/lineLimitTypes.ts (1)
  • LineLimitTooSmallError (135-144)
tests/core/file/lineLimitStrategies/GoLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/GoLineLimitStrategy.ts (1)
  • GoLineLimitStrategy (8-385)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/config/configLoad.ts (1)
src/shared/logger.ts (1)
  • logger (89-89)
src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategyRegistry (90-92)
  • LanguageStrategy (80-85)
src/core/treeSitter/lang2Query.ts (1)
  • SupportedLang (37-37)
src/core/file/lineLimitStrategies/RustLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryRust.ts (1)
  • queryRust (1-75)
tests/core/file/lineLimitStrategies/RubyLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/RubyLineLimitStrategy.ts (1)
  • RubyLineLimitStrategy (8-362)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/lineLimitStrategies/DartLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryDart.ts (1)
  • queryDart (1-29)
tests/core/file/lineLimitStrategies/JavaLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/JavaLineLimitStrategy.ts (1)
  • JavaLineLimitStrategy (8-356)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
tests/core/file/lineLimitTypes.test.ts (1)
src/core/file/lineLimitTypes.ts (3)
  • LineLimitError (120-133)
  • LineLimitTooSmallError (135-144)
  • LineLimitParseError (146-151)
tests/integration-tests/cliLineLimit.test.ts (3)
tests/testing/testUtils.ts (1)
  • isWindows (47-47)
src/cli/cliRun.ts (1)
  • runCli (232-283)
src/shared/errorHandle.ts (1)
  • RepomixError (6-11)
src/core/file/fileProcessContent.ts (2)
src/core/file/fileTypes.ts (2)
  • RawFile (1-4)
  • TruncationInfo (13-18)
src/core/file/lineLimitProcessor.ts (2)
  • applyLineLimit (52-118)
  • applyLineLimit (417-473)
src/core/file/lineLimitStrategies/KotlinLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryJava.ts (1)
  • queryJava (1-33)
tests/core/file/lineLimitStrategies/TypeScriptLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/TypeScriptLineLimitStrategy.ts (1)
  • TypeScriptLineLimitStrategy (8-339)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/truncationMetrics.ts (2)
src/core/file/fileTypes.ts (3)
  • ProcessedFile (6-11)
  • TruncationMetrics (20-30)
  • PerFileTruncation (32-38)
src/config/configSchema.ts (1)
  • RepomixConfigMerged (163-163)
src/core/file/lineLimitStrategies/PythonLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryPython.ts (1)
  • queryPython (1-32)
src/core/file/lineLimitStrategies/JavaLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryJava.ts (1)
  • queryJava (1-33)
src/core/file/lineLimitStrategies/CLineLimitStrategy.ts (3)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryCpp.ts (1)
  • queryCpp (1-19)
src/core/treeSitter/queries/queryC.ts (1)
  • queryC (1-13)
tests/core/file/lineLimitStrategies/CSharpLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/CSharpLineLimitStrategy.ts (1)
  • CSharpLineLimitStrategy (8-385)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
tests/integration-tests/configLineLimit.test.ts (3)
tests/testing/testUtils.ts (1)
  • isWindows (47-47)
src/config/configLoad.ts (2)
  • loadFileConfig (69-111)
  • mergeConfigs (170-253)
src/config/configSchema.ts (1)
  • repomixConfigFileSchema (137-137)
src/core/file/lineLimitStrategies/CSharpLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryCSharp.ts (1)
  • queryCSharp (1-50)
tests/core/file/lineLimitProcessor.test.ts (4)
src/core/file/lineLimitProcessor.ts (3)
  • LineLimitProcessor (19-412)
  • applyLineLimit (52-118)
  • applyLineLimit (417-473)
src/core/file/lineLimitTypes.ts (3)
  • LineLimitError (120-133)
  • LineLimitParseError (146-151)
  • LineLimitConfig (97-102)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (1)
  • LineLimitStrategyRegistry (19-134)
tests/core/file/lineLimitStrategies/PythonLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/PythonLineLimitStrategy.ts (1)
  • PythonLineLimitStrategy (8-359)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
scripts/performance-benchmark.ts (2)
tests/performance/performanceUtils.ts (3)
  • PerformanceThresholds (63-82)
  • PerformanceMetrics (8-31)
  • measurePerformance (161-228)
tests/performance/testDataGenerators.ts (3)
  • generateLargeFile (1480-1495)
  • generatePerformanceTestCases (1573-1599)
  • PerformanceTestCase (7-13)
tests/core/file/lineLimitStrategies/CLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/CLineLimitStrategy.ts (1)
  • CLineLimitStrategy (9-398)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/lineLimitStrategies/SwiftLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/querySwift.ts (1)
  • querySwift (1-41)
src/core/packager.ts (2)
src/core/file/fileTypes.ts (1)
  • TruncationMetrics (20-30)
src/core/file/truncationMetrics.ts (1)
  • calculateTruncationMetrics (7-91)
tests/core/file/lineLimitStrategies/AllLineLimitStrategies.test.ts (3)
src/core/file/lineLimitTypes.ts (1)
  • LineLimitConfig (97-102)
src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (1)
  • LineLimitStrategyRegistry (19-134)
src/core/file/lineLimitProcessor.ts (1)
  • LineLimitProcessor (19-412)
tests/core/file/lineLimitStrategies/RustLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/RustLineLimitStrategy.ts (1)
  • RustLineLimitStrategy (8-420)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/fileProcess.ts (1)
src/core/file/truncationMetrics.ts (1)
  • formatTruncationProgress (96-104)
tests/core/file/fileProcessContent.test.ts (5)
src/core/file/fileTypes.ts (1)
  • RawFile (1-4)
src/core/file/fileProcessContent.ts (1)
  • processContent (22-113)
src/core/file/truncateBase64.ts (1)
  • truncateBase64Content (15-45)
src/core/file/fileManipulate.ts (1)
  • getFileManipulator (367-370)
src/core/file/lineLimitProcessor.ts (2)
  • applyLineLimit (52-118)
  • applyLineLimit (417-473)
src/cli/cliRun.ts (1)
src/shared/errorHandle.ts (1)
  • RepomixError (6-11)
tests/core/file/lineLimitIntegration.test.ts (1)
src/core/file/lineLimitProcessor.ts (1)
  • LineLimitProcessor (19-412)
tests/core/output/truncationIndicators.test.ts (4)
src/config/configSchema.ts (1)
  • RepomixConfigMerged (163-163)
src/core/file/fileTypes.ts (1)
  • ProcessedFile (6-11)
tests/testing/testUtils.ts (1)
  • createMockConfig (15-45)
src/core/output/outputGenerate.ts (1)
  • generateOutput (243-284)
src/cli/cliReport.ts (4)
src/core/packager.ts (1)
  • PackResult (19-35)
src/cli/reporters/tokenCountTreeReporter.ts (1)
  • reportTokenCountTree (11-43)
src/core/file/truncationMetrics.ts (1)
  • getTruncationStats (126-160)
src/core/file/fileTypes.ts (1)
  • PerFileTruncation (32-38)
src/core/file/lineLimitStrategies/GoLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryGo.ts (1)
  • queryGo (1-64)
src/core/file/lineLimitStrategies/PhpLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryPhp.ts (1)
  • queryPhp (1-48)
tests/core/file/truncationMetrics.test.ts (2)
src/core/file/fileTypes.ts (2)
  • ProcessedFile (6-11)
  • TruncationMetrics (20-30)
src/core/file/truncationMetrics.ts (4)
  • calculateTruncationMetrics (7-91)
  • formatTruncationProgress (96-104)
  • getTruncationSummary (109-121)
  • getTruncationStats (126-160)
src/core/metrics/workers/calculateMetricsWorker.ts (3)
src/core/metrics/TokenCounter.ts (2)
  • countTokensPair (45-53)
  • countTokens (19-43)
src/core/metrics/tokenCounterFactory.ts (1)
  • getTokenCounter (12-19)
src/shared/logger.ts (1)
  • error (34-38)
tests/core/file/lineLimitStrategies/PhpLineLimitStrategy.test.ts (2)
src/core/file/lineLimitStrategies/PhpLineLimitStrategy.ts (1)
  • PhpLineLimitStrategy (8-384)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/lineLimitStrategies/RubyLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryRuby.ts (1)
  • queryRuby (1-72)
src/core/metrics/calculateSelectiveFileMetrics.ts (4)
src/core/file/fileTypes.ts (1)
  • ProcessedFile (6-11)
src/shared/processConcurrency.ts (1)
  • TaskRunner (97-100)
src/core/metrics/workers/calculateMetricsWorker.ts (2)
  • TokenCountTask (17-21)
  • TokenCountPairTask (23-28)
src/core/metrics/workers/types.ts (1)
  • FileMetrics (1-7)
src/core/metrics/calculateMetrics.ts (2)
src/shared/processConcurrency.ts (2)
  • TaskRunner (97-100)
  • initTaskRunner (102-108)
src/core/metrics/workers/calculateMetricsWorker.ts (1)
  • TokenCountPairTask (23-28)
src/core/file/lineLimitProcessor.ts (5)
src/core/file/lineLimitTypes.ts (8)
  • LanguageStrategy (80-85)
  • LineLimitError (120-133)
  • LineLimitParseError (146-151)
  • LineLimitConfig (97-102)
  • LineLimitResult (47-54)
  • LineAllocation (38-42)
  • SourceLine (6-12)
  • TruncationIndicator (71-75)
src/core/treeSitter/loadLanguage.ts (1)
  • loadLanguage (7-19)
src/core/file/lineLimitStrategies/LineLimitStrategyRegistry.ts (1)
  • LineLimitStrategyRegistry (19-134)
src/core/treeSitter/lang2Query.ts (1)
  • SupportedLang (37-37)
src/core/treeSitter/ext2Lang.ts (1)
  • ext2Lang (4-31)
src/cli/reporters/tokenCountTreeReporter.ts (1)
src/core/tokenCount/buildTokenCountStructure.ts (1)
  • FileWithTokens (3-8)
src/core/file/lineLimitStrategies/TypeScriptLineLimitStrategy.ts (2)
src/core/file/lineLimitTypes.ts (2)
  • LanguageStrategy (80-85)
  • FunctionAnalysis (26-33)
src/core/treeSitter/queries/queryTypescript.ts (1)
  • queryTypescript (1-73)
🪛 LanguageTool
docs/performance-testing.md

[grammar] ~5-~5: Use a hyphen to join words.
Context: ...erformance testing approach for the line limiting feature in Repomix. The testing...

(QB_NEW_EN_HYPHEN)


[grammar] ~9-~9: Use a hyphen to join words.
Context: ... Based on the PRD requirements, the line limiting feature must meet these perform...

(QB_NEW_EN_HYPHEN)


[style] ~71-~71: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...) Comprehensive benchmarking tool with CLI interface: - Automated Benchmarking: Run ful...

(ACRONYM_TAUTOLOGY)


[style] ~91-~91: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...2000-10000 lines) with scaling limits - Very large files (15000-50000 lines) with aggressi...

(EN_WEAK_ADJECTIVE)


[style] ~109-~109: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...nes): Should process in < 100 seconds - Very large files (> 10000 lines): Should process i...

(EN_WEAK_ADJECTIVE)


[style] ~115-~115: As an alternative to the over-used intensifier ‘extremely’, consider replacing this phrase.
Context: ...adation detection - Edge case handling (extremely large files) ### 3. Language-Specific Perfor...

(EN_WEAK_ADJECTIVE)


[style] ~144-~144: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...- Single Large File: Processing one very large file - Multiple Large Files: Proces...

(EN_WEAK_ADJECTIVE)


[grammar] ~483-~483: Use a hyphen to join words.
Context: ...ance testing suite ensures that the line limiting feature meets all PRD requireme...

(QB_NEW_EN_HYPHEN)

README.md

[grammar] ~437-~437: Use a hyphen to join words.
Context: ... #### How Line Limiting Works The line limiting feature uses an intelligent sel...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/performance-testing.md

26-26: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


291-291: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (16)
src/cli/actions/defaultAction.ts (2)

93-93: LGTM: Verbose flag integration.

The verbose flag is properly passed to enable detailed truncation reporting.


286-292: LGTM: Line limit CLI option handling.

The line option is correctly wired to the output configuration with proper schema validation downstream.

src/cli/types.ts (1)

59-59: LGTM: CLI option type definition.

The optional line property is correctly typed for the new line-limiting feature.

src/config/configSchema.ts (1)

40-46: LGTM: Schema definition with clear documentation.

The lineLimit configuration option is properly validated as a positive integer with excellent inline documentation describing the 30/60/10 distribution strategy.

Also applies to: 106-106

src/core/output/outputStyles/markdownStyle.ts (1)

44-46: LGTM: Truncation notice in Markdown output.

The conditional truncation notice is properly formatted and provides clear information about the number of lines shown vs. original.

src/core/output/outputStyles/xmlStyle.ts (1)

49-51: LGTM: Truncation notice in XML output.

The HTML comment format is appropriate for XML output and maintains consistency with other output styles.

tests/core/output/outputGenerate.test.ts (1)

274-279: LGTM: Test updated for new JSON output structure.

The test correctly reflects the new JSON output format where file entries are objects with a content property. Note that this represents a breaking change in the JSON output format.

src/core/metrics/TokenCounter.ts (1)

45-53: LGTM: Convenient paired token counting.

The countTokensPair method is a clean convenience wrapper that reuses existing token counting logic for both original and truncated content.

src/config/configLoad.ts (1)

179-190: LGTM: Environment variable parsing and validation.

The parsing and validation logic for REPOMIX_LINE_LIMIT is well-implemented with appropriate error handling and logging for invalid values.

src/core/tokenCount/types.ts (1)

4-5: LGTM! Clean type extension.

The optional fields originalTokens and truncated appropriately extend the interface to support truncation metadata without breaking existing code.

src/core/file/fileProcess.ts (1)

44-64: LGTM! Well-integrated truncation tracking.

The truncation count tracking and conditional progress messaging are correctly implemented. The use of optional chaining (result.truncation?.truncated) safely handles cases where truncation info is absent, and the conditional logic appropriately switches between enhanced and standard progress formats based on configuration.

tests/core/file/fileProcess.test.ts (1)

73-167: LGTM! Consistent test updates.

All test assertions have been correctly updated to access result.content instead of result directly, reflecting the API change where processContent now returns an object with a content property. The changes are consistent across all test cases.

tests/core/output/outputStyles/jsonStyle.test.ts (1)

124-150: LGTM! Test expectations align with new JSON format.

The test assertions have been correctly updated to expect file content as objects with a content property, consistent with the new JSON output structure that supports additional metadata like truncation information.

src/core/tokenCount/buildTokenCountStructure.ts (1)

6-7: LGTM! Clean metadata propagation.

The interface extension and field propagation are correctly implemented. The use of file.truncated || false on line 46 ensures the truncated field is always a boolean value, consistent with the type definition.

Also applies to: 45-46

src/core/file/fileTypes.ts (1)

9-38: LGTM! Comprehensive truncation type definitions.

The new interfaces (TruncationInfo, TruncationMetrics, PerFileTruncation) and the extensions to ProcessedFile are well-structured and provide comprehensive metadata tracking for the line-limiting feature. The use of optional fields ensures backward compatibility.

tests/core/file/lineLimitStrategies/AllLineLimitStrategies.test.ts (1)

421-428: Add missing end in Ruby sample

The Ruby example lacks an end to close def save_user, so the class never terminates cleanly. Tree-sitter will flag the snippet as erroneous, weakening the test signal. Add the method-closing end before the class-closing end:

     rescue
       false
     end
-end
+  end
+end

Likely an incorrect or invalid review comment.

Comment on lines +150 to +160
return await applyLineLimit(content, filePath, testCase.lineLimit);
});

caseResults.push(metrics);
}

// Calculate average metrics
const avgMetrics = this.calculateAverageMetrics(caseResults);
this.currentResults.push(avgMetrics);

// Check against thresholds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix zero-throughput benchmark metrics

measurePerformance only fills linesProcessed, linesOutput, and lineLimit when the measured function returns originalLineCount/limitedLineCount (or metadata) at the top level. applyLineLimit exposes those counts under truncation, so every iteration records zeros. That drives metrics.throughputLinesPerSec to 0, passesThresholds always fails, and the summary/report show false negatives even when the limiter is fast. Please surface the counts (and limit) before returning from the measured callback—for example, spread the result and copy truncation.originalLineCount/truncation.truncatedLineCount (and metadata) into the shape measurePerformance expects—so the benchmarks emit real numbers.

🤖 Prompt for AI Agents
In scripts/performance-benchmark.ts around lines 150-160, the measured callback
returns counts nested under truncation so measurePerformance sees zeros; modify
the callback to return an object shaped like measurePerformance expects by
spreading the original result and copying truncation.originalLineCount ->
linesProcessed, truncation.truncatedLineCount -> linesOutput (and set lineLimit
from testCase.lineLimit or truncation.limit if present), and copy any metadata
up to the top level before returning so throughput and threshold checks use real
numbers.

Comment on lines +117 to +136
.option(
'-l, --line <number>',
'Maximum number of lines per file. Limits each file to specified number of lines using intelligent selection. Alias: --line-limit',
(v: string) => {
if (!/^\d+$/.test(v)) {
throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
}
return Number(v);
},
)
.option(
'--line-limit <number>',
'Alias for --line option. Maximum number of lines per file using intelligent selection',
(v: string) => {
if (!/^\d+$/.test(v)) {
throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
}
return Number(v);
},
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix validation to match "positive integer" requirement.

The regex /^\d+$/ accepts 0, but the error message states "Must be a positive integer." Positive integers are typically > 0, not >= 0. This creates a validation mismatch where --line 0 would pass regex validation but violate the semantic requirement.

Apply this diff to fix the validation:

         '-l, --line <number>',
         'Maximum number of lines per file. Limits each file to specified number of lines using intelligent selection. Alias: --line-limit',
         (v: string) => {
-          if (!/^\d+$/.test(v)) {
+          if (!/^[1-9]\d*$/.test(v)) {
             throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
           }
           return Number(v);
         },
       )
       .option(
         '--line-limit <number>',
         'Alias for --line option. Maximum number of lines per file using intelligent selection',
         (v: string) => {
-          if (!/^\d+$/.test(v)) {
+          if (!/^[1-9]\d*$/.test(v)) {
             throw new RepomixError(`Invalid line limit: '${v}'. Must be a positive integer.`);
           }
           return Number(v);
         },
       )

Alternatively, if 0 should be allowed, change the error message to "Must be a non-negative integer."

🤖 Prompt for AI Agents
In src/cli/cliRun.ts around lines 117 to 136, the validator uses /^\d+$/ which
allows "0" despite the message saying "Must be a positive integer"; update both
option validators (for -l/--line and --line-limit) to enforce >0 — either change
the regex to /^[1-9]\d*$/ or parse to Number and check Number(v) > 0, and keep
throwing RepomixError with the same message when the check fails so "0" is
rejected; ensure both validators return the numeric value on success.

Comment on lines +81 to +83
const selectedLines = [...headerLines, ...coreLines, ...footerLines]
.sort((a, b) => a.lineNumber - b.lineNumber)
.slice(0, config.lineLimit);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Deduplicate overlapping sections before slicing.

Header/core/footer selections can point to the same line numbers. Today those duplicates consume the quota, so we repeat the same lines while dropping unique ones later in the file. De‑duplicate on lineNumber (keeping the most important variant) before the final sort/slice.

-      const selectedLines = [...headerLines, ...coreLines, ...footerLines]
-        .sort((a, b) => a.lineNumber - b.lineNumber)
-        .slice(0, config.lineLimit);
+      const merged = [...headerLines, ...coreLines, ...footerLines];
+      const deduped = Array.from(
+        merged
+          .reduce((acc, line) => {
+            const current = acc.get(line.lineNumber);
+            if (!current || current.importance < line.importance) {
+              acc.set(line.lineNumber, line);
+            }
+            return acc;
+          }, new Map<number, SourceLine>())
+          .values(),
+      )
+        .sort((a, b) => a.lineNumber - b.lineNumber)
+        .slice(0, config.lineLimit);
+
+      const selectedLines = deduped;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/core/file/lineLimitProcessor.ts around lines 81 to 83, the
header/core/footer arrays may contain overlapping lineNumber entries which
currently consume the lineLimit quota; deduplicate by lineNumber before sorting
and slicing by merging the three arrays with a defined priority (header highest,
then core, then footer), keeping the entry from the highest-priority section
when duplicate lineNumbers are found, then create the final array from the
deduplicated entries, sort by lineNumber and slice to config.lineLimit.

Comment on lines +202 to +211
private calculateLineAllocation(totalLimit: number): LineAllocation {
const headerLines = Math.floor(totalLimit * 0.3);
const coreLines = Math.floor(totalLimit * 0.6);
const footerLines = Math.floor(totalLimit * 0.1);

return {
headerLines,
coreLines,
footerLines,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Honor the requested limit by distributing the remainder.

Flooring the 30/60/10 buckets drops the remainder, so for most limits we emit fewer lines than requested (e.g., a limit of 25 only returns 24 lines). That’s a correctness bug for the flagship feature. Please reallocate the leftover lines so the buckets always sum to the caller’s limit.

   private calculateLineAllocation(totalLimit: number): LineAllocation {
-    const headerLines = Math.floor(totalLimit * 0.3);
-    const coreLines = Math.floor(totalLimit * 0.6);
-    const footerLines = Math.floor(totalLimit * 0.1);
-
-    return {
-      headerLines,
-      coreLines,
-      footerLines,
-    };
+    const allocation: LineAllocation = {
+      headerLines: Math.floor(totalLimit * 0.3),
+      coreLines: Math.floor(totalLimit * 0.6),
+      footerLines: Math.floor(totalLimit * 0.1),
+    };
+
+    let remainder = totalLimit - (allocation.headerLines + allocation.coreLines + allocation.footerLines);
+    const distributionOrder: Array<keyof LineAllocation> = ['coreLines', 'headerLines', 'footerLines'];
+
+    for (const key of distributionOrder) {
+      if (remainder === 0) {
+        break;
+      }
+      allocation[key] += 1;
+      remainder -= 1;
+    }
+
+    return allocation;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private calculateLineAllocation(totalLimit: number): LineAllocation {
const headerLines = Math.floor(totalLimit * 0.3);
const coreLines = Math.floor(totalLimit * 0.6);
const footerLines = Math.floor(totalLimit * 0.1);
return {
headerLines,
coreLines,
footerLines,
};
private calculateLineAllocation(totalLimit: number): LineAllocation {
const allocation: LineAllocation = {
headerLines: Math.floor(totalLimit * 0.3),
coreLines: Math.floor(totalLimit * 0.6),
footerLines: Math.floor(totalLimit * 0.1),
};
let remainder = totalLimit - (allocation.headerLines + allocation.coreLines + allocation.footerLines);
const distributionOrder: Array<keyof LineAllocation> = ['coreLines', 'headerLines', 'footerLines'];
for (const key of distributionOrder) {
if (remainder === 0) {
break;
}
allocation[key] += 1;
remainder -= 1;
}
return allocation;
}
🤖 Prompt for AI Agents
In src/core/file/lineLimitProcessor.ts around lines 202 to 211, the current
30/60/10 flooring drops the remainder so the returned buckets can sum to less
than totalLimit; compute headerLines = Math.floor(totalLimit * 0.3), coreLines =
Math.floor(totalLimit * 0.6), footerLines = Math.floor(totalLimit * 0.1), then
compute remainder = totalLimit - (headerLines + coreLines + footerLines) and
distribute that remainder back into the buckets (e.g., in priority order core ->
header -> footer, adding 1 to each until remainder is 0) so the returned
headerLines/coreLines/footerLines always sum to totalLimit.

Comment on lines +443 to +448
if (finalConfig.showTruncationIndicators && result.truncationIndicators.length > 0) {
const lines = limitedContent.split('\n');
for (const indicator of result.truncationIndicators) {
if (indicator.position <= lines.length) {
lines.splice(indicator.position - 1, 0, `// ${indicator.description}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix truncation indicator insertion and match comment syntax to the language.

Because indicator.position is measured in the original file, the <= lines.length guard prevents indicators from ever being inserted, so showTruncationIndicators is currently a no-op. When we do insert, we always prepend //, which breaks Python, Ruby, SQL, etc. Please clamp the insertion index against the truncated output and derive an appropriate line comment prefix from the file extension.

-    if (finalConfig.showTruncationIndicators && result.truncationIndicators.length > 0) {
-      const lines = limitedContent.split('\n');
-      for (const indicator of result.truncationIndicators) {
-        if (indicator.position <= lines.length) {
-          lines.splice(indicator.position - 1, 0, `// ${indicator.description}`);
-        }
-      }
+    if (finalConfig.showTruncationIndicators && result.truncationIndicators.length > 0) {
+      const lines = limitedContent.split('\n');
+      const commentPrefix = getTruncationCommentPrefix(filePath);
+      for (const indicator of result.truncationIndicators) {
+        const insertionIndex = Math.min(Math.max(indicator.position - 1, 0), lines.length);
+        lines.splice(insertionIndex, 0, `${commentPrefix}${indicator.description}`);
+      }
       return {
         content: lines.join('\n'),
         truncation: {
           truncated: result.originalLineCount > lineLimit,
@@
     };
   } finally {
     processor.dispose();
   }
 };
+
+function getTruncationCommentPrefix(filePath: string): string {
+  const ext = filePath.split('.').pop()?.toLowerCase();
+  if (!ext) {
+    return '// ';
+  }
+
+  if (['py', 'rb', 'sh', 'bash', 'ps1'].includes(ext)) {
+    return '# ';
+  }
+
+  if (ext === 'sql') {
+    return '-- ';
+  }
+
+  return '// ';
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (finalConfig.showTruncationIndicators && result.truncationIndicators.length > 0) {
const lines = limitedContent.split('\n');
for (const indicator of result.truncationIndicators) {
if (indicator.position <= lines.length) {
lines.splice(indicator.position - 1, 0, `// ${indicator.description}`);
}
if (finalConfig.showTruncationIndicators && result.truncationIndicators.length > 0) {
const lines = limitedContent.split('\n');
const commentPrefix = getTruncationCommentPrefix(filePath);
for (const indicator of result.truncationIndicators) {
const insertionIndex = Math.min(Math.max(indicator.position - 1, 0), lines.length);
lines.splice(insertionIndex, 0, `${commentPrefix}${indicator.description}`);
}
return {
content: lines.join('\n'),
truncation: {
truncated: result.originalLineCount > lineLimit,
}
};
} finally {
processor.dispose();
}
};
function getTruncationCommentPrefix(filePath: string): string {
const ext = filePath.split('.').pop()?.toLowerCase();
if (!ext) {
return '// ';
}
if (['py', 'rb', 'sh', 'bash', 'ps1'].includes(ext)) {
return '# ';
}
if (ext === 'sql') {
return '-- ';
}
return '// ';
}
🤖 Prompt for AI Agents
In src/core/file/lineLimitProcessor.ts around lines 443 to 448, the current
guard uses indicator.position <= lines.length which prevents insertion when
positions are based on the original file and always uses '//' as the prefix;
change to clamp the insert index to the truncated output: compute insertIndex =
Math.max(1, Math.min(indicator.position, lines.length + 1)) and insert at
insertIndex - 1 so indicators at or beyond the end still append; derive a
language-appropriate line comment prefix from the file extension (map common
extensions: .py -> '#', .rb -> '#', .sql -> '--', .sh -> '#',
.js/.ts/.java/.c/.cpp -> '//', etc., with a sensible default) and use that
prefix instead of hardcoded '//' when inserting the indicator comment.

Comment on lines +264 to +294
const content = [
'import React from "react";',
'function App() {',
' return <div>Hello</div>;',
'}',
'export default App;',
].join('\n');

// First call
const startTime1 = Date.now();
const result1 = await processor.applyLineLimit(content, 'test.jsx', {
lineLimit: 3,
preserveStructure: true,
showTruncationIndicators: true,
enableCaching: true,
});
const endTime1 = Date.now();

// Second call (should use cache)
const startTime2 = Date.now();
const result2 = await processor.applyLineLimit(content, 'test.jsx', {
lineLimit: 3,
preserveStructure: true,
showTruncationIndicators: true,
enableCaching: true,
});
const endTime2 = Date.now();

expect(result1.selectedLines).toEqual(result2.selectedLines);
expect(endTime2 - startTime2).toBeLessThan(endTime1 - startTime1); // Second call should be faster
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace timing-based cache assertion

Using wall-clock timings (endTime2 - startTime2) to prove caching is unreliable—noise from the event loop or GC can easily flip the comparison and turn this into a flaky test. Please swap the timing check for a deterministic assertion, e.g. spy on the underlying parser so the second call confirms no extra parse happens:

-      const startTime1 = Date.now();
-      const result1 = await processor.applyLineLimit(content, 'test.jsx', {
-        lineLimit: 3,
-        preserveStructure: true,
-        showTruncationIndicators: true,
-        enableCaching: true,
-      });
-      const endTime1 = Date.now();
-
-      // Second call (should use cache)
-      const startTime2 = Date.now();
-      const result2 = await processor.applyLineLimit(content, 'test.jsx', {
-        lineLimit: 3,
-        preserveStructure: true,
-        showTruncationIndicators: true,
-        enableCaching: true,
-      });
-      const endTime2 = Date.now();
-
-      expect(result1.selectedLines).toEqual(result2.selectedLines);
-      expect(endTime2 - startTime2).toBeLessThan(endTime1 - startTime1); // Second call should be faster
+      await processor.applyLineLimit(content, 'test.jsx', {
+        lineLimit: 3,
+        preserveStructure: true,
+        showTruncationIndicators: true,
+        enableCaching: true,
+      });
+      const parser = (processor as any).languageParser;
+      const parseSpy = vi.spyOn(parser, 'parse');
+
+      const result2 = await processor.applyLineLimit(content, 'test.jsx', {
+        lineLimit: 3,
+        preserveStructure: true,
+        showTruncationIndicators: true,
+        enableCaching: true,
+      });
+
+      expect(result2.selectedLines).toHaveLength(3);
+      expect(parseSpy).not.toHaveBeenCalled();

This keeps the intent while making the suite stable.

🤖 Prompt for AI Agents
In tests/core/file/lineLimitConfig.test.ts around lines 264 to 294, the test
uses wall-clock timing to assert caching which is flaky; replace the
timing-based assertion with a deterministic spy on the underlying parser/cache
entry so you can assert the parser is only invoked once on the two calls. Update
the test to import or access the parser (or processor.parse method), wrap it
with a spy/mock before the first call, call applyLineLimit twice with the same
args, assert result1.selectedLines equals result2.selectedLines, and then assert
the parser/mock was called exactly once (or that cache lookup was used) instead
of comparing endTime durations. Ensure the spy is restored/cleared after the
test.

Comment on lines +44 to +47
await expect(processor.initialize('test.ts')).resolves.not.toThrow();
await expect(processor.initialize('test.js')).resolves.not.toThrow();
await expect(processor.initialize('test.py')).resolves.not.toThrow();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Don’t use toThrow on a resolved promise

await expect(processor.initialize('test.ts')).resolves.not.toThrow() invokes the toThrow matcher on the resolved value (undefined), which immediately fails with “received value must be a function”. Assert the resolved value instead, e.g. await expect(processor.initialize('test.ts')).resolves.toBeUndefined();. Apply the same fix to the .js and .py variants.

🤖 Prompt for AI Agents
In tests/core/file/lineLimitProcessor.test.ts around lines 44 to 47, the test
uses await expect(...).resolves.not.toThrow(), which calls toThrow on the
resolved value (undefined) and fails; replace those three assertions with await
expect(processor.initialize('test.ts')).resolves.toBeUndefined(), await
expect(processor.initialize('test.js')).resolves.toBeUndefined(), and await
expect(processor.initialize('test.py')).resolves.toBeUndefined() so the resolved
promise value is asserted correctly.

Comment on lines +248 to +257
for (auto& user : users) {
if (user.getId() == id) {
return &user;
}
}
}
}
return nullptr;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove stray brace in C++ sample

The UserService::getUser sample has an extra closing brace before return nullptr;, making the snippet invalid C++. That introduces parse errors and defeats the purpose of exercising the strategy against well-formed code. Drop the stray brace so the function structure is valid. For example:

-        }
-        }
-        return nullptr;
+        }
+        return nullptr;
🤖 Prompt for AI Agents
In tests/core/file/lineLimitStrategies/AllLineLimitStrategies.test.ts around
lines 248 to 257, the C++ sample for UserService::getUser contains an extra
closing brace immediately before "return nullptr;" which makes the snippet
invalid; remove that stray closing brace so the function's braces match
correctly and the "return nullptr;" remains inside the function body (verify
surrounding braces still balance for the function and any enclosing
class/namespace).

Comment on lines +591 to +664
test('should identify headers when parsing fails', () => {
const lines = [
'require "json"',
'require "net/http"',
'class UserService',
' def initialize',
' @users = []',
' end',
'end',
];

// Mock parsing failure by using empty tree
const tree = parser.parse('');
if (!tree) throw new Error('Failed to parse code');
const headerLines = strategy.identifyHeaderLines(lines, tree);

expect(headerLines).toContain(0); // require
expect(headerLines).toContain(1); // require
expect(headerLines).toContain(2); // class UserService
expect(headerLines).toContain(3); // def initialize
});

test('should analyze functions when parsing fails', () => {
const lines = [
'class TestClass',
' def simple_method',
' "simple"',
' end',
' ',
' def complex_method(param)',
' if param > 0',
' (1..param).each { |i| puts i }',
' end',
' param',
' end',
'end',
];

// Mock parsing failure by using empty tree
const tree = parser.parse('');
if (!tree) throw new Error('Failed to parse code');
const functions = strategy.analyzeFunctions(lines, tree);

expect(functions).toHaveLength(2);

const simpleMethod = functions.find((f) => f.name === 'simple_method');
expect(simpleMethod).toBeDefined();

const complexMethod = functions.find((f) => f.name === 'complex_method');
expect(complexMethod).toBeDefined();
expect(complexMethod!.complexity).toBeGreaterThan(0.5);
});

test('should identify footers when parsing fails', () => {
const lines = [
'require "json"',
'class Application',
' def run',
' puts "Running..."',
' end',
'end',
'',
'app = Application.new',
'app.run',
];

// Mock parsing failure by using empty tree
const tree = parser.parse('');
if (!tree) throw new Error('Failed to parse code');
const footerLines = strategy.identifyFooterLines(lines, tree);

expect(footerLines).toContain(9); // app = Application.new
expect(footerLines).toContain(10); // app.run
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fallback tests never hit the heuristic path

These “Fallback Heuristics” tests still feed a perfectly valid (albeit empty) tree from parser.parse(''), so identifyHeaderLines/analyzeFunctions/identifyFooterLines never throw, the catch block is never entered, and the heuristic helpers aren’t exercised. As written the expectations will fail because each method returns []. Force the error path (e.g. by passing a mock tree whose language access throws or by spying on the helpers and calling them directly) before asserting heuristic behaviour.

Comment on lines +45 to +236
await expect(runCli([tempDir], tempDir, { line: 10 })).resolves.not.toThrow();

// The test passes if no error is thrown during CLI processing
});

test('should reject invalid line limit values', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");');

// Test with negative line limit
await expect(runCli([tempDir], tempDir, { line: -5 })).rejects.toThrow(RepomixError);

// Test with zero line limit
await expect(runCli([tempDir], tempDir, { line: 0 })).rejects.toThrow(RepomixError);

// Test with non-integer line limit (this should be caught by Commander.js validation)
// We can't directly test this case here since Commander.js validates before our code runs
});

test('should handle line limit with different output formats', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Line 1");\n'.repeat(15));

// Test with XML output
await expect(runCli([tempDir], tempDir, { line: 10, style: 'xml' })).resolves.not.toThrow();

// Test with Markdown output
await expect(runCli([tempDir], tempDir, { line: 10, style: 'markdown' })).resolves.not.toThrow();

// Test with Plain output
await expect(runCli([tempDir], tempDir, { line: 10, style: 'plain' })).resolves.not.toThrow();

// Test with JSON output
await expect(runCli([tempDir], tempDir, { line: 10, style: 'json' })).resolves.not.toThrow();
});

test('should handle line limit with other CLI options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with verbose mode
await expect(runCli([tempDir], tempDir, { line: 10, verbose: true })).resolves.not.toThrow();

// Test with copy to clipboard
await expect(runCli([tempDir], tempDir, { line: 10, copy: true })).resolves.not.toThrow();

// Test with remove comments
await expect(runCli([tempDir], tempDir, { line: 10, removeComments: true })).resolves.not.toThrow();

// Test with remove empty lines
await expect(runCli([tempDir], tempDir, { line: 10, removeEmptyLines: true })).resolves.not.toThrow();

// Test with compress
await expect(runCli([tempDir], tempDir, { line: 10, compress: true })).resolves.not.toThrow();
});

test('should handle line limit with file selection options', async () => {
// Create multiple test files
await fs.writeFile(path.join(tempDir, 'test1.js'), 'console.log("Test 1");\n'.repeat(20));
await fs.writeFile(path.join(tempDir, 'test2.ts'), 'console.log("Test 2");\n'.repeat(20));
await fs.writeFile(path.join(tempDir, 'test3.md'), '# Test 3\n'.repeat(20));

// Test with include pattern
await expect(runCli([tempDir], tempDir, { line: 10, include: '*.js' })).resolves.not.toThrow();

// Test with ignore pattern
await expect(runCli([tempDir], tempDir, { line: 10, ignore: '*.md' })).resolves.not.toThrow();

// Test with no gitignore
await expect(runCli([tempDir], tempDir, { line: 10, gitignore: false })).resolves.not.toThrow();

// Test with no default patterns
await expect(runCli([tempDir], tempDir, { line: 10, defaultPatterns: false })).resolves.not.toThrow();
});

test('should handle line limit with output options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with custom output file
const outputFile = path.join(tempDir, 'custom-output.xml');
await expect(runCli([tempDir], tempDir, { line: 10, output: outputFile })).resolves.not.toThrow();

// Test with stdout
await expect(runCli([tempDir], tempDir, { line: 10, stdout: true })).resolves.not.toThrow();

// Test with show line numbers
await expect(runCli([tempDir], tempDir, { line: 10, outputShowLineNumbers: true })).resolves.not.toThrow();

// Test with parsable style
await expect(runCli([tempDir], tempDir, { line: 10, parsableStyle: true })).resolves.not.toThrow();
});

test('should handle line limit with security options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with security check disabled
await expect(runCli([tempDir], tempDir, { line: 10, securityCheck: false })).resolves.not.toThrow();
});

test('should handle line limit with git options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with no git sort by changes
await expect(runCli([tempDir], tempDir, { line: 10, gitSortByChanges: false })).resolves.not.toThrow();

// Test with include diffs
await expect(runCli([tempDir], tempDir, { line: 10, includeDiffs: true })).resolves.not.toThrow();

// Test with include logs
await expect(runCli([tempDir], tempDir, { line: 10, includeLogs: true })).resolves.not.toThrow();

// Test with include logs count
await expect(runCli([tempDir], tempDir, { line: 10, includeLogsCount: 25 })).resolves.not.toThrow();
});

test('should handle line limit with token count options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with token count encoding
await expect(runCli([tempDir], tempDir, { line: 10, tokenCountEncoding: 'cl100k_base' })).resolves.not.toThrow();

// Test with token count tree
await expect(runCli([tempDir], tempDir, { line: 10, tokenCountTree: true })).resolves.not.toThrow();

// Test with token count tree threshold
await expect(runCli([tempDir], tempDir, { line: 10, tokenCountTree: 100 })).resolves.not.toThrow();
});

test('should handle line limit with top files length option', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with custom top files length
await expect(runCli([tempDir], tempDir, { line: 10, topFilesLen: 20 })).resolves.not.toThrow();
});

test('should handle line limit with header text option', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with custom header text
await expect(runCli([tempDir], tempDir, { line: 10, headerText: 'Custom Header Text' })).resolves.not.toThrow();
});

test('should handle line limit with instruction file path option', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

const instructionFile = path.join(tempDir, 'instructions.txt');
await fs.writeFile(instructionFile, 'Custom instructions for AI');

// Test with instruction file path
await expect(runCli([tempDir], tempDir, { line: 10, instructionFilePath: instructionFile })).resolves.not.toThrow();
});

test('should handle line limit with directory structure options', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with include empty directories
await expect(runCli([tempDir], tempDir, { line: 10, includeEmptyDirectories: true })).resolves.not.toThrow();

// Test with include full directory structure
await expect(runCli([tempDir], tempDir, { line: 10, includeFullDirectoryStructure: true })).resolves.not.toThrow();
});

test('should handle line limit with truncate base64 option', async () => {
const testFile = path.join(tempDir, 'test.js');
await fs.writeFile(testFile, 'console.log("Hello World");\n'.repeat(20));

// Test with truncate base64
await expect(runCli([tempDir], tempDir, { line: 10, truncateBase64: true })).resolves.not.toThrow();
});

test('should handle line limit with multiple directories', async () => {
// Create multiple directories with test files
const dir1 = path.join(tempDir, 'dir1');
const dir2 = path.join(tempDir, 'dir2');

await fs.mkdir(dir1, { recursive: true });
await fs.mkdir(dir2, { recursive: true });

await fs.writeFile(path.join(dir1, 'test1.js'), 'console.log("Dir 1");\n'.repeat(20));
await fs.writeFile(path.join(dir2, 'test2.js'), 'console.log("Dir 2");\n'.repeat(20));

// Test with multiple directories
await expect(runCli([dir1, dir2], tempDir, { line: 10 })).resolves.not.toThrow();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix async assertion: resolves.not.toThrow() will always fail

Each await expect(runCli(...)).resolves.not.toThrow(); call is invalid because toThrow expects a function. When the promise resolves, Jest/Vitest passes the resolved value (undefined) into toThrow, which immediately errors with “received value must be a function,” so these tests will never pass. Swap to either asserting on the resolved value or wrapping the call:

-    await expect(runCli([tempDir], tempDir, { line: 10 })).resolves.not.toThrow();
+    await expect(runCli([tempDir], tempDir, { line: 10 })).resolves.toBeUndefined();

Apply the same pattern everywhere you’re using .resolves.not.toThrow().

🤖 Prompt for AI Agents
In tests/integration-tests/cliLineLimit.test.ts around lines 45-236, all uses of
await expect(runCli(...)).resolves.not.toThrow() are invalid because toThrow
expects a function; replace each .resolves.not.toThrow() with
.resolves.toBeUndefined() (or simply await runCli(...) directly) so the promise
resolution is asserted correctly; apply this change to every occurrence in the
file while leaving rejects.toThrow() checks untouched.

@bramburn
Copy link
Author

bramburn commented Nov 3, 2025

these reviews with AI are really good!! working on those changes

@bramburn
Copy link
Author

bramburn commented Nov 6, 2025

I'll work on it when i get some time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant