Skip to content

feat: add third-party license management and in-app viewer#4

Merged
tphakala merged 2 commits intomainfrom
feat/third-party-licenses
Feb 8, 2026
Merged

feat: add third-party license management and in-app viewer#4
tphakala merged 2 commits intomainfrom
feat/third-party-licenses

Conversation

@tphakala
Copy link
Copy Markdown
Owner

@tphakala tphakala commented Feb 8, 2026

Summary

  • Add THIRD_PARTY_LICENSES.txt generated from all npm dependencies via generate-license-file
  • Add GitHub Actions workflow (.github/workflows/licenses.yml) that auto-regenerates the file when package-lock.json changes and opens a PR
  • Bundle the license file in packaged builds via extraResources in electron-builder config
  • Add Help > Third Party Licenses menu item that opens a scrollable modal viewer
  • Full IPC plumbing: handler, preload whitelist, renderer wrapper, i18n strings

Test plan

  • Run npm run dev and click Help > Third Party Licenses — modal opens with license text
  • Verify modal closes via X button, Close button, and backdrop click
  • Run npm run build && npx electron-builder --dir and confirm THIRD_PARTY_LICENSES.txt exists in release/*/resources/
  • Verify npm run validate passes (format, lint, typecheck, audit)

🤖 Generated with Claude Code

Add automated license file generation via GitHub Actions workflow that
triggers on package-lock.json changes and creates a PR with updated
THIRD_PARTY_LICENSES.txt. Bundle the file in packaged builds via
extraResources and expose it through Help > Third Party Licenses menu
item that opens a scrollable modal viewer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 8, 2026

Warning

Rate limit exceeded

@tphakala has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 56 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.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/third-party-licenses

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 @tphakala, 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 introduces a comprehensive system for managing and displaying third-party software licenses within the application. It ensures that all npm dependency licenses are automatically collected, bundled with the application, and made accessible to users through a new in-app viewer, enhancing transparency and compliance.

Highlights

  • In-App License Viewer: A new modal viewer has been implemented, accessible via the 'Help > Third Party Licenses' menu, to display all third-party software licenses used in the application.
  • Automated License Management: The THIRD_PARTY_LICENSES.txt file, containing licenses from npm dependencies, is now automatically generated and kept up-to-date via a GitHub Actions workflow. This workflow creates a pull request whenever package-lock.json changes.
  • Bundling in Packaged Builds: The THIRD_PARTY_LICENSES.txt file is now included as an extra resource in packaged Electron builds, ensuring it's available in the final application.
  • IPC Plumbing and Internationalization: Full Inter-Process Communication (IPC) plumbing has been established to facilitate license retrieval and viewer control, including a new main process handler, preload script whitelisting, renderer wrapper functions, and internationalization strings for the viewer's UI.
Changelog
  • messages/en.json
    • Added internationalization keys for the license viewer title ('licenses_title'), a 'not found' message ('licenses_notFound'), and a common close button ('common_button_close').
  • package.json
    • Configured electron-builder to include THIRD_PARTY_LICENSES.txt as an extra resource in packaged application builds, ensuring its presence in the final distribution.
  • src/main/index.ts
    • Modified the main process menu creation to include a 'Third Party Licenses' option under the 'Help' menu, which triggers an IPC event (menu:show-licenses) to open the viewer.
  • src/main/ipc/handlers.ts
    • Updated to import and register the new license-specific IPC handlers (registerLicenseHandlers), integrating them into the application's main process communication flow.
  • src/main/ipc/licenses.ts
    • Introduced a new module (licenses.ts) responsible for handling IPC requests (app:get-licenses) to retrieve the content of THIRD_PARTY_LICENSES.txt, dynamically locating the file based on whether the app is packaged or in development.
  • src/preload/index.ts
    • Extended the IPC whitelist to securely allow app:get-licenses for invoking and menu:show-licenses for receiving events, enabling communication between the renderer and main processes for license management.
  • src/renderer/src/App.svelte
    • Integrated the new LicenseViewer Svelte component into the main application.
    • Added state management (showLicenses) and event listeners (onShowLicenses, offShowLicenses) to control the visibility of the license viewer based on menu interactions.
  • src/renderer/src/lib/components/LicenseViewer.svelte
    • Added a new Svelte component (LicenseViewer.svelte) that renders a modal dialog to display the fetched third-party license text.
    • Includes functionality to fetch license content via IPC, display loading and error states, and provides options to close the modal.
  • src/renderer/src/lib/utils/ipc.ts
    • Exposed new utility functions (getLicenses, onShowLicenses, offShowLicenses) for the renderer process to interact with the main process, specifically for invoking the app:get-licenses IPC handler and managing listeners for the menu:show-licenses event.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/licenses.yml
Activity
  • The pull request was created by tphakala.
  • The description provides a detailed summary of changes, a test plan, and notes that the code was generated with Claude Code.
  • No other human activity (comments, reviews) is indicated in the provided context.
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
Copy Markdown

@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 effectively adds a new feature for viewing third-party licenses. The implementation is well-structured, covering the main process, preload script, and renderer components. I've added a suggestion to improve error handling robustness in the renderer process. Overall, this is a great addition.

licenseText = text;
})
.catch((e: unknown) => {
error = (e as Error).message;
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

The error object e in a catch block is of type unknown. Directly casting it with as Error is not type-safe and can lead to runtime errors if the caught value is not an Error object. It's better to check if e is an instance of Error before accessing its properties.

          error = e instanceof Error ? e.message : String(e);

- Add generate-license-file to knip ignoreBinaries (fixes knip check)
- Use instanceof Error guard in LicenseViewer catch block for type safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tphakala tphakala merged commit 96030b0 into main Feb 8, 2026
5 checks passed
@tphakala tphakala deleted the feat/third-party-licenses branch February 8, 2026 11:35
tphakala added a commit that referenced this pull request Feb 12, 2026
- Update SQL query to use IN ('completed', 'completed_with_errors')
- Ensures previous runs with errors are replaced on re-analysis
- Resolves Seer #4 and CodeRabbit Major issue
tphakala added a commit that referenced this pull request Feb 12, 2026
* docs: add directory analysis feature design document

Addresses #10 - comprehensive design for adding directory analysis
support with durable JSON output, incremental database ingestion,
and crash-resistant progress tracking.

* feat: add directory analysis event payload types

* feat: add completed_with_errors status to AnalysisRun

* feat: add database migration for completed_with_errors status

* fix: set completed_at timestamp for completed_with_errors status

* feat: add outputDir parameter to enable dual output mode

* feat: add importDetectionsFromJson function

* fix: remove unused path import from detections.ts

* fix: preserve common_name field from JSON output

* feat: implement directory analysis mode with event handling and cleanup

- Add helper functions for temp directory management and JSON path derivation
- Detect if source path is a directory and create temp output directory
- Enable dual output mode (NDJSON streaming for directories)
- Handle directory-specific progress events (pipeline_started, file_started, file_completed)
- Import detections incrementally from JSON files as each file completes
- Track failed and skipped files during directory analysis
- Determine final status based on file processing results (completed vs completed_with_errors)
- Clean up temp directory in finally block regardless of success/failure
- Maintain backward compatibility with single file analysis mode

* fix: address critical ESLint errors in directory analysis

Fixes 4 critical issues identified in code quality review:

1. Async event handler - Wrapped async operations in void IIFE with
   try/catch to prevent unhandled promise rejections in 'data' event
   handler. Synchronous event forwarding remains outside IIFE.

2. Unnecessary condition - Replaced final 'else if' with 'else' for
   'failed' status case (only remaining option).

3. JSON.parse validation - Added Zod schemas (BirdaDetectionSchema,
   BirdaJsonOutputSchema) to validate JSON.parse output from birda
   CLI JSON files, preventing potential runtime errors from malformed
   data.

4. Status logic bug - Fixed critical bug where all-failed directory
   analysis was marked 'completed' instead of 'failed'. Now correctly
   returns 'failed' when processedCount is 0.

Also removed unused DetectionsPayload import (still used via inline
import statement).

All changes maintain backward compatibility with single-file mode.
Build and ESLint validation passed successfully.

* fix: resolve critical race conditions in analysis handler

Two critical race conditions have been fixed in the directory analysis feature:

1. Async Event Handler Race: Status calculation previously read state
   (totalDetections, failedFiles, skippedFiles) immediately after
   `await handle.promise`, but async IIFEs in event handlers could still
   be running. Now all async event handler promises are tracked in
   `pendingImports` array and awaited with `Promise.allSettled()` before
   calculating final status.

2. Analysis Lock Race: Gap between null check and assignment of
   `currentAnalysis` allowed concurrent IPC requests to pass through.
   Now a placeholder AnalysisHandle is assigned immediately after the
   null check, locking the handler. The placeholder is replaced with
   the real handle once available. Lock is released early on setup
   errors if still holding the placeholder.

Changes:
- Add `pendingImports: Promise<void>[]` array to track async operations
- Extract async IIFE in data event handler to named `importPromise`
- Push each promise to `pendingImports` array
- Add `await Promise.allSettled(pendingImports)` before status calculation
- Create placeholder AnalysisHandle immediately after null check
- Assign placeholder to `currentAnalysis` to lock immediately
- Wrap setup work in try/catch to release lock on error
- Replace placeholder with real handle when available

* fix: add memory limits, input validation, and atomic operations

- Cap failedFiles/skippedFiles arrays at 100 entries to prevent unbounded memory growth in directory analysis
- Add Zod-based input validation for analysis IPC requests
- Make database delete operations atomic with new deleteCompletedRunsForSource() transaction
- Extract magic constants (LEAP_YEAR_FOR_DOY, MAX_TRACKED_FILES, MAX_STDERR_LINES, JSON_READ_RETRIES, BASE_RETRY_DELAY_MS)

Addresses code review tasks 3-6.

* style: fix prettier formatting in analysis.ts

* fix: resolve knip issues - add zod dependency, clean up exports

* fix: disable foreign keys during migration 4 table recreation

* fix: resolve duplicate key error in LogPanel

Add unique ID field to LogEntry to prevent Svelte each_key_duplicate
error during rapid logging. When multiple log entries have the same
timestamp (millisecond precision), the keyed each block would fail
with duplicate keys.

Changes:
- Add `id: number` field to LogEntry interface
- Add `nextId` counter that increments with each new entry
- Update LogPanel to use `entry.id` as key instead of `entry.timestamp`

Fixes: Svelte error "each_key_duplicate" during directory analysis

* fix: specify JSON format for birda directory analysis

When using --output-dir with birda, we need to specify --format json
to write JSON files to disk. Without this, birda defaults to CSV format,
causing the GUI to fail when trying to import detections from JSON files.

The --output-mode ndjson controls stdout streaming, while --format json
controls the file format written to disk.

* fix: preserve file_completed events in analysis event array

When the analysis event array exceeded MAX_EVENTS (500), the trim logic
would remove old events including critical file_completed events. This
caused checkmarks to disappear from completed files in the directory
analysis UI.

The fix modifies the trimming logic to:
- Keep ALL file_completed events (critical for UI state)
- Only trim progress events when the limit is reached
- Maintain recent progress events for current file feedback

This ensures checkmarks remain visible for all completed files throughout
the entire directory analysis, even when processing thousands of segments.

* fix: update JSON schema to match birda's actual output format

The GUI was expecting a 'metadata' wrapper object, but birda's actual JSON
format has top-level fields: source_file, analysis_date, model, settings,
detections, and summary.

Updated the Zod schema to match birda's JsonResultFile struct:
- source_file (not metadata.file)
- settings.min_confidence (not metadata.min_confidence)
- summary object with detection statistics

This fixes the validation error that was causing all directory analysis
imports to fail with 'expected object, received undefined' for metadata.

* fix: eliminate duplicate event payload types and correct field names

- Remove duplicate type definitions from src/main/birda/types.ts
- Re-export types from shared/types.ts as canonical source
- Add FileStartedPayload to shared/types.ts
- Fix analysis.ts to use total_files instead of files_total
- Resolves CodeRabbit Major issue about type duplication

* fix: add separate counters for failed/skipped files

- Add failedFileCount and skippedFileCount numeric variables
- Increment counters whenever file fails or is skipped
- Use counters instead of array.length for processedCount calculation
- Fixes incorrect counts when arrays are capped at MAX_TRACKED_FILES
- Resolves CodeRabbit Major issue about processedCount

* fix: preserve temp directory on failure for debugging

- Move finalStatus declaration outside try block
- Set finalStatus to 'failed' in catch block
- Check finalStatus in finally block
- Only cleanup temp dir if not failed
- Log preservation message when keeping temp dir
- Resolves CodeRabbit Major issue about temp dir cleanup

* fix: include completed_with_errors in findCompletedRuns

- Update SQL query to use IN ('completed', 'completed_with_errors')
- Ensures previous runs with errors are replaced on re-analysis
- Resolves Seer #4 and CodeRabbit Major issue

* fix: add try/finally for foreign key pragma in migration 4

- Wrap transaction in try/finally block
- Ensures foreign keys are re-enabled even if migration fails
- Resolves Seer #3 and CodeRabbit Nitpick issue

* fix: add concurrency limit for JSON imports (DoS prevention)

- Add Semaphore class for limiting concurrent operations
- Set MAX_CONCURRENT_IMPORTS to 10
- Wrap importDetectionsFromJson with semaphore acquire/release
- Prevents resource exhaustion with large directories
- Resolves Gemini Critical DoS issue

* refactor: use mkdtemp for temp directory creation

- Replace Date.now() timestamp with fs.promises.mkdtemp
- Provides atomic unique directory creation
- More idiomatic Node.js approach
- Resolves CodeRabbit Nitpick issue

* refactor: extract helper function for array overflow handling

- Add trackFileWithOverflow helper function
- Replace three duplicated code blocks with helper calls
- Improves code maintainability and readability
- Resolves Gemini suggestion for refactoring

* chore: run prettier on analysis.ts

* fix: use T[] instead of Array<T> for eslint compliance
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