Skip to content

feat: Add Internxt Virtual Drive extension for Nemo file manager - #409

Open
egalvis27 wants to merge 7 commits into
mainfrom
feat/add-nemo-file-system-extension
Open

feat: Add Internxt Virtual Drive extension for Nemo file manager#409
egalvis27 wants to merge 7 commits into
mainfrom
feat/add-nemo-file-system-extension

Conversation

@egalvis27

@egalvis27 egalvis27 commented Jul 16, 2026

Copy link
Copy Markdown

What is Changed / Added

We've added unified file manager extension support for both Nautilus and Nemo. The app now automatically detects which manager you have installed and handles everything transparently. Created a new file-manager-extension module with detection logic, installation orchestration, and version tracking. Also fixed GTK compatibility issues (was 4.0, now 3.0) so Nemo works properly on Linux Mint. Updated IPC handlers, config store, and all components to use the new system. Includes 28 comprehensive tests covering both managers, and fixed a global mock issue that was breaking other tests.

Why

Users on Linux Mint and other Cinnamon-based distros couldn't use the file manager integration since we only supported Nautilus. This unifies both managers under a single detection point, so the same extension system works whether you use Nautilus, Nemo, or switch between them. Makes the codebase cleaner too—one module handling both cases instead of duplicated logic everywhere.

Summary by CodeRabbit

  • New Features
    • Added support for Nautilus, Nemo, and Dolphin file managers with automatic extension installation and updates.
    • Virtual Drive items now display sync status and support online-only actions.
    • Added “Copy Internxt Link” actions for files and folders.
  • Bug Fixes
    • Improved handling of special characters and URI-encoded paths.
    • Corrected file-manager availability detection and warning behavior.
  • Documentation
    • Added compatibility details and KDE Wallet setup guidance.
  • Chores
    • File-manager extension versions now persist across sign-in sessions.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds generic Nautilus, Nemo, and Dolphin detection, file-manager extension lifecycle management, persisted extension versions, sharing-link generation, Nemo virtual-drive integration, smoke testing, and generic availability reporting through IPC and the renderer.

Changes

File-manager extension support

Layer / File(s) Summary
Detection and extension service
src/backend/features/file-manager-extension/constants.ts, src/backend/features/file-manager-extension/detect-available.ts, src/backend/features/file-manager-extension/service.ts, src/backend/features/file-manager-extension/*test.ts
Detects supported file managers and manages their extension assets, reload commands, installation state, and deletion.
Installation lifecycle and persisted version
src/backend/features/file-manager-extension/install.ts, src/backend/features/file-manager-extension/version.ts, src/core/bootstrap/*, src/core/electron/store/*, src/apps/main/config*, knip.json, src/backend/features/nautilus-extension/*
Installs, upgrades, and uninstalls the generic extension during startup and logout. Persists fileManagerExtensionVersion and removes obsolete Nautilus installer wiring.
File-manager sharing links
src/backend/features/file-manager-extension/create-sharing-link/*, src/apps/drive/hydration-api/controllers/*
Resolves file or folder metadata, creates encrypted sharing links, selects domains, copies links to the clipboard, and updates controller dependencies and tests.
Nemo and Dolphin virtual-drive integration
assets/python-nemo/internxt-virtual-drive.py, assets/python-nautilus/internxt-virtual-drive.py, assets/dolphin/*, src/core/electron/paths.ts
Adds Nemo sync-status metadata and hydration actions, improves Nautilus URI decoding, and adds Dolphin link-copy actions and service-menu integration.
File-manager availability API
src/core/bootstrap/register-main-ipc-handlers.ts, src/apps/main/preload.*, src/apps/main/interface.d.ts, src/apps/renderer/pages/Widget/InfoBanners/Banners/*
Replaces Nautilus-specific availability IPC with generic file-manager detection and updates the renderer banner and tests.
Smoke validation and support documentation
src/backend/features/file-manager-extension/file-manager-extension-smoke.ts, tests/smoke/file-manager-extension/*, .github/workflows/*, package.json, README.md
Adds installation/removal smoke tests for Nautilus, Nemo, and Dolphin, runs them in pull-request workflow jobs, updates packaging, and documents supported environments and KDE Wallet setup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant FileManagerDetection
  participant ExtensionInstaller
  participant FileManagerService
  participant FileManager
  App->>ExtensionInstaller: installFileManagerExtension()
  ExtensionInstaller->>FileManagerDetection: detectAvailableFileManager()
  ExtensionInstaller->>FileManagerService: copy or replace extension
  ExtensionInstaller->>FileManagerService: persist fileManagerExtensionVersion
  ExtensionInstaller->>FileManager: reload detected manager
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the new Nemo virtual drive extension, which is a significant part of the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-nemo-file-system-extension

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.

@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: 5

Caution

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

⚠️ Outside diff range comments (1)
src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsx (1)

12-18: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Complete the migration from Nautilus-specific terminology.

The new contract is file-manager agnostic, but the UI and tests still describe only Nautilus.

  • src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsx#L12-L18: rename the state/copy to generic file-manager terminology.
  • src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsx#L9-L20: update test descriptions to refer to supported file managers rather than Nautilus.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsx`
around lines 12 - 18, Complete the terminology migration in
NautilusUnavailable.tsx by renaming Nautilus-specific state and user-facing copy
to generic file-manager terminology while preserving behavior. In
NautilusUnavailable.test.tsx, update test descriptions and assertions that
reference Nautilus to describe supported file managers; apply the requested
changes at both listed files and ranges.
🧹 Nitpick comments (3)
src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsx (1)

9-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the test descriptions to match the generic API.

These tests now exercise getFileManagerAvailability, so titles such as “when Nautilus is available” are misleading. Use “when a supported file manager is available/unavailable” to keep the tests aligned with the new contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsx`
around lines 9 - 20, Rename the two test descriptions in the NautilusUnavailable
test suite to refer to “a supported file manager” being available or
unavailable, matching the getFileManagerAvailability API contract while leaving
the test behavior unchanged.
assets/python-nemo/internxt-virtual-drive.py (2)

76-76: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unnecessary semicolon.

Python does not require semicolons to terminate statements.

♻️ Proposed refactor
-        file_uri = file.get_uri();
+        file_uri = file.get_uri()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/python-nemo/internxt-virtual-drive.py` at line 76, Remove the
unnecessary semicolon from the file.get_uri() statement in the surrounding code,
keeping the assignment behavior unchanged.

Source: Linters/SAST tools


80-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unnecessary semicolon.

Python does not require semicolons to terminate statements.

♻️ Proposed refactor
-        file_uri = file.get_uri();
+        file_uri = file.get_uri()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/python-nemo/internxt-virtual-drive.py` at line 80, Remove the
unnecessary semicolon from the statement assigning the URI in the surrounding
file-handling code, leaving the file.get_uri() call and resulting assignment
unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/python-nemo/internxt-virtual-drive.py`:
- Line 106: Update all external requests calls in
assets/python-nemo/internxt-virtual-drive.py to include a reasonable timeout,
such as 2 seconds: requests.get in _get_availability (106-106), requests.post in
_make_locally_available (195-195) and _copy_internxt_link (208-208), and
requests.delete in _make_remote_only (240-240). Ensure every listed call uses
the timeout consistently.
- Around line 175-181: Update _encode_file_path to URL-decode file.get_uri()
before deriving the relative path, then remove self.root_folder from the decoded
value instead of replacing self.file_base_dir on the encoded URI. Preserve the
existing UTF-8 and base64 encoding flow.

In `@src/backend/features/file-manager-extension/install.ts`:
- Around line 59-66: Update the installed-version replacement flow around
deleteExtensionFile and install so the new extension is first staged in the
destination directory, then atomically renamed over the existing extension only
after installation succeeds. Preserve the current working extension when staging
or copying fails, and remove the pre-install deletion step.

In `@src/backend/features/file-manager-extension/service.ts`:
- Around line 89-97: Update deleteExtensionFile to clean up both known
file-manager destination paths instead of relying on getFileManagerConfig’s
currently detected manager. Enumerate the Nautilus and Nemo destinations, check
each with doesFileExist, and remove every existing extension file via fs.rm
while preserving the no-op behavior when neither is installed.
- Around line 110-128: Update the Promise wrapping the reload command in the
file-manager reload service to enforce a short timeout for the exec process.
When the timeout is exceeded, terminate the child process if possible and reject
the Promise, while preserving the existing handling for exit code 255, stderr,
and successful completion.

---

Outside diff comments:
In `@src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsx`:
- Around line 12-18: Complete the terminology migration in
NautilusUnavailable.tsx by renaming Nautilus-specific state and user-facing copy
to generic file-manager terminology while preserving behavior. In
NautilusUnavailable.test.tsx, update test descriptions and assertions that
reference Nautilus to describe supported file managers; apply the requested
changes at both listed files and ranges.

---

Nitpick comments:
In `@assets/python-nemo/internxt-virtual-drive.py`:
- Line 76: Remove the unnecessary semicolon from the file.get_uri() statement in
the surrounding code, keeping the assignment behavior unchanged.
- Line 80: Remove the unnecessary semicolon from the statement assigning the URI
in the surrounding file-handling code, leaving the file.get_uri() call and
resulting assignment unchanged.

In
`@src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsx`:
- Around line 9-20: Rename the two test descriptions in the NautilusUnavailable
test suite to refer to “a supported file manager” being available or
unavailable, matching the getFileManagerAvailability API contract while leaving
the test behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 848e88cd-965e-4df2-83ac-968d7767f691

📥 Commits

Reviewing files that changed from the base of the PR and between e6b1171 and e5dddc3.

📒 Files selected for processing (23)
  • assets/python-nemo/internxt-virtual-drive.py
  • knip.json
  • src/apps/main/auth/service.test.ts
  • src/apps/main/config.ts
  • src/apps/main/config/save-config.ts
  • src/apps/main/interface.d.ts
  • src/apps/main/preload.d.ts
  • src/apps/main/preload.js
  • src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsx
  • src/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsx
  • src/backend/features/file-manager-extension/detect-available.test.ts
  • src/backend/features/file-manager-extension/detect-available.ts
  • src/backend/features/file-manager-extension/install.test.ts
  • src/backend/features/file-manager-extension/install.ts
  • src/backend/features/file-manager-extension/service.test.ts
  • src/backend/features/file-manager-extension/service.ts
  • src/backend/features/file-manager-extension/version.ts
  • src/core/bootstrap/register-app-ready-flow.ts
  • src/core/bootstrap/register-main-ipc-handlers.ts
  • src/core/bootstrap/register-session-event-handlers.ts
  • src/core/electron/store/app-store.interface.ts
  • src/core/electron/store/defaults.ts
  • vitest.setup.main.ts

Comment thread assets/python-nemo/internxt-virtual-drive.py
Comment thread assets/python-nemo/internxt-virtual-drive.py
Comment on lines +59 to +66
if (installed && !hasLatestVersion) {
logger.debug({
msg: '[FILE_MANAGER_EXTENSION] There is a newer version to be installed',
});

await deleteExtensionFile();
await install();
await reloadFileManager().catch((reloadError) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Do not delete the working extension before staging its replacement.

If install() fails after Line 64, the previous extension is already gone. Stage the new asset in the destination directory and atomically rename it over the existing file, preserving the old version if copying fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/features/file-manager-extension/install.ts` around lines 59 - 66,
Update the installed-version replacement flow around deleteExtensionFile and
install so the new extension is first staged in the destination directory, then
atomically renamed over the existing extension only after installation succeeds.
Preserve the current working extension when staging or copying fails, and remove
the pre-install deletion step.

Comment thread src/backend/features/file-manager-extension/service.ts Outdated
Comment thread src/backend/features/file-manager-extension/service.ts

@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.

Caution

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

⚠️ Outside diff range comments (2)
src/backend/features/file-manager-extension/service.test.ts (2)

80-114: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Assert the manager-specific extension path.

These tests only control doesFileExist’s return value, so they would still pass if Nautilus and Nemo used the wrong or shared path. Assert the exact expected path for each manager (and that no path check occurs when no manager is available).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/features/file-manager-extension/service.test.ts` around lines 80
- 114, Add assertions to the isInstalled tests verifying that doesFileExistMock
receives the exact manager-specific extension path for Nautilus and Nemo. Also
cover the no-manager case and assert that doesFileExistMock is not called, while
preserving the existing boolean result assertions.

132-138: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the exec mocks honor the child-process contract.

reloadFileManager() attaches an error listener to the object returned by exec. These mocks invoke the callback synchronously and return nothing, so the promise may resolve before the invalid childProcess.on(...) call occurs. Return an EventEmitter-like object and invoke the callback after execMock returns; otherwise these tests can mask regressions in the reload setup.

This test double should match the reloadFileManager() contract in src/backend/features/file-manager-extension/service.ts:104-138.

Suggested mock shape
 execMock.mockImplementation((cmd, optionsOrCallback, callback) => {
   const cb = typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
-  cb?.(null, '', '');
+  const childProcess = { on: vi.fn() };
+  queueMicrotask(() => cb?.(null, '', ''));
+  return childProcess;
 });

Also applies to: 150-156, 168-174, 201-204

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/features/file-manager-extension/service.test.ts` around lines 132
- 138, Update every execMock implementation in the affected tests to return an
EventEmitter-like child-process object supporting the error listener used by
reloadFileManager(), and defer callback invocation until after execMock returns.
Preserve each test’s existing command, options, and callback assertions while
ensuring the mock matches the reloadFileManager() child-process contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/backend/features/file-manager-extension/service.test.ts`:
- Around line 80-114: Add assertions to the isInstalled tests verifying that
doesFileExistMock receives the exact manager-specific extension path for
Nautilus and Nemo. Also cover the no-manager case and assert that
doesFileExistMock is not called, while preserving the existing boolean result
assertions.
- Around line 132-138: Update every execMock implementation in the affected
tests to return an EventEmitter-like child-process object supporting the error
listener used by reloadFileManager(), and defer callback invocation until after
execMock returns. Preserve each test’s existing command, options, and callback
assertions while ensuring the mock matches the reloadFileManager() child-process
contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 00664aa5-5a11-435e-a849-56093e524cd2

📥 Commits

Reviewing files that changed from the base of the PR and between 73b9a99 and 269866e.

📒 Files selected for processing (1)
  • src/backend/features/file-manager-extension/service.test.ts

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts`:
- Around line 22-33: Handle a null result from fetchRandomDomain before
generating the code or calling createSharingResult: return the flow’s existing
error response immediately when no domain is available, and preserve the current
sharing-link generation path for valid domains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f042ef24-c340-406b-8a29-a165a09e1a35

📥 Commits

Reviewing files that changed from the base of the PR and between 269866e and dfe207d.

📒 Files selected for processing (27)
  • src/apps/drive/hydration-api/controllers/contents.test.ts
  • src/apps/drive/hydration-api/controllers/contents.ts
  • src/apps/main/auth/service.test.ts
  • src/apps/main/config.ts
  • src/apps/main/config/save-config.ts
  • src/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.ts
  • src/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.ts
  • src/backend/features/file-manager-extension/create-sharing-link/generate-link.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts
  • src/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.ts
  • src/backend/features/file-manager-extension/create-sharing-link/types.ts
  • src/backend/features/nautilus-extension/install.test.ts
  • src/backend/features/nautilus-extension/install.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.test.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.ts
  • src/backend/features/nautilus-extension/reload.test.ts
  • src/backend/features/nautilus-extension/reload.ts
  • src/backend/features/nautilus-extension/service.test.ts
  • src/backend/features/nautilus-extension/service.ts
  • src/backend/features/nautilus-extension/uninstall.test.ts
  • src/backend/features/nautilus-extension/uninstall.ts
  • src/backend/features/nautilus-extension/version.ts
  • src/core/electron/store/app-store.interface.ts
  • src/core/electron/store/defaults.ts
💤 Files with no reviewable changes (14)
  • src/backend/features/nautilus-extension/install.test.ts
  • src/apps/main/config.ts
  • src/backend/features/nautilus-extension/service.test.ts
  • src/backend/features/nautilus-extension/uninstall.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.ts
  • src/backend/features/nautilus-extension/reload.ts
  • src/backend/features/nautilus-extension/service.ts
  • src/backend/features/nautilus-extension/reload.test.ts
  • src/backend/features/nautilus-extension/uninstall.test.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.test.ts
  • src/backend/features/nautilus-extension/install.ts
  • src/apps/main/config/save-config.ts
  • src/backend/features/nautilus-extension/version.ts
  • src/apps/main/auth/service.test.ts

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts`:
- Around line 22-33: Handle a null result from fetchRandomDomain before
generating the code or calling createSharingResult: return the flow’s existing
error response immediately when no domain is available, and preserve the current
sharing-link generation path for valid domains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f042ef24-c340-406b-8a29-a165a09e1a35

📥 Commits

Reviewing files that changed from the base of the PR and between 269866e and dfe207d.

📒 Files selected for processing (27)
  • src/apps/drive/hydration-api/controllers/contents.test.ts
  • src/apps/drive/hydration-api/controllers/contents.ts
  • src/apps/main/auth/service.test.ts
  • src/apps/main/config.ts
  • src/apps/main/config/save-config.ts
  • src/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.ts
  • src/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.ts
  • src/backend/features/file-manager-extension/create-sharing-link/generate-link.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts
  • src/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.test.ts
  • src/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.ts
  • src/backend/features/file-manager-extension/create-sharing-link/types.ts
  • src/backend/features/nautilus-extension/install.test.ts
  • src/backend/features/nautilus-extension/install.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.test.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.ts
  • src/backend/features/nautilus-extension/reload.test.ts
  • src/backend/features/nautilus-extension/reload.ts
  • src/backend/features/nautilus-extension/service.test.ts
  • src/backend/features/nautilus-extension/service.ts
  • src/backend/features/nautilus-extension/uninstall.test.ts
  • src/backend/features/nautilus-extension/uninstall.ts
  • src/backend/features/nautilus-extension/version.ts
  • src/core/electron/store/app-store.interface.ts
  • src/core/electron/store/defaults.ts
💤 Files with no reviewable changes (14)
  • src/backend/features/nautilus-extension/install.test.ts
  • src/apps/main/config.ts
  • src/backend/features/nautilus-extension/service.test.ts
  • src/backend/features/nautilus-extension/uninstall.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.ts
  • src/backend/features/nautilus-extension/reload.ts
  • src/backend/features/nautilus-extension/service.ts
  • src/backend/features/nautilus-extension/reload.test.ts
  • src/backend/features/nautilus-extension/uninstall.test.ts
  • src/backend/features/nautilus-extension/is-nautilus-available.test.ts
  • src/backend/features/nautilus-extension/install.ts
  • src/apps/main/config/save-config.ts
  • src/backend/features/nautilus-extension/version.ts
  • src/apps/main/auth/service.test.ts
🛑 Comments failed to post (1)
src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts (1)

22-33: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Stop when no sharing domain is available.

fetchRandomDomain() returns null for an empty list, but this flow still creates a sharing record and copies null/sh/... as a success. Return an error before generating or persisting the sharing.

Proposed fix
     const item = await resolveShareableItem({ path });
     const domain = await fetchRandomDomain();
+    if (!domain) {
+      return { error: new Error('No public sharing domain is available') };
+    }
+
     const plainCode = stringUtils.generateRandomStringUrlSafe(8);
📝 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.

    const domain = await fetchRandomDomain();
    if (!domain) {
      return { error: new Error('No public sharing domain is available') };
    }

    const plainCode = stringUtils.generateRandomStringUrlSafe(8);
    const encryptionKey = aes.encrypt(mnemonic, plainCode);
    const encryptedCode = aes.encrypt(plainCode, mnemonic);
    const sharing = await createSharingResult({
      encryptedCode,
      encryptionKey,
      item,
    });
    const recoveredCode = aes.decrypt(sharing.encryptedCode, mnemonic);
    const sharingId = stringUtils.encodeV4Uuid(sharing.id);
    const shareLink = `${domain}/sh/${item.itemType}/${sharingId}/${recoveredCode}`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/backend/features/file-manager-extension/create-sharing-link/generate-link.ts`
around lines 22 - 33, Handle a null result from fetchRandomDomain before
generating the code or calling createSharingResult: return the flow’s existing
error response immediately when no domain is available, and preserve the current
sharing-link generation path for valid domains.

Comment thread src/backend/features/file-manager-extension/service.ts Outdated
Comment on lines +56 to +72
async function hasNautilusBinary(): Promise<boolean> {
try {
await execAsync('command -v nautilus');
return true;
} catch {
return false;
}
}

async function hasNemoBinary(): Promise<boolean> {
try {
await execAsync('command -v nemo');
return true;
} catch {
return false;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

these 2 functions are exactly the same minus the "nemo" and "nautilus" part, why not simplify them?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

Comment on lines +12 to +23
if (desktopEntry.includes('nemo.desktop')) {
if (await hasNemoBinary()) {
return 'nemo';
}
}

if (desktopEntry.includes('nautilus.desktop')) {
if (await hasNautilusBinary()) {
return 'nautilus';
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You are doing 2 similar steps here, why not simplify it so the code is more readable?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

import { LATEST_EXTENSION_VERSION } from './version';

function isUpToDate(): boolean {
const extensionInstalledAt = configStore.get('fileManagerExtensionVersion');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is this variable name incorrect?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The variable was named incorrectly, but it has now been corrected.

return false;
}

return extensionInstalledAt >= LATEST_EXTENSION_VERSION;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

From what I have read, you are replacing entirely the version of the old nautilusExtensionVersion to a new fileManagerExtensionVersion with no plan on "migrating", what will happen to the users that have been using the app and have the old value? that behaviour is not documented anywhere (perhaps i have overlooked it)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

There's no need to have a migration plan for existing users; all that will happen is that the extension will be reinstalled and the application will continue to function normally. The new field will be created in the settings, and the next time there's an update to the extension, that field will be used to trigger its reinstallation.

Comment on lines +8 to +10
ipcMain.handle('get-file-manager-availability', async () => {
const fileManager = await detectAvailableFileManager();
return fileManager !== null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: would it make sense to expose an isFileManagerAvailable function just like we had with isNautilusAvailable and have the IPC handler delegate to it? That would keep the handler declarative.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

@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: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/file-manager-extension-smoke.yml:
- Around line 25-26: Update the actions/checkout@v4 step in the smoke-test
workflow to set persist-credentials to false, ensuring later steps cannot read
the stored GITHUB_TOKEN from Git configuration.

In `@assets/dolphin/internxt-dolphin-actions.sh`:
- Around line 14-21: Update the root validation around file_path and root_folder
to use os.path.commonpath and confirm it exactly matches root_folder before
deriving relative_path. Preserve the existing empty-output and early-exit
behavior for paths outside the root, then slice only after this component-aware
check.
- Around line 57-59: Add bounded connection and total timeouts to the curl
invocation in the copy-link request within the response hydration flow, ensuring
stalled HTTP requests cannot block the Dolphin action indefinitely while
preserving the existing silent failure and empty-response handling.
- Around line 51-58: Update encode_relative_path and the URL construction in the
copy-link request so the complete Base64 value is percent-encoded as a single
path segment before appending it to /copy-link/. Preserve the existing
empty-value exit and ensure the server receives the same decoded value through
req.params.path.

In `@package.json`:
- Line 38: Update the smoke:file-manager-extension script in package.json to
unset NODE_ENV or set it to production, ensuring copyExtensionFile() exercises
the production fs.cp installation path rather than the development fs.link path.

In `@README.md`:
- Around line 25-84: Fix the KDE Wallet section hierarchy in the README: change
“Prerequisites for KDE based distros” to an H3 sibling under Installation,
hyphenate it as “KDE-based distros,” and change “### Step 3: Configure KDE
Wallet for GPG” to H4 so it matches the other Method 2 step headings.

In `@src/backend/features/file-manager-extension/file-manager-extension-smoke.ts`:
- Around line 31-47: Replace the hardcoded path logic in getExpectedPaths with
values derived from getFileManagerConfig. In run(), await the configuration and
assert asset destinations from config.assets, including each asset’s template
and executable flags; update the Dolphin-specific checks to follow the flags on
the corresponding assets.

In `@src/backend/features/file-manager-extension/service.test.ts`:
- Around line 33-37: Restore the process-wide NODE_ENV value after each test in
the suite containing the beforeEach setup. Capture the original value before
overriding it, then restore that value in an afterEach hook while keeping the
existing mock setup unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a5777a9f-d4d3-48b8-bf1e-9546f6070d82

📥 Commits

Reviewing files that changed from the base of the PR and between dfe207d and be7f20e.

📒 Files selected for processing (17)
  • .eslintrc.js
  • .github/workflows/file-manager-extension-smoke.yml
  • README.md
  • assets/dolphin/internxt-dolphin-actions.sh
  • assets/dolphin/internxt-virtual-drive.desktop
  • package.json
  • src/backend/features/file-manager-extension/constants.ts
  • src/backend/features/file-manager-extension/detect-available.test.ts
  • src/backend/features/file-manager-extension/detect-available.ts
  • src/backend/features/file-manager-extension/file-manager-extension-smoke.ts
  • src/backend/features/file-manager-extension/install.test.ts
  • src/backend/features/file-manager-extension/install.ts
  • src/backend/features/file-manager-extension/service.test.ts
  • src/backend/features/file-manager-extension/service.ts
  • src/backend/features/file-manager-extension/version.ts
  • src/core/electron/paths.ts
  • tests/smoke/file-manager-extension/smoke-electron-mock.cjs
💤 Files with no reviewable changes (1)
  • .eslintrc.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/backend/features/file-manager-extension/install.ts
  • src/backend/features/file-manager-extension/install.test.ts
  • src/backend/features/file-manager-extension/version.ts

Comment on lines +25 to +26
- name: Check out Git repository
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Disable credential persistence on checkout.

This job only reads the repository; it never pushes. Set persist-credentials: false on actions/checkout@v4 so the GITHUB_TOKEN credential isn't left in the git config for later steps (e.g., npm ci, which runs arbitrary install scripts) to read.

🔒 Proposed fix
       - name: Check out Git repository
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
📝 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
- name: Check out Git repository
uses: actions/checkout@v4
- name: Check out Git repository
uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.28.0)

[warning] 25-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/file-manager-extension-smoke.yml around lines 25 - 26,
Update the actions/checkout@v4 step in the smoke-test workflow to set
persist-credentials to false, ensuring later steps cannot read the stored
GITHUB_TOKEN from Git configuration.

Source: Linters/SAST tools

Comment on lines +14 to +21
file_path = os.path.realpath(sys.argv[1])
root_folder = os.path.realpath(sys.argv[2])

if not file_path.startswith(root_folder):
print("")
sys.exit(0)

relative_path = file_path[len(root_folder):]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a component-aware root check.

Line [17] accepts sibling paths such as /home/user/Internxt Drive Backup/file.txt. The helper then sends a path outside ROOT_FOLDER. Use os.path.commonpath before slicing the relative path.

Proposed fix
-if not file_path.startswith(root_folder):
+try:
+    is_inside_root = os.path.commonpath((file_path, root_folder)) == root_folder
+except ValueError:
+    is_inside_root = False
+
+if not is_inside_root:
     print("")
     sys.exit(0)
📝 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
file_path = os.path.realpath(sys.argv[1])
root_folder = os.path.realpath(sys.argv[2])
if not file_path.startswith(root_folder):
print("")
sys.exit(0)
relative_path = file_path[len(root_folder):]
file_path = os.path.realpath(sys.argv[1])
root_folder = os.path.realpath(sys.argv[2])
try:
is_inside_root = os.path.commonpath((file_path, root_folder)) == root_folder
except ValueError:
is_inside_root = False
if not is_inside_root:
print("")
sys.exit(0)
relative_path = file_path[len(root_folder):]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/dolphin/internxt-dolphin-actions.sh` around lines 14 - 21, Update the
root validation around file_path and root_folder to use os.path.commonpath and
confirm it exactly matches root_folder before deriving relative_path. Preserve
the existing empty-output and early-exit behavior for paths outside the root,
then slice only after this component-aware check.

Comment on lines +51 to +58
encoded="$(encode_relative_path "$file_path")"

if [ -z "$encoded" ]; then
exit 0
fi

local response
response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || 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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

URL-encode the Base64 path segment.

Line [58] inserts standard Base64 directly into /copy-link/:path. Standard Base64 can contain /, so valid paths can become multiple route segments and fail before req.params.path reaches src/apps/drive/hydration-api/controllers/contents.ts:145-159. Encode the complete segment before constructing the URL, or switch both sides to URL-safe Base64.

Proposed fix
   local encoded
   encoded="$(encode_relative_path "$file_path")"
+  local encoded_url
+  encoded_url="$(python3 - "$encoded" <<'PY'
+from urllib.parse import quote
+import sys
+
+print(quote(sys.argv[1], safe=""))
+PY
+)"
 
   if [ -z "$encoded" ]; then
     exit 0
   fi
 
   local response
-  response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
+  response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded_url" 2>/dev/null || true)"
📝 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
encoded="$(encode_relative_path "$file_path")"
if [ -z "$encoded" ]; then
exit 0
fi
local response
response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
encoded="$(encode_relative_path "$file_path")"
local encoded_url
encoded_url="$(python3 - "$encoded" <<'PY'
from urllib.parse import quote
import sys
print(quote(sys.argv[1], safe=""))
PY
)"
if [ -z "$encoded" ]; then
exit 0
fi
local response
response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded_url" 2>/dev/null || true)"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/dolphin/internxt-dolphin-actions.sh` around lines 51 - 58, Update
encode_relative_path and the URL construction in the copy-link request so the
complete Base64 value is percent-encoded as a single path segment before
appending it to /copy-link/. Preserve the existing empty-value exit and ensure
the server receives the same decoded value through req.params.path.

Comment on lines +57 to +59
local response
response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
if [ -z "$response" ]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Bound the local HTTP request.

Line [58] has no connection or total timeout. If the hydration service accepts the connection but stops responding, the Dolphin action can remain open indefinitely. Add bounded timeouts.

Proposed fix
-  response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
+  response="$(curl -sS --connect-timeout 2 --max-time 10 \
+    -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
📝 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
local response
response="$(curl -sS -X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
if [ -z "$response" ]; then
local response
response="$(curl -sS --connect-timeout 2 --max-time 10 \
-X POST "$BASE_URL/copy-link/$encoded" 2>/dev/null || true)"
if [ -z "$response" ]; then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/dolphin/internxt-dolphin-actions.sh` around lines 57 - 59, Add bounded
connection and total timeouts to the curl invocation in the copy-link request
within the response hydration flow, ensuring stalled HTTP requests cannot block
the Dolphin action indefinitely while preserving the existing silent failure and
empty-response handling.

Comment thread package.json
Comment thread README.md
Comment on lines +25 to +84
## Prerequisites for KDE based distros

### KDE Wallet Configuration Guide

Our application requires the KDE key manager to be properly configured. Depending on your security needs, you can choose between two methods:

* **Method 1 (Recommended / Easy):** Uses standard symmetric encryption with a master password. It is fast, requires no additional software, and supports **automatic unlocking when you log in**.
* **Method 2 (Advanced / GPG):** Uses an OpenPGP key pair via Kleopatra for higher security, though it requires manual entry of your passphrase or PIN upon logging in.

> **Why Kleopatra?** It is the official KDE key manager, offering native integration with KDE Wallet, fewer permission conflicts, and a user-friendly setup wizard compared to generic GPG tools.
>
> For reference, Electron's secure storage API is documented here: [safe-storage](https://www.electronjs.org/docs/latest/api/safe-storage).

---

### Method 1: Standard Setup (Easy & Recommended)

This is the simplest way to set up KDE Wallet and allows seamless automatic unlocking upon system login.

#### Step 1: Open KDE Wallet Settings
1. Open **System Settings**.
2. Navigate to **KDE Wallet** (or search for *Wallet* in the search bar).
3. Ensure **Enable the KDE wallet subsystem** is checked.

#### Step 2: Create a New Wallet
1. Under **Automatic Wallet Selection**, click **Create New Wallet...**
2. Enter a name for your wallet (e.g., `kdewallet`).
3. Select **Blowfish encryption** (standard password) and click **Next**.
4. Enter and confirm your **Master Password**.
> **Note:** If you set this password to match your Linux user login password, the wallet will unlock automatically when you sign in!
5. Click **Finish**.

---

### Method 2: GPG Key Setup (Advanced)

Use this method if you prefer asymmetric GPG encryption managed via external key managers.

#### Step 1: Install Kleopatra
Install **Kleopatra**, which will be used to generate your GPG encryption key:

```bash
sudo apt update && sudo apt install kleopatra
```

#### Step 2: Generate a GPG Key Pair
1. Open **Kleopatra** and click **New Key Pair** (or **File > New Key Pair**).
2. Select **Create a personal OpenPGP key pair**.
3. Enter your **Name** and **Email Address**.
4. Click **Create** (or **Finish**) to complete the setup.

### Step 3: Configure KDE Wallet for GPG
1. Open **System Settings** and search for **KDE Wallet**.
2. Under **Automatic Wallet Selection**, click **Create New Wallet...**
3. Select **Use GPG encryption for added security** and click **Next**.
4. Choose the GPG key you created earlier in Kleopatra and click **Finish**.

---


Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix heading hierarchy in the new KDE Wallet section.

This section has two heading-level inconsistencies:

  1. "## Prerequisites for KDE based distros" (line 25) is an H2 inserted between "### .deb Package (Recommended)" and "### AppImage", both H3 subsections of "## Installation". This makes "### AppImage" render as nested under "## Prerequisites for KDE based distros" in a generated table of contents. Either demote this section to H3 (a sibling of ".deb Package" and "AppImage" under "## Installation"), or move it entirely outside the "## Installation" section.
  2. "### Step 3: Configure KDE Wallet for GPG" (line 76) uses H3, while its siblings "#### Step 1: Install Kleopatra" and "#### Step 2: Generate a GPG Key Pair" use H4. Align Step 3 to H4 for consistency.

Also, "KDE based distros" (line 25) should be hyphenated as "KDE-based distros".

🧰 Tools
🪛 LanguageTool

[grammar] ~25-~25: Use a hyphen to join words.
Context: ..._amd64.deb ``` ## Prerequisites for KDE based distros ### KDE Wallet Configurat...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 25 - 84, Fix the KDE Wallet section hierarchy in the
README: change “Prerequisites for KDE based distros” to an H3 sibling under
Installation, hyphenate it as “KDE-based distros,” and change “### Step 3:
Configure KDE Wallet for GPG” to H4 so it matches the other Method 2 step
headings.

Source: Linters/SAST tools

Comment on lines +31 to +47
function getExpectedPaths({ manager }: { manager: SupportedFileManager }) {
const home = homedir();

if (manager === 'nautilus') {
return [join(home, '.local/share/nautilus-python/extensions/internxt-virtual-drive.py')];
}

if (manager === 'nemo') {
return [join(home, '.local/share/nemo-python/extensions/internxt-virtual-drive.py')];
}

return [
join(home, '.local/share/kio/servicemenus/internxt-virtual-drive.desktop'),
join(home, '.local/share/kservices5/ServiceMenus/internxt-virtual-drive.desktop'),
join(home, '.local/share/internxt-dolphin-extension/internxt-dolphin-actions.sh'),
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)file-manager-extension-smoke\.ts$|(^|/)file-manager-extension-service\.ts$|constants\.ts$|ser' | sed -n '1,120p'

echo
echo "== smoke outline =="
f="src/backend/features/file-manager-extension/file-manager-extension-smoke.ts"
if [ -f "$f" ]; then
  wc -l "$f"
  ast-grep outline "$f" --view compact || true
  echo
  sed -n '1,190p' "$f" | nl -ba
fi

echo
echo "== candidate service/constants =="
for f in src/backend/features/file-manager-extension/*.ts; do
  echo "--- $f ($(wc -l < "$f")) ---"
  rg -n "getFileManagerConfig|getFileManager|assets|destination|nautilus|nemo|dolphin|template|executable|SupportedFileManager" "$f" || true
done

Repository: internxt/drive-desktop-linux

Length of output: 9072


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== smoke.ts =="
python3 - <<'PY'
from pathlib import Path
p=Path('src/backend/features/file-manager-extension/file-manager-extension-smoke.ts')
text=p.read_text()
for i,line in enumerate(text.splitlines(),1):
    print(f"{i:4}: {line}")
PY

echo
echo "== file-manager-extension files =="
for f in src/backend/features/file-manager-extension/*.ts; do
  echo "--- $f ---"
  wc -l "$f"
  echo "-- symbols --"
  ast-grep outline "$f" --view names || true
  echo "-- relevant searches --"
  rg -n "getFileManagerConfig|getFileManager|SupportedFileManager|assets|destination|template|executable|nautilus|nemo|internxt-dolphin|const|function " "$f" || true
done

Repository: internxt/drive-desktop-linux

Length of output: 23684


Derive expected paths from getFileManagerConfig.

getExpectedPaths duplicates asset destinations from service.ts. service.ts also owns template and executable flags, while this test hardcodes Dolphin only. Import getFileManagerConfig, await it in run(), and assert config.assets.map((asset) => asset.destination) plus the per-asset flags; update Dolphin template/executable checks where each asset sets them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/features/file-manager-extension/file-manager-extension-smoke.ts`
around lines 31 - 47, Replace the hardcoded path logic in getExpectedPaths with
values derived from getFileManagerConfig. In run(), await the configuration and
assert asset destinations from config.assets, including each asset’s template
and executable flags; update the Dolphin-specific checks to follow the flags on
the corresponding assets.

Comment on lines +33 to +37
beforeEach(() => {
vi.clearAllMocks();
process.env.NODE_ENV = 'development';
detectAvailableFileManagerMock.mockResolvedValue('nautilus');
doesFileExistMock.mockResolvedValue(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restore NODE_ENV after each test.

Line 35 changes a process-wide value. The suite never restores it. A later test in the same worker can inherit development and select different behavior.

Proposed fix
+const originalNodeEnv = process.env.NODE_ENV;
+
 describe('service', () => {
@@
   beforeEach(() => {
@@
     doesFileExistMock.mockResolvedValue(false);
   });
+
+  afterEach(() => {
+    if (originalNodeEnv === undefined) {
+      delete process.env.NODE_ENV;
+    } else {
+      process.env.NODE_ENV = originalNodeEnv;
+    }
+  });
📝 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
beforeEach(() => {
vi.clearAllMocks();
process.env.NODE_ENV = 'development';
detectAvailableFileManagerMock.mockResolvedValue('nautilus');
doesFileExistMock.mockResolvedValue(false);
const originalNodeEnv = process.env.NODE_ENV;
describe('service', () => {
beforeEach(() => {
vi.clearAllMocks();
process.env.NODE_ENV = 'development';
detectAvailableFileManagerMock.mockResolvedValue('nautilus');
doesFileExistMock.mockResolvedValue(false);
});
afterEach(() => {
if (originalNodeEnv === undefined) {
delete process.env.NODE_ENV;
} else {
process.env.NODE_ENV = originalNodeEnv;
}
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/features/file-manager-extension/service.test.ts` around lines 33
- 37, Restore the process-wide NODE_ENV value after each test in the suite
containing the beforeEach setup. Capture the original value before overriding
it, then restore that value in an afterEach hook while keeping the existing mock
setup unchanged.

@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
76.7% Coverage on New Code (required ≥ 80%)
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

const destinationExists = await doesFileExist(destination);
if (destinationExists) {
if (asset.executable) {
await fs.chmod(destination, 0o755);
}

if (asset.executable) {
await fs.chmod(destination, 0o755);
@egalvis27
egalvis27 requested a review from AlexisMora August 4, 2026 18:08
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.

3 participants