Skip to content

fix: restore UI resizing and filtering + add cross-platform QA gate#24

Merged
Mehdi-Bl merged 3 commits into
mainfrom
fix/ui-filter-qa-gate
Feb 8, 2026
Merged

fix: restore UI resizing and filtering + add cross-platform QA gate#24
Mehdi-Bl merged 3 commits into
mainfrom
fix/ui-filter-qa-gate

Conversation

@Mehdi-Bl

@Mehdi-Bl Mehdi-Bl commented Feb 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • restore default filtering behavior so custom excludes/includes and .gitignore are wired correctly again
  • fix renderer layout to use responsive/flex sizing instead of fixed-height panes
  • add a QA matrix workflow for Linux/Windows/macOS that runs lint/tests/build and uploads UI screenshots

Validation

  • npm run lint
  • npm test -- --runInBand
  • npm run build:ts
  • npm run build:css
  • npm run build:webpack
  • npm run qa:screenshot

Summary by Sourcery

Restore default file filtering behavior and improve the renderer layout to be fully responsive while adding cross-platform QA automation with UI screenshot capture.

Bug Fixes:

  • Fix file extension and exclude pattern handling so custom includes/excludes and .gitignore apply by default and interact correctly.
  • Adjust renderer and tab layouts to use flexible, scrollable panels that fill the viewport instead of fixed-height content.

Enhancements:

  • Normalize include extension matching to be case-insensitive and simplify filter utility tests.
  • Improve Electron main process filtering setup by using an empty pattern bundle default instead of a placeholder entry.

Build:

  • Add a Playwright-based script and npm command to serve the renderer bundle and capture UI screenshots for QA.

CI:

  • Introduce a GitHub Actions QA matrix workflow across Linux, Windows, and macOS that runs linting, tests, builds, and uploads UI screenshots.

Tests:

  • Extend filter-utils unit tests to cover default include/exclude behavior and interaction with gitignore patterns.

Summary by CodeRabbit

Release Notes

  • Improvements

    • Enhanced layout responsiveness with flexible viewport-based sizing for better full-screen experience
    • Improved scrolling behavior and content area flexibility across tabs and components
    • Refined filter pattern handling with improved default behavior for include/exclude logic
  • Chores

    • Added QA testing infrastructure with automated UI screenshot capture
    • Added testing dependency to support quality assurance workflows
  • Tests

    • Expanded test coverage for default filter configurations and edge cases

@sourcery-ai

sourcery-ai Bot commented Feb 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

Restores default file filtering semantics (custom includes/excludes and .gitignore), converts the renderer layout to a fully flex-based, viewport-height UI, and introduces a cross-platform QA GitHub Actions workflow that builds, tests, and captures Playwright-based UI screenshots.

Sequence diagram for the new cross-platform UI screenshot capture

sequenceDiagram
  actor Developer
  participant GitHubActionsRunner as GitHubActionsRunner
  participant NodeQAJob as Node_QA_job
  participant CaptureScript as capture_ui_screenshot_js
  participant StaticServer as Static_HTTP_Server
  participant Playwright as Playwright_chromium
  participant RendererFiles as Renderer_src_renderer
  participant ScreenshotFile as dist_qa_screenshots

  Developer->>GitHubActionsRunner: push_or_PR_to_main
  GitHubActionsRunner->>NodeQAJob: start_QA_matrix_job(os=ubuntu/windows/macos)

  NodeQAJob->>NodeQAJob: npm_ci / lint / test / build
  NodeQAJob->>CaptureScript: npm_run_qa_colon_screenshot

  CaptureScript->>StaticServer: createStaticServer()
  StaticServer-->>CaptureScript: server_listening_on_PORT

  CaptureScript->>Playwright: chromium.launch(headless=true)
  Playwright-->>CaptureScript: browser_instance
  CaptureScript->>Playwright: newPage(viewport=1440x900)

  Playwright->>StaticServer: GET_/index.html
  StaticServer->>RendererFiles: read(index.html)
  RendererFiles-->>StaticServer: HTML_content
  StaticServer-->>Playwright: 200_index.html

  Playwright->>StaticServer: GET_/bundle.js_and_assets
  StaticServer->>RendererFiles: read(static_assets)
  RendererFiles-->>StaticServer: asset_bytes
  StaticServer-->>Playwright: 200_assets

  Playwright->>Playwright: waitForSelector(#app)
  Playwright->>Playwright: waitForTimeout(1000ms)
  Playwright->>ScreenshotFile: screenshot(fullPage=true,path=SCREENSHOT_PATH)

  Playwright-->>CaptureScript: close_page_and_browser
  StaticServer-->>CaptureScript: server_closed

  CaptureScript-->>NodeQAJob: exit_code_0_or_1
  NodeQAJob->>GitHubActionsRunner: upload_artifact(ui-screenshot-${runner.os})
Loading

Class diagram for updated filtering configuration and utilities

classDiagram
  class ConfigObject {
    +boolean use_custom_includes [optional]
    +boolean use_custom_excludes [optional]
    +boolean use_gitignore [optional]
    +string[] include_extensions [optional]
    +string[] exclude_patterns [optional]
  }

  class FilterPatternBundle {
    string[] array_base (array base)
    string[] includePatterns [optional]
    string[] includeExtensions [optional]
  }

  class filter_utils {
    +getRelativePath(filePath string, rootPath string) string
    +shouldExcludeByExtension(itemPath string, config ConfigObject) boolean
    +shouldExclude(itemPath string, rootPath string, config ConfigObject, gitignorePath string) boolean
    +matchesExcludePatterns(normalizedPath string, itemName string, patterns string[]) boolean
  }

  ConfigObject "1" --> "0..1" FilterPatternBundle : derives_excludePatterns

  filter_utils --> ConfigObject : reads_filter_settings
  filter_utils --> FilterPatternBundle : builds_customExcludes

  %% Key behavioral changes
  class shouldExcludeByExtension {
    +useCustomIncludes = config.use_custom_includes != false
    +lowercase include_extensions
    +return true if extension not in include_extensions
  }

  class shouldExclude {
    +useCustomExcludes = config.use_custom_excludes != false
    +customExcludes = useCustomExcludes ? exclude_patterns : []
    +always apply customExcludes when length > 0
    +filter gitignore patterns against customExcludes
  }
Loading

File-Level Changes

Change Details Files
Normalize extension/custom include/exclude and .gitignore behavior in filtering utilities and tests.
  • Treat custom include extensions as enabled by default unless explicitly disabled and compare extensions case-insensitively.
  • Default custom exclude patterns to enabled unless explicitly disabled; centralize exclude pattern bundle and avoid overlapping gitignore patterns.
  • Adjust shouldExclude tests to remove brittle path.extname mocking and add coverage for default include/exclude behaviors and gitignore precedence.
src/utils/filter-utils.ts
src/main/index.ts
tests/unit/utils/filter-utils.test.ts
Refactor renderer layout to use flexbox and viewport-height sizing for scrollable, resizable panes.
  • Make the root app container and main panel flex-based with full viewport height, moving scrolling into inner content regions.
  • Update SourceTab, FileTree, and ProcessedTab containers to be flex columns with min-h-0 and vh-based max heights so trees and content areas scroll independently without fixed pixel constraints.
  • Adjust global styles and HTML body/app wrappers to remove hard-coded tab-content min-height and ensure the entire app occupies the full screen height with overflow managed at content panes.
src/renderer/components/App.tsx
src/renderer/components/SourceTab.tsx
src/renderer/components/FileTree.tsx
src/renderer/components/ProcessedTab.tsx
src/renderer/index.html
src/renderer/styles.css
Add a cross-platform QA workflow that builds, tests, and captures UI screenshots using Playwright.
  • Introduce a Node script that serves the built renderer via a simple static HTTP server and uses Playwright Chromium to capture a full-page UI screenshot into a dist/qa/screenshots directory.
  • Wire a new npm script qa:screenshot and add Playwright as a devDependency, as well as minor package.json devDependency ordering cleanups.
  • Create a GitHub Actions QA Matrix workflow that runs on Linux/Windows/macOS, performing lint, tests, TypeScript/CSS/webpack builds, installs Playwright per-OS, runs the screenshot script, and uploads the screenshots as artifacts.
scripts/capture-ui-screenshot.js
.github/workflows/qa-matrix.yml
package.json
package-lock.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Feb 8, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 6.4
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 57 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 6branch protection is not maximal on development and all release branches
Vulnerabilities🟢 73 existing vulnerabilities detected
SAST🟢 8SAST tool detected but not run on all commits
actions/actions/setup-node 6044e13b5dc448c55e2357c09f80417699197238 🟢 5.7
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 810 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 8
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 9binaries present in source code
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 1branch protection is not maximal on development and all release branches
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
Vulnerabilities🟢 46 existing vulnerabilities detected
actions/actions/upload-artifact b7c566a772e6b6bfb58ed0dc250532a479d7789f 🟢 6.2
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Code-Review🟢 10all changesets reviewed
Maintained🟢 1027 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Vulnerabilities🟢 64 existing vulnerabilities detected
SAST🟢 10SAST tool is run on all commits
npm/fsevents 2.3.2 🟢 3.7
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 3Found 7/22 approved changesets -- score normalized to 3
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Vulnerabilities🟢 100 existing vulnerabilities detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/playwright 1.58.2 🟢 6.5
Details
CheckScoreReason
Maintained🟢 1030 commit(s) out of 30 and 6 issue activity out of 30 found in the last 90 days -- score normalized to 10
Code-Review🟢 9GitHub code reviews found for 29 commits out of the last 30 -- score normalized to 9
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 10security policy file detected
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Binary-Artifacts🟢 6binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
Fuzzing⚠️ 0project is not fuzzed
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Branch-Protection🟢 3branch protection is not maximal on development and all release branches
npm/playwright-core 1.58.2 🟢 6.5
Details
CheckScoreReason
Maintained🟢 1030 commit(s) out of 30 and 6 issue activity out of 30 found in the last 90 days -- score normalized to 10
Code-Review🟢 9GitHub code reviews found for 29 commits out of the last 30 -- score normalized to 9
CII-Best-Practices⚠️ 0no badge detected
Vulnerabilities🟢 10no vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 10security policy file detected
License🟢 10license file detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1no published package detected
Token-Permissions⚠️ 0non read-only tokens detected in GitHub workflows
Binary-Artifacts🟢 6binaries present in source code
Dependency-Update-Tool🟢 10update tool detected
Fuzzing⚠️ 0project is not fuzzed
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Branch-Protection🟢 3branch protection is not maximal on development and all release branches

Scanned Files

  • .github/workflows/qa-matrix.yml
  • package-lock.json

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Restore filtering behavior, fix responsive UI layout, and add cross-platform QA gate

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Restore default filtering behavior for custom excludes/includes and .gitignore patterns
• Fix UI layout to use responsive flex sizing instead of fixed-height panes
• Add cross-platform QA workflow matrix for Linux/Windows/macOS testing
• Add UI screenshot capture script with Playwright for visual regression testing
Diagram
flowchart LR
  A["Filter Logic"] -->|"Default behavior"| B["shouldExclude Function"]
  B -->|"Applies by default"| C["Custom Excludes"]
  B -->|"Applies by default"| D["Include Extensions"]
  B -->|"Applies by default"| E["Gitignore Patterns"]
  F["UI Components"] -->|"Responsive flex layout"| G["App Container"]
  G -->|"Full height"| H["Tab Content"]
  H -->|"Flexible sizing"| I["FileTree & ProcessedTab"]
  J["QA Workflow"] -->|"Multi-platform"| K["Linux/Windows/macOS"]
  K -->|"Runs tests & builds"| L["Capture Screenshots"]
  L -->|"Upload artifacts"| M["Screenshot Storage"]
Loading

Grey Divider

File Changes

1. src/main/index.ts ✨ Enhancement +3/-2

Define FilterPatternBundle type for filter patterns

src/main/index.ts


2. src/utils/filter-utils.ts 🐞 Bug fix +12/-11

Restore default filtering behavior for excludes/includes

src/utils/filter-utils.ts


3. tests/unit/utils/filter-utils.test.ts 🧪 Tests +36/-25

Add tests for default filtering behavior

tests/unit/utils/filter-utils.test.ts


View more (9)
4. scripts/capture-ui-screenshot.js ✨ Enhancement +91/-0

Add Playwright-based UI screenshot capture script

scripts/capture-ui-screenshot.js


5. src/renderer/index.html 🐞 Bug fix +4/-2

Fix body and app container for full-height layout

src/renderer/index.html


6. src/renderer/styles.css 🐞 Bug fix +0/-4

Remove fixed min-height constraint from tab content

src/renderer/styles.css


7. .github/workflows/qa-matrix.yml ✨ Enhancement +71/-0

Add cross-platform QA matrix workflow with screenshots

.github/workflows/qa-matrix.yml


8. package.json Dependencies +7/-5

Add Playwright dependency and qa:screenshot script

package.json


9. src/renderer/components/App.tsx 🐞 Bug fix +3/-3

Convert to flex layout with responsive sizing

src/renderer/components/App.tsx


10. src/renderer/components/FileTree.tsx 🐞 Bug fix +2/-2

Apply flex layout for responsive file tree sizing

src/renderer/components/FileTree.tsx


11. src/renderer/components/ProcessedTab.tsx 🐞 Bug fix +2/-2

Use viewport-relative heights for content sections

src/renderer/components/ProcessedTab.tsx


12. src/renderer/components/SourceTab.tsx 🐞 Bug fix +3/-3

Apply flex layout for responsive source tab layout

src/renderer/components/SourceTab.tsx


Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Feb 8, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Mehdi-Bl has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

This pull request introduces a new GitHub Actions QA workflow for cross-platform testing with automated screenshot capture, reorganizes layout styling for responsive design across multiple React components, and refactors filter pattern logic to change default behavior and simplify conditional handling.

Changes

Cohort / File(s) Summary
QA Infrastructure
.github/workflows/qa-matrix.yml, scripts/capture-ui-screenshot.js, package.json
Adds GitHub Actions workflow running matrix tests across ubuntu, windows, and macos; introduces Playwright dependency and Node script to capture full-page UI screenshots with OS-specific naming and artifact storage.
Layout & Responsive Design
src/renderer/components/App.tsx, src/renderer/components/FileTree.tsx, src/renderer/components/ProcessedTab.tsx, src/renderer/components/SourceTab.tsx, src/renderer/index.html, src/renderer/styles.css
Updates container and content styling from fixed heights to flexbox-based responsive layouts with viewport-relative heights (e.g., max-h-[45vh]), enabling better full-screen rendering and scrolling behavior. Removes fixed min-height constraint from .tab-content.
Filter Pattern Logic & Types
src/main/index.ts, src/utils/filter-utils.ts, tests/unit/utils/filter-utils.test.ts
Extracts FilterPatternBundle type alias, changes excludePatterns default from [''] to [], refactors inclusion/exclusion conditions to default to custom rules (use_custom_excludes defaults to true), and adds test coverage for undefined config flags and gitignore interaction scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 The rabbit builds with screenshots bright,
Responsive layouts, flexing right,
Filters simplified, defaults now true,
QA matrices tested through and through!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the three main changes: fixing UI resizing, restoring filtering behavior, and adding cross-platform QA automation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/ui-filter-qa-gate

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
Copy Markdown

Summary of Changes

Hello @Mehdi-Bl, 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 addresses critical functional and UI issues by rectifying file filtering logic and implementing a more robust, responsive layout for the application's user interface. Additionally, it significantly boosts the project's quality assurance process by integrating a new cross-platform UI screenshot capture mechanism, which will help prevent future regressions and ensure consistent visual presentation across different operating systems.

Highlights

  • Filtering Logic Restoration: The pull request restores the intended behavior of file filtering, ensuring that custom exclude/include patterns and .gitignore rules are correctly applied. This fixes issues where these configurations were not being respected.
  • Responsive UI Layout Fixes: The user interface has been updated to use responsive and flexible sizing (Flexbox and Tailwind CSS utility classes) instead of fixed-height panes. This improves the UI's adaptability and resizing capabilities.
  • Cross-Platform QA Gate with Playwright: A new cross-platform QA workflow has been introduced, utilizing Playwright to capture UI screenshots on Linux, Windows, and macOS. This enhances automated testing and visual regression capabilities.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • package-lock.json
    • Added playwright and playwright-core as dev dependencies.
    • Added fsevents as an optional dependency for playwright on macOS.
  • package.json
    • Added playwright as a dev dependency.
    • Introduced a new qa:screenshot script to trigger UI screenshot capture.
  • scripts/capture-ui-screenshot.js
    • New file added to implement a Node.js script that launches a static HTTP server, uses Playwright (Chromium) to navigate to the application's index.html, waits for the UI to render, and captures a full-page screenshot.
    • The script supports environment variables for screenshot name and port.
  • src/main/index.ts
    • Defined a new type FilterPatternBundle for better type safety in filtering logic.
    • Modified the initialization of excludePatterns to an empty array, ensuring correct default behavior for filtering.
  • src/renderer/components/App.tsx
    • Updated the main container div to use Flexbox (flex, flex-col) and occupy full screen height (h-screen, w-full, max-w-screen-2xl) for responsive layout.
    • Modified the tab content container to be flexible (flex, min-h-0, flex-1) and allow vertical scrolling (overflow-y-auto).
  • src/renderer/components/FileTree.tsx
    • Updated the file-tree container to use Flexbox (flex, flex-col, min-h-0, flex-1) for better layout management.
    • Modified the content area of the file tree to be flexible (flex-1, min-h-0) and allow scrolling (overflow-auto).
  • src/renderer/components/ProcessedTab.tsx
    • Adjusted the processed-content area to use dynamic height (max-h-[45vh], min-h-48) instead of a fixed max-h-96.
    • Updated the "Files by Token Count" table container to use dynamic height (h-[35vh], min-h-48, max-h-[45vh]) for improved responsiveness.
  • src/renderer/components/SourceTab.tsx
    • Updated the main container div to use Flexbox (flex, h-full, min-h-0, flex-col).
    • Modified the directory tree container to be flexible (flex, min-h-0, flex-1, flex-col).
    • Updated the file/folder selection div to be flexible (flex, min-h-0, flex-1).
  • src/renderer/index.html
    • Added h-screen and overflow-hidden CSS classes to the body tag to ensure the body takes up the full viewport height and prevents unwanted scrolling.
    • Added h-full to the #app div to make it occupy the full height of its parent.
  • src/renderer/styles.css
    • Removed the fixed min-height: 500px; from the .tab-content class, allowing the new Flexbox-based layout to manage its height responsively.
  • src/utils/filter-utils.ts
    • Refined shouldExcludeByExtension logic to correctly handle use_custom_includes being undefined (defaulting to true) and ensuring include_extensions is not empty. It also now normalizes extensions to lowercase for consistent matching.
    • Modified shouldExclude to correctly apply custom excludes by default when use_custom_excludes is undefined (defaulting to true).
    • Improved the filtering of gitignoreExcludes to correctly exclude patterns that are also present in customExcludes.
  • tests/unit/utils/filter-utils.test.ts
    • Removed redundant jest.spyOn(path, 'extname') mocks and their restorations, as the shouldExcludeByExtension logic was updated to handle extensions directly.
    • Added new test cases to verify the default behavior of use_custom_includes and use_custom_excludes when they are undefined.
    • Added a test case to ensure gitignore excludes remain active even when custom excludes are explicitly disabled.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/qa-matrix.yml
Activity
  • The author, Mehdi-Bl, has provided a detailed summary and validation steps, indicating local testing was performed using npm run lint, npm test -- --runInBand, npm run build:ts, npm run build:css, npm run build:webpack, and npm run qa:screenshot. This suggests a thorough self-review and verification process before submitting the pull request.
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.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `tests/unit/utils/filter-utils.test.ts:111` </location>
<code_context>
+      expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(true);
     });

     test('should include files with matching extensions when use_custom_includes is true', () => {
</code_context>

<issue_to_address>
**suggestion (testing):** Add a test to verify extension matching is case-insensitive for both config and file extension

The code now lowercases both the file extension and `include_extensions`, but there’s no test covering mixed-case values (e.g. `.JS` on disk or `'.JS'` in config). Please add a test like the one below to exercise this behavior and guard against regressions:

```ts
test('should treat include_extensions as case-insensitive', () => {
  const itemPath = '/project/src/FILE.JS';
  const rootPath = '/project';
  const excludePatterns: string[] = [];
  const config = {
    use_custom_includes: true,
    include_extensions: ['.Js'],
  };

  expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
});
```

```suggestion
    test('should include files with matching extensions when use_custom_includes is true', () => {
      expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
    });

    test('should treat include_extensions as case-insensitive', () => {
      const itemPath = '/project/src/FILE.JS';
      const rootPath = '/project';
      const excludePatterns: string[] = [];
      const config = {
        use_custom_includes: true,
        include_extensions: ['.Js'],
      };

      expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
    });

    test('should apply include extension filtering by default when use_custom_includes is undefined', () => {
```
</issue_to_address>

### Comment 2
<location> `tests/unit/utils/filter-utils.test.ts:134-136` </location>
<code_context>
       expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
     });

+    test('should apply custom excludes by default when use_custom_excludes is undefined', () => {
+      const itemPath = '/project/build/output.log';
+      const rootPath = '/project';
+      const excludePatterns = [];
+      const config = {
+        exclude_patterns: ['**/*.log'],
+      };
+
+      expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(true);
+    });
+
</code_context>

<issue_to_address>
**suggestion (testing):** Add a test that covers the default behavior of gitignore filtering when `use_gitignore` is undefined

You’ve added coverage for explicit `use_gitignore` values and defaulted custom includes/excludes. Please also add a test that verifies gitignore excludes are applied when `use_gitignore` is omitted, mirroring the new defaulted custom-excludes test so the default gitignore behavior is explicitly locked in.

```suggestion
    test('should exclude files that match gitignore patterns when use_gitignore is true', () => {
      const itemPath = '/project/logs/error.log';
      const rootPath = '/project';
      expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
    });

    test('should apply gitignore excludes by default when use_gitignore is undefined', () => {
      const itemPath = '/project/logs/error.log';
      const rootPath = '/project';
      const configWithDefaultGitignore = { ...config, use_gitignore: undefined };

      expect(shouldExclude(itemPath, rootPath, excludePatterns, configWithDefaultGitignore)).toBe(true);
    });
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(true);
});

test('should include files with matching extensions when use_custom_includes is true', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (testing): Add a test to verify extension matching is case-insensitive for both config and file extension

The code now lowercases both the file extension and include_extensions, but there’s no test covering mixed-case values (e.g. .JS on disk or '.JS' in config). Please add a test like the one below to exercise this behavior and guard against regressions:

test('should treat include_extensions as case-insensitive', () => {
  const itemPath = '/project/src/FILE.JS';
  const rootPath = '/project';
  const excludePatterns: string[] = [];
  const config = {
    use_custom_includes: true,
    include_extensions: ['.Js'],
  };

  expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
});
Suggested change
test('should include files with matching extensions when use_custom_includes is true', () => {
test('should include files with matching extensions when use_custom_includes is true', () => {
expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
});
test('should treat include_extensions as case-insensitive', () => {
const itemPath = '/project/src/FILE.JS';
const rootPath = '/project';
const excludePatterns: string[] = [];
const config = {
use_custom_includes: true,
include_extensions: ['.Js'],
};
expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
});
test('should apply include extension filtering by default when use_custom_includes is undefined', () => {

Comment on lines 134 to 136
test('should exclude files that match gitignore patterns when use_gitignore is true', () => {
const itemPath = '/project/logs/error.log';
const rootPath = '/project';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (testing): Add a test that covers the default behavior of gitignore filtering when use_gitignore is undefined

You’ve added coverage for explicit use_gitignore values and defaulted custom includes/excludes. Please also add a test that verifies gitignore excludes are applied when use_gitignore is omitted, mirroring the new defaulted custom-excludes test so the default gitignore behavior is explicitly locked in.

Suggested change
test('should exclude files that match gitignore patterns when use_gitignore is true', () => {
const itemPath = '/project/logs/error.log';
const rootPath = '/project';
test('should exclude files that match gitignore patterns when use_gitignore is true', () => {
const itemPath = '/project/logs/error.log';
const rootPath = '/project';
expect(shouldExclude(itemPath, rootPath, excludePatterns, config)).toBe(false);
});
test('should apply gitignore excludes by default when use_gitignore is undefined', () => {
const itemPath = '/project/logs/error.log';
const rootPath = '/project';
const configWithDefaultGitignore = { ...config, use_gitignore: undefined };
expect(shouldExclude(itemPath, rootPath, excludePatterns, configWithDefaultGitignore)).toBe(true);
});

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

Copy link
Copy Markdown

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 is a significant improvement, successfully restoring file filtering logic and refactoring the UI to be fully responsive with a flexbox layout. The addition of a Playwright-based QA script for capturing UI screenshots across different platforms is also a valuable enhancement for ensuring visual consistency. My review includes two suggestions: one to make the new QA script more robust by avoiding fixed delays, and another to improve the layout of the 'Processed' tab to be more consistent with the new flex-based design and prevent potential layout issues.

try {
await page.goto(`http://127.0.0.1:${PORT}/index.html`, { waitUntil: 'networkidle' });
await page.waitForSelector('#app', { timeout: 10000 });
await page.waitForTimeout(1000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using a fixed waitForTimeout can lead to flaky tests. If the UI takes longer than 1 second to render (e.g., on a slower machine), the screenshot might be captured prematurely. Conversely, the script waits unnecessarily if the UI renders faster.

A better practice is to wait for a specific element to be visible, which ensures the UI is ready before capturing the screenshot. This makes the test more robust and efficient.

Suggested change
await page.waitForTimeout(1000);
await page.waitForSelector('#app > div', { state: 'visible', timeout: 10000 });

<div
id='processed-content'
className='max-h-96 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
className='max-h-[45vh] min-h-48 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using viewport height units (vh) within a scrollable flex container can lead to layout issues like double scrollbars or content being cut off. This is because vh units are relative to the viewport, not the parent container.

To align with the other responsive improvements in this PR, I recommend refactoring this component to use a flex column layout. This would make the "Processed Content" and "Files by Token Count" sections properly share the available space.

Here's an example of how you could restructure the component:

// Make the root div a flex container that fills the height
<div className='flex h-full min-h-0 flex-col'>
  {/* ...action buttons... */}

  {/* Make content sections flexible */}
  <div className='mb-4 flex flex-1 flex-col min-h-0'>
    {/* ...label... */}
    <div id='processed-content' className='flex-1 min-h-0 overflow-auto ...'>
      {/* ...pre... */}
    </div>
  </div>

  <div className='mt-6 flex flex-1 flex-col min-h-0'>
    {/* ...h3... */}
    <div className='flex-1 min-h-0 overflow-y-auto ...'>
      {/* ...table... */}
    </div>
  </div>
</div>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/main/index.ts (1)

128-174: ⚠️ Potential issue | 🔴 Critical

Spread operator drops custom properties from FilterPatternBundle.

When excludePatterns is reassigned via spread on Line 146 or Line 162, it creates a plain string[], discarding any .includeExtensions or .includePatterns properties previously attached to the old reference. Specifically, if includeExtensions is set on Line 155 and then gitignore patterns are merged on Line 162, the new array loses .includeExtensions.

Consider using a proper object to hold these separate concerns instead of augmenting an array:

Proposed refactor
-type FilterPatternBundle = string[] & { includePatterns?: string[]; includeExtensions?: string[] };
+interface FilterPatternBundle {
+  excludePatterns: string[];
+  includePatterns: string[];
+  includeExtensions: string[];
+}

 // ...

-let excludePatterns: FilterPatternBundle = [];
+let filterBundle: FilterPatternBundle = {
+  excludePatterns: [],
+  includePatterns: [],
+  includeExtensions: [],
+};

Then accumulate into the separate arrays without risk of property loss on spread.

🤖 Fix all issues with AI agents
In `@package.json`:
- Line 162: The package.json lists "playwright": "^1.58.2" which is invalid
because 1.58.2 doesn't exist; update the dependency to "playwright": "^1.58.1"
in the package.json (locate the "playwright" entry) and then run your package
manager (npm install or yarn install) to update lockfiles and ensure
consistency.

In `@src/renderer/components/FileTree.tsx`:
- Line 275: The FileTree root div currently applies rounded-md border
border-gray-200 dark:border-gray-700 which duplicates the identical classes
applied by the parent container in SourceTab; remove the duplicated border
styling from one side—either delete the border and rounded classes from the
FileTree root div in component FileTree (the div with className 'file-tree ...')
or remove them from the parent wrapper in SourceTab (the div that wraps FileTree
and also has rounded-md border border-gray-200 dark:border-gray-700 shadow-sm)
so only one element retains the border/rounded classes to avoid the double
border.
🧹 Nitpick comments (3)
src/renderer/components/ProcessedTab.tsx (1)

214-214: max-h-[45vh] is effectively unused here.

With h-[35vh], the element's height is fixed at 35vh. The max-h-[45vh] constraint can never be reached since h-[35vh] already sets it to a smaller value. If the intent is to let the table grow up to 45vh, consider replacing h-[35vh] with min-h-[35vh] or removing the redundant max-h.

src/main/index.ts (1)

180-182: Redundant YAML parse — config is parsed twice.

The config is already parsed at Lines 130–132 inside the same handler scope. This second parse on Lines 180–182 is redundant and wasteful. Hoist the first config declaration to the outer scope (or reuse it) instead of re-parsing.

.github/workflows/qa-matrix.yml (1)

23-24: Pinned action SHAs are a good security practice.

Consider adding a comment with the version tag next to each SHA for maintainability (e.g., # v4.2.2), so future maintainers can easily identify which version is pinned.

Comment thread package.json
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^15.2.2",
"playwright": "^1.58.2",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

playwright npm package latest version 2026

💡 Result:

As of February 8, 2026, the latest stable version of the playwright npm package is 1.58.1. [1]

If you’re looking at pre-releases, there are newer 1.59.0-alpha builds available. [2]

Sources: [1] [2]


Update playwright version from ^1.58.2 to ^1.58.1.

Playwright version 1.58.2 does not exist. The latest stable version as of February 2026 is 1.58.1.

🤖 Prompt for AI Agents
In `@package.json` at line 162, The package.json lists "playwright": "^1.58.2"
which is invalid because 1.58.2 doesn't exist; update the dependency to
"playwright": "^1.58.1" in the package.json (locate the "playwright" entry) and
then run your package manager (npm install or yarn install) to update lockfiles
and ensure consistency.


return (
<div className='file-tree rounded-md border border-gray-200 dark:border-gray-700'>
<div className='file-tree flex min-h-0 flex-1 flex-col rounded-md border border-gray-200 dark:border-gray-700'>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find FileTree usage in SourceTab and check the structure
rg -n 'FileTree' --type=tsx -B3 -A3 src/renderer/components/SourceTab.tsx

Repository: codingworkflow/ai-code-fusion

Length of output: 100


🏁 Script executed:

# Check the specific area in FileTree.tsx around line 275
sed -n '270,280p' src/renderer/components/FileTree.tsx

Repository: codingworkflow/ai-code-fusion

Length of output: 621


🏁 Script executed:

# Check SourceTab.tsx around line 395
sed -n '390,400p' src/renderer/components/SourceTab.tsx

Repository: codingworkflow/ai-code-fusion

Length of output: 436


Remove duplicate border styling between FileTree and parent container.

The FileTree root element (line 275) has rounded-md border border-gray-200 dark:border-gray-700, and its parent container in SourceTab.tsx (line 395-399) wraps it with identical border classes rounded-md border border-gray-200 dark:border-gray-700 shadow-sm. This creates a visually doubled border.

Remove the border classes from one of the two elements—either from the FileTree root or the parent div in SourceTab.

🤖 Prompt for AI Agents
In `@src/renderer/components/FileTree.tsx` at line 275, The FileTree root div
currently applies rounded-md border border-gray-200 dark:border-gray-700 which
duplicates the identical classes applied by the parent container in SourceTab;
remove the duplicated border styling from one side—either delete the border and
rounded classes from the FileTree root div in component FileTree (the div with
className 'file-tree ...') or remove them from the parent wrapper in SourceTab
(the div that wraps FileTree and also has rounded-md border border-gray-200
dark:border-gray-700 shadow-sm) so only one element retains the border/rounded
classes to avoid the double border.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. UI_SCREENSHOT_NAME path not sanitized 📘 Rule violation ⛨ Security
Description
SCREENSHOT_NAME is taken directly from process.env.UI_SCREENSHOT_NAME and used in
  path.join(SCREENSHOT_DIR, SCREENSHOT_NAME), allowing path traversal (e.g., ../...) and
  unintended writes outside dist/qa/screenshots.
• This violates the requirement to validate/sanitize external inputs (environment variables) and can
  create a security risk in CI runners or other environments where env vars can be influenced.
Code

scripts/capture-ui-screenshot.js[R11-14]

+const SCREENSHOT_NAME =
+  process.env.UI_SCREENSHOT_NAME || `ui-${process.platform}-${process.arch}.png`;
+const SCREENSHOT_PATH = path.join(SCREENSHOT_DIR, SCREENSHOT_NAME);
+const PORT = Number(process.env.UI_SCREENSHOT_PORT || 4173);
Evidence
PR Compliance ID 6 requires validation/sanitization of external inputs. The code uses an environment
variable to construct an output file path without restricting it to a safe filename, enabling
directory traversal or overwriting arbitrary files.

Rule 6: Generic: Security-First Input Validation and Data Handling
scripts/capture-ui-screenshot.js[11-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`scripts/capture-ui-screenshot.js` uses `process.env.UI_SCREENSHOT_NAME` directly when creating `SCREENSHOT_PATH`, which can allow path traversal and writing files outside the intended screenshots directory.

## Issue Context
Environment variables are external inputs. The script should only allow a safe filename (e.g., `ui-linux.png`) and disallow `..`, absolute paths, or path separators.

## Fix Focus Areas
- scripts/capture-ui-screenshot.js[11-14]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Include filter regression 🐞 Bug ✓ Correctness
Description
shouldExcludeByExtension now skips extension filtering when include_extensions is empty, which
  can cause the directory tree to include all files even though the UI states “Only process files with
  these extensions”.
• This also makes behavior inconsistent with repository analysis: FileAnalyzer will still exclude
  everything when use_custom_includes is enabled and the extension list is empty (and it also does
  not normalize include_extensions casing, unlike the updated filter-utils).
• Impact: confusing UX (tree shows selectable files that will never be analyzed) and possible
  performance/memory issues when rendering a huge tree unexpectedly.
Code

src/utils/filter-utils.ts[R13-24]

+  const useCustomIncludes = config?.use_custom_includes !== false;
+
  if (
-    config?.use_custom_includes &&
+    useCustomIncludes &&
    config?.include_extensions &&
    Array.isArray(config.include_extensions) &&
+    config.include_extensions.length > 0 &&
    path.extname(itemPath)
  ) {
    const ext = path.extname(itemPath).toLowerCase();
-    return !config.include_extensions.includes(ext);
+    const includeExtensions = config.include_extensions.map((includeExt) => includeExt.toLowerCase());
+    return !includeExtensions.includes(ext);
Evidence
The UI explicitly describes include_extensions as a restrictive allowlist (“Only process files
with these extensions”). However, filter-utils now bypasses extension filtering if the list is
empty, while FileAnalyzer still applies filtering whenever the field exists (even if empty) and
also compares against the raw config array (no lowercasing), creating inconsistent outcomes between
tree filtering and analysis.

src/utils/filter-utils.ts[12-25]
src/renderer/components/ConfigTab.tsx[410-416]
src/utils/file-analyzer.ts[80-90]
src/main/index.ts[184-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`shouldExcludeByExtension` currently **disables** extension filtering when `include_extensions` is an empty array. That contradicts the UI’s “Only process files with these extensions” wording and diverges from `FileAnalyzer` behavior (which still filters when the array exists, even if empty). Also, `filter-utils` now lowercases `include_extensions` entries, but `FileAnalyzer` does not, which can create mismatches.

## Issue Context
This impacts both the directory tree (main process uses `shouldExclude`) and analysis (uses `FileAnalyzer`). In the empty-include-list case, the tree may show many files that analysis will later skip.

## Fix Focus Areas
- src/utils/filter-utils.ts[12-25]
- src/utils/file-analyzer.ts[80-90]
- src/renderer/components/ConfigTab.tsx[410-416]
- src/main/index.ts[184-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. decodeURIComponent() can crash server 📘 Rule violation ⛯ Reliability
Description
resolveFilePath() calls decodeURIComponent() on requestUrl without a guard; malformed
  percent-encoding can throw and crash the HTTP server process.
• This violates the requirement to validate/handle external inputs and edge cases, and can cause the
  QA workflow to fail nondeterministically.
Code

scripts/capture-ui-screenshot.js[R25-33]

+function resolveFilePath(requestUrl) {
+  const urlPath = decodeURIComponent(requestUrl.split('?')[0]);
+  const relativePath = urlPath === '/' ? 'index.html' : urlPath.replace(/^\/+/, '');
+  const absolutePath = path.resolve(RENDERER_DIR, relativePath);
+  const relativeToRoot = path.relative(RENDERER_DIR, absolutePath);
+
+  if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
+    return null;
+  }
Evidence
PR Compliance IDs 3 and 6 require robust handling of potential failure points and validation of
external inputs. request.url is external input to the server; calling decodeURIComponent()
without try/catch can throw and bring down the process.

Rule 3: Generic: Robust Error Handling and Edge Case Management
Rule 6: Generic: Security-First Input Validation and Data Handling
scripts/capture-ui-screenshot.js[25-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`decodeURIComponent()` may throw on malformed request URLs, which can crash the static server and fail the workflow.

## Issue Context
The request URL is external input to the HTTP server. Handle malformed percent-encoding gracefully.

## Fix Focus Areas
- scripts/capture-ui-screenshot.js[25-33]
- scripts/capture-ui-screenshot.js[38-60]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Screenshot may be blank 🐞 Bug ⛯ Reliability
Description
• The screenshot script waits for #app, but #app exists in the static HTML before React renders,
  so this check does not confirm that the UI actually loaded.
• If the renderer bundle fails to execute (runtime error, missing asset, etc.), the workflow can
  still produce and upload a screenshot that looks blank/incorrect, reducing the usefulness of the QA
  signal.
Code

scripts/capture-ui-screenshot.js[R76-80]

+    await page.goto(`http://127.0.0.1:${PORT}/index.html`, { waitUntil: 'networkidle' });
+    await page.waitForSelector('#app', { timeout: 10000 });
+    await page.waitForTimeout(1000);
+    await page.screenshot({ path: SCREENSHOT_PATH, fullPage: true });
+    console.log(`UI screenshot captured: ${SCREENSHOT_PATH}`);
Evidence
#app is always present in index.html, so waiting for it does not prove the React UI rendered.
The App UI includes a stable heading (“AI Code Fusion”) that can be used as a more meaningful
readiness indicator.

scripts/capture-ui-screenshot.js[72-80]
src/renderer/index.html[29-34]
src/renderer/components/App.tsx[565-567]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The screenshot capture currently waits for `#app`, which is present in the static HTML and does not confirm the UI is rendered.

## Issue Context
A more reliable readiness condition would wait for an element that is rendered by React (e.g., the `AI Code Fusion` heading).

## Fix Focus Areas
- scripts/capture-ui-screenshot.js[72-80]
- src/renderer/index.html[29-34]
- src/renderer/components/App.tsx[565-567]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +11 to +14
const SCREENSHOT_NAME =
process.env.UI_SCREENSHOT_NAME || `ui-${process.platform}-${process.arch}.png`;
const SCREENSHOT_PATH = path.join(SCREENSHOT_DIR, SCREENSHOT_NAME);
const PORT = Number(process.env.UI_SCREENSHOT_PORT || 4173);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. ui_screenshot_name path not sanitized 📘 Rule violation ⛨ Security

SCREENSHOT_NAME is taken directly from process.env.UI_SCREENSHOT_NAME and used in
  path.join(SCREENSHOT_DIR, SCREENSHOT_NAME), allowing path traversal (e.g., ../...) and
  unintended writes outside dist/qa/screenshots.
• This violates the requirement to validate/sanitize external inputs (environment variables) and can
  create a security risk in CI runners or other environments where env vars can be influenced.
Agent Prompt
## Issue description
`scripts/capture-ui-screenshot.js` uses `process.env.UI_SCREENSHOT_NAME` directly when creating `SCREENSHOT_PATH`, which can allow path traversal and writing files outside the intended screenshots directory.

## Issue Context
Environment variables are external inputs. The script should only allow a safe filename (e.g., `ui-linux.png`) and disallow `..`, absolute paths, or path separators.

## Fix Focus Areas
- scripts/capture-ui-screenshot.js[11-14]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/utils/filter-utils.ts
Comment on lines +13 to +24
const useCustomIncludes = config?.use_custom_includes !== false;

if (
config?.use_custom_includes &&
useCustomIncludes &&
config?.include_extensions &&
Array.isArray(config.include_extensions) &&
config.include_extensions.length > 0 &&
path.extname(itemPath)
) {
const ext = path.extname(itemPath).toLowerCase();
return !config.include_extensions.includes(ext);
const includeExtensions = config.include_extensions.map((includeExt) => includeExt.toLowerCase());
return !includeExtensions.includes(ext);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Include filter regression 🐞 Bug ✓ Correctness

shouldExcludeByExtension now skips extension filtering when include_extensions is empty, which
  can cause the directory tree to include all files even though the UI states “Only process files with
  these extensions”.
• This also makes behavior inconsistent with repository analysis: FileAnalyzer will still exclude
  everything when use_custom_includes is enabled and the extension list is empty (and it also does
  not normalize include_extensions casing, unlike the updated filter-utils).
• Impact: confusing UX (tree shows selectable files that will never be analyzed) and possible
  performance/memory issues when rendering a huge tree unexpectedly.
Agent Prompt
## Issue description
`shouldExcludeByExtension` currently **disables** extension filtering when `include_extensions` is an empty array. That contradicts the UI’s “Only process files with these extensions” wording and diverges from `FileAnalyzer` behavior (which still filters when the array exists, even if empty). Also, `filter-utils` now lowercases `include_extensions` entries, but `FileAnalyzer` does not, which can create mismatches.

## Issue Context
This impacts both the directory tree (main process uses `shouldExclude`) and analysis (uses `FileAnalyzer`). In the empty-include-list case, the tree may show many files that analysis will later skip.

## Fix Focus Areas
- src/utils/filter-utils.ts[12-25]
- src/utils/file-analyzer.ts[80-90]
- src/renderer/components/ConfigTab.tsx[410-416]
- src/main/index.ts[184-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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