feat: Add Internxt Virtual Drive extension for Nemo file manager - #409
feat: Add Internxt Virtual Drive extension for Nemo file manager#409egalvis27 wants to merge 5 commits into
Conversation
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (27)
💤 Files with no reviewable changes (14)
📝 WalkthroughWalkthroughAdds generic Nautilus/Nemo detection, file-manager extension lifecycle management, persisted extension versions, sharing-link generation, Nemo virtual-drive integration, and generic availability reporting through IPC and the renderer. ChangesFile-manager extension support
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 extension version
ExtensionInstaller->>FileManager: reload detected manager
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 winComplete 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 winRename 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 valueRemove 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 valueRemove 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
📒 Files selected for processing (23)
assets/python-nemo/internxt-virtual-drive.pyknip.jsonsrc/apps/main/auth/service.test.tssrc/apps/main/config.tssrc/apps/main/config/save-config.tssrc/apps/main/interface.d.tssrc/apps/main/preload.d.tssrc/apps/main/preload.jssrc/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.test.tsxsrc/apps/renderer/pages/Widget/InfoBanners/Banners/NautilusUnavailable.tsxsrc/backend/features/file-manager-extension/detect-available.test.tssrc/backend/features/file-manager-extension/detect-available.tssrc/backend/features/file-manager-extension/install.test.tssrc/backend/features/file-manager-extension/install.tssrc/backend/features/file-manager-extension/service.test.tssrc/backend/features/file-manager-extension/service.tssrc/backend/features/file-manager-extension/version.tssrc/core/bootstrap/register-app-ready-flow.tssrc/core/bootstrap/register-main-ipc-handlers.tssrc/core/bootstrap/register-session-event-handlers.tssrc/core/electron/store/app-store.interface.tssrc/core/electron/store/defaults.tsvitest.setup.main.ts
| 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) => { |
There was a problem hiding this comment.
🩺 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.
| export async function deleteExtensionFile(): Promise<void> { | ||
| const config = await getFileManagerConfig(); | ||
| if (!config) return; | ||
|
|
||
| const destination = path.join(config.destinationDir, extensionFileName); | ||
| const isThere = await doesFileExist(destination); | ||
| if (!isThere) return; | ||
|
|
||
| await fs.rm(destination); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove extensions for both managers during cleanup.
This only deletes from the currently detected manager. If a user installs under Nautilus, switches to Nemo, then logs out, the Nautilus extension remains installed and active. Cleanup should inspect and remove both known destination paths without depending on current detection.
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { exec } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🤖 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.ts` around lines 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.
There was a problem hiding this comment.
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 winAssert 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 winMake the
execmocks honor the child-process contract.
reloadFileManager()attaches anerrorlistener to the object returned byexec. These mocks invoke the callback synchronously and return nothing, so the promise may resolve before the invalidchildProcess.on(...)call occurs. Return an EventEmitter-like object and invoke the callback afterexecMockreturns; otherwise these tests can mask regressions in the reload setup.This test double should match the
reloadFileManager()contract insrc/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
📒 Files selected for processing (1)
src/backend/features/file-manager-extension/service.test.ts
|
There was a problem hiding this comment.
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
📒 Files selected for processing (27)
src/apps/drive/hydration-api/controllers/contents.test.tssrc/apps/drive/hydration-api/controllers/contents.tssrc/apps/main/auth/service.test.tssrc/apps/main/config.tssrc/apps/main/config/save-config.tssrc/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.test.tssrc/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.tssrc/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.test.tssrc/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.tssrc/backend/features/file-manager-extension/create-sharing-link/generate-link.test.tssrc/backend/features/file-manager-extension/create-sharing-link/generate-link.tssrc/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.test.tssrc/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.tssrc/backend/features/file-manager-extension/create-sharing-link/types.tssrc/backend/features/nautilus-extension/install.test.tssrc/backend/features/nautilus-extension/install.tssrc/backend/features/nautilus-extension/is-nautilus-available.test.tssrc/backend/features/nautilus-extension/is-nautilus-available.tssrc/backend/features/nautilus-extension/reload.test.tssrc/backend/features/nautilus-extension/reload.tssrc/backend/features/nautilus-extension/service.test.tssrc/backend/features/nautilus-extension/service.tssrc/backend/features/nautilus-extension/uninstall.test.tssrc/backend/features/nautilus-extension/uninstall.tssrc/backend/features/nautilus-extension/version.tssrc/core/electron/store/app-store.interface.tssrc/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
There was a problem hiding this comment.
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
📒 Files selected for processing (27)
src/apps/drive/hydration-api/controllers/contents.test.tssrc/apps/drive/hydration-api/controllers/contents.tssrc/apps/main/auth/service.test.tssrc/apps/main/config.tssrc/apps/main/config/save-config.tssrc/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.test.tssrc/backend/features/file-manager-extension/create-sharing-link/create-sharing-result.tssrc/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.test.tssrc/backend/features/file-manager-extension/create-sharing-link/fetch-random-domain.tssrc/backend/features/file-manager-extension/create-sharing-link/generate-link.test.tssrc/backend/features/file-manager-extension/create-sharing-link/generate-link.tssrc/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.test.tssrc/backend/features/file-manager-extension/create-sharing-link/resolve-shareable-item.tssrc/backend/features/file-manager-extension/create-sharing-link/types.tssrc/backend/features/nautilus-extension/install.test.tssrc/backend/features/nautilus-extension/install.tssrc/backend/features/nautilus-extension/is-nautilus-available.test.tssrc/backend/features/nautilus-extension/is-nautilus-available.tssrc/backend/features/nautilus-extension/reload.test.tssrc/backend/features/nautilus-extension/reload.tssrc/backend/features/nautilus-extension/service.test.tssrc/backend/features/nautilus-extension/service.tssrc/backend/features/nautilus-extension/uninstall.test.tssrc/backend/features/nautilus-extension/uninstall.tssrc/backend/features/nautilus-extension/version.tssrc/core/electron/store/app-store.interface.tssrc/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()returnsnullfor an empty list, but this flow still creates a sharing record and copiesnull/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.


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-extensionmodule 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