Skip to content

Add remote File Explorer downloads - #3925

Closed
austinywang wants to merge 28 commits into
mainfrom
issue-3637-download-remote-files-file-explorer
Closed

austinywang wants to merge 28 commits into
mainfrom
issue-3637-download-remote-files-file-explorer

Conversation

@austinywang

@austinywang austinywang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a remote-only File Explorer context menu action to download SSH-backed files and directories to a chosen local folder.
  • Reuse scp-style SSH options for remote-to-local downloads, including directory recursion, remote path quoting, IPv6 destination handling, and background-safe ControlMaster filtering.
  • Track the selected workspace's initial local directory as the default download destination and show completion/failure feedback.

Verification

  • git diff --check
  • jq empty Resources/Localizable.xcstrings
  • Local tests/builds not run per repository and issue instructions; CI owns test execution before the tagged launch.

Closes #3637


Note

Medium Risk
Adds new SSH download flow that spawns and manages scp processes (timeouts, cancellation, path/option handling), which could impact remote workflow reliability and error handling.

Overview
Adds a remote-only File Explorer context menu action, Download to Local…, that prompts for a destination folder and downloads the selected SSH-backed file or directory to disk via scp.

This extends the SSH file explorer transport with download(...), implements a new ProcessSSHFileExplorerTransport that runs scp with quoting/IPv6 destination handling, background-safe SSH option filtering, destination validation, and timeout/cancellation behavior, and wires per-workspace notifications/alerts for success/failure.

Also centralizes shell single-quoting and SSH option parsing in new helpers (ShellArgumentQuoting, SSHCommandArgumentSupport), tracks a default download directory (LocalDirectoryPathNormalization + defaultLocalDownloadDirectory propagation), adds full localization strings for the new UI/errors, and expands tests around download arguments/errors and SSH option parsing edge cases.

Reviewed by Cursor Bugbot for commit 66b7d50. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds a remote‑only “Download to Local…” action in File Explorer to save SSH‑backed files or folders to a chosen local folder via scp, with safe SSH defaults, strong quoting, a 30‑minute timeout, and per‑workspace notifications. Fully localizes the flow and SSH error strings across app languages, implementing #3637.

  • New Features

    • Context menu on SSH items opens a folder picker and remembers a per‑workspace default (seeded from the workspace’s initial local dir or active tab cwd; falls back to Downloads/home). Clears when no selection exists.
    • scp download supports files/directories, IPv6, strict host‑key defaults, background‑safe option filtering, and robust path quoting. Validates the destination and shows localized completion/errors.
  • Bug Fixes

    • Hardened process lifecycle and cancellation (async wait, concurrent output capture, 30‑min timeout, SIGTERM→SIGKILL), with sanitized launch failures and localized SSH error messages.
    • Transport isolation via ProcessSSHFileExplorerTransport and shared helpers (ShellArgumentQuoting, SSHCommandArgumentSupport, LocalDirectoryPathNormalization), with workspaceId threading and a synced default download directory between tabs. Tests cover quoting, launch failures, and ControlPath values containing = or spaces.

Written for commit 66b7d50. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Download files and directories from remote servers directly to your local machine. Access the new "Download to Local" option from the file explorer context menu and select your preferred destination directory.
  • Localization

    • Added English and Japanese translations for the download feature, including download prompts, completion confirmations, and error messages.

Review Change Stack

@vercel

vercel Bot commented May 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 19, 2026 8:29am
cmux-staging Building Building Preview, Comment May 19, 2026 8:29am

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements a "Download to Local…" feature for SSH-backed file browsing, enabling remote-to-local file transfers via SCP. Changes include localization strings, SCP backend API with refactored process management, download directory configuration wiring, FileExplorerView UI flows with notifications, and comprehensive test coverage.

Changes

Remote File Download Feature

Layer / File(s) Summary
Localization Strings
Resources/Localizable.xcstrings
Adds UI text for context menu action, destination picker dialog, completion/failure notifications, and error messages in English and Japanese.
SSH Download Backend via SCP
Sources/FileExplorerStore.swift
Extends SSHFileExplorerTransport protocol with download(...) method. SSHFileExplorerProvider delegates to the transport. ProcessSSHFileExplorerTransport implements SCP download: validates local destination, constructs command arguments (with IPv6 bracketing and SSH option normalization), runs process with concurrent I/O draining, timeout enforcement, and graceful termination. Adds defaultLocalDownloadDirectory state and setDefaultLocalDownloadDirectory(_:) validation. Refactors SSH command execution to use shared CommandProcess for concurrent stdout/stderr draining and cancellation support. Maps SCP failures to new FileExplorerError cases (invalidDownloadDestination, downloadFailed, downloadTimedOut).
Download Directory Management
Sources/Workspace.swift, Sources/ContentView.swift
Workspace stores initialLocalDirectory and exposes defaultLocalDownloadDirectory computed property that validates path existence and is-directory status. ContentView.syncFileExplorerDirectory() keeps FileExplorerStore.defaultLocalDownloadDirectory synchronized with selected tab and workspace—clearing it when no tab is selected or local directory is empty, setting it from remote workspace's default or trimmed local directory otherwise.
Download UI Flow and Integration
Sources/FileExplorerView.swift, Sources/RightSidebarPanelView.swift
FileExplorerPanelView gains optional workspaceId property and passes it to Coordinator. Coordinator tracks active download state (activeDownloadTask, activeDownloadID) and cancels on deinit. Context menu includes "Download to Local…" for SSH providers, invoking contextMenuDownloadToLocal handler that opens NSOpenPanel destination picker (defaulting to stored download directory), starts async SCP download, and routes completion/failure to notifications (when workspaceId present) or NSAlert sheets (otherwise). Download task finalization ensures only latest in-flight download updates UI. RightSidebarPanelView passes workspaceId to both .files and .find mode file explorer panels.
Tests
cmuxTests/FileExplorerStoreTests.swift
MockSSHFileExplorerTransport adds DownloadRequest struct and download(...) implementation to record requests and return injected result or synthesized path. Tests verify SCP provider delegates to transport with correct parameters, rejects download when provider unavailable, and validates SCP argument construction including IPv6 host bracketing and SSH background-control option handling. Coordinator initialization updated to include workspaceId: nil in two find-search test scenarios.

Sequence Diagram

sequenceDiagram
  participant User
  participant FileExplorerView
  participant SSHFileExplorerProvider
  participant ProcessSSHFileExplorerTransport
  participant SCP as SCP Process
  
  User->>FileExplorerView: Right-click remote file
  FileExplorerView->>FileExplorerView: Show context menu
  User->>FileExplorerView: Select "Download to Local…"
  FileExplorerView->>FileExplorerView: Open destination picker
  User->>FileExplorerView: Choose local directory
  FileExplorerView->>SSHFileExplorerProvider: download(remotePath, isDirectory, toLocalDirectory)
  SSHFileExplorerProvider->>ProcessSSHFileExplorerTransport: download(remotePath, isDirectory, connection, toLocalDirectory)
  ProcessSSHFileExplorerTransport->>ProcessSSHFileExplorerTransport: Validate local destination
  ProcessSSHFileExplorerTransport->>ProcessSSHFileExplorerTransport: Build SCP command args
  ProcessSSHFileExplorerTransport->>SCP: Run scp with timeout/cancellation
  SCP-->>ProcessSSHFileExplorerTransport: Success or error
  ProcessSSHFileExplorerTransport-->>SSHFileExplorerProvider: Local path or throw error
  SSHFileExplorerProvider-->>FileExplorerView: Return result
  FileExplorerView->>FileExplorerView: Show completion/failure notification or alert
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#3028: Modifies ContentView.syncFileExplorerDirectory() to adjust file-explorer directory and default download directory synchronization logic.
  • manaflow-ai/cmux#1904: Modifies SSH file-transfer and process-execution code including SCP command construction and process cancellation/timeout behavior.
  • manaflow-ai/cmux#819: Updates localization resources in Resources/Localizable.xcstrings with new string keys.

🐰 A fluffy download tunnel appears,
SCP hops through SSH's remote cheers!
From server to Mac, files take flight—
No copy-paste needed, just drag-drop delight! ✨


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (4 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error Swift 6 actor isolation violation: Task at line 681 in FileExplorerView.swift lacks @MainActor while calling @MainActor methods. Add @MainActor to Task: activeDownloadTask = Task { @mainactor [weak self] in. Pattern matches other Tasks in class at lines 111, 601, 1308, 1631.
Cmux Swift @Concurrent ❌ Error Network-heavy async provider.download() is called from @MainActor context without @concurrent annotation or explicit actor hop, violating the swift-concurrent-annotation rule. Add @concurrent to SSHFileExplorerProvider.download() and ProcessSSHFileExplorerTransport.download() methods, or create Task with explicit non-MainActor context like Task(priority: .userInitiated).
Cmux Swift File And Package Boundaries ❌ Error Adds 531 net lines to FileExplorerStore.swift (1793 lines, >800 threshold). Violates 250+ line rule for oversized files. Implements subprocess/SCP logic that should extract to package. Extract ProcessSSHFileExplorerTransport download impl and CommandProcess to new package. This owns subprocess contracts and can test independently. Reduces FileExplorerStore.swift by >200 lines.
Cmux Swift Auxiliary Window Close Shortcuts ❌ Error FileExplorerView.swift adds NSOpenPanel (line 627) with runModal fallback (line 653), creating standalone NSPanel without cmux.* identifier in cmuxAuxiliaryWindowIdentifiers, violating the rule. Either remove runModal fallback for sheet-only behavior, or assign panel identifier "cmux.fileExplorerDownloadDirectory" and register in cmuxAuxiliaryWindowIdentifiers in Sources/cmuxApp.swift.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (10 passed)
Check name Status Explanation
Linked Issues check ✅ Passed All coding requirements from #3637 are met: context menu action for remote downloads [#3637], scp-based file/directory transfer [#3637], default destination directory handling [#3637], and completion/error UI feedback [#3637].
Out of Scope Changes check ✅ Passed All changes are directly related to implementing remote file downloads: localization strings, SSH download API, process execution, UI plumbing, and tests align with the stated objectives and issue requirements.
Cmux Swift Blocking Runtime ✅ Passed Task.sleep and ContinuousClock.sleep used correctly in timeout/grace-period race patterns. NSLock appropriately protects Process callback state in low-level platform bridge.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift code and localization strings. The check applies to TypeScript, JavaScript, shell scripts, and non-Swift runtime code. Swift code is excluded per rule.
Cmux Swift Concurrency ✅ Passed PR implements modern async/await patterns. NSOpenPanel callback is AppKit boundary (allowed). Task properly stored and managed with lifecycle tracking and cancellation support.
Cmux Swift Logging ✅ Passed Download feature code complies with logging rules. FileExplorerStore NSLog calls are DEBUG-guarded. Download UI code has no logging.
Cmux Swiftui State Layout ✅ Passed State management complies. Download task state in Coordinator is @MainActor-protected. defaultLocalDownloadDirectory is not @Published. No render-time mutations or layout violations found.
Cmux Architecture Rethink ✅ Passed Proper structured concurrency, single state owners, clear invariants with UUID gating. No timing patches, split ownership, or duplicated paths.
Title check ✅ Passed The title 'Add remote File Explorer downloads' clearly and concisely summarizes the main change—adding a download feature for remote SSH files in the File Explorer.
Description check ✅ Passed The pull request description exceeds the template requirements with comprehensive summary, verification steps, and detailed context; however, it lacks explicit sections for testing methodology and a demo video URL.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3637-download-remote-files-file-explorer

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.

Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerView.swift
@greptile-apps

greptile-apps Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a "Download to Local…" context menu action to the SSH-backed File Explorer, using scp (in legacy mode) to transfer files and directories from remote hosts to a user-chosen local folder. It also extracts duplicated SSH option-parsing, quoting, and host-bracketing utilities into shared helpers (SSHCommandArgumentSupport, ShellArgumentQuoting, LocalDirectoryPathNormalization).

  • New download flow: ProcessSSHFileExplorerTransport.download(...) runs scp with a 30-minute timeout, concurrent stdout/stderr collection, TerminationWaiter-based async waiting, and a SIGTERM→SIGKILL grace race. FileExplorerView.Coordinator tracks the active download task lifecycle (cancel-on-new, cancel-on-deinit), shows completion/failure via workspace notifications or NSAlert, and persists the default local download directory per workspace.
  • Refactoring: backgroundOptions, hasOptionKey, scpRemoteDestination, singleQuoted, and related helpers were duplicated across Workspace.swift, WorkspaceRemoteSSHBatchCommandBuilder.swift, TerminalSSHSessionDetector.swift, and GhosttyTerminalView.swift; they are now consolidated into new standalone files and all call sites updated.
  • Localization: All 10+ new user-facing strings carry complete translations across all 19 supported locales (ar, bs, da, de, en, es, fr, it, ja, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant).

Confidence Score: 5/5

Safe to merge. Every issue raised in prior review rounds has been corrected, and the new code is well-structured throughout.

All previously flagged issues are resolved: async subprocess management now uses TerminationWaiter continuations and a task-group timeout race instead of semaphores and waitUntilExit; pipe reads are concurrent with process execution; the SIGTERM→SIGKILL grace correctly races the termination signal; the active download Task is stored and cancelled on new download or deinit; actor isolation on the download lifecycle path is statically enforced via @mainactor annotations; error messages use localized exit-status strings rather than raw stderr; scp launch failures are caught and rethrown as a user-friendly FileExplorerError; the remote path is shell-quoted and legacy SCP mode (-O) is enabled; and all new user-facing strings carry complete translations across all 19 supported locales.

No files require special attention.

Important Files Changed

Filename Overview
Sources/ProcessSSHFileExplorerTransport.swift New 588-line file implementing scp download with proper async subprocess management: TerminationWaiter continuation, concurrent OutputCollector readability handlers, withThrowingTaskGroup timeout race, and detached SIGTERM→SIGKILL grace. All previously flagged issues (semaphore, pipe deadlock, raw stderr, launch failure wrapping, remote path quoting, Task.sleep grace) are addressed.
Sources/FileExplorerView.swift Adds download context menu and lifecycle management. Coordinator stores and cancels active download task, guards on downloadID for stale completion suppression, and is @MainActor-annotated throughout. All previously flagged isolation and lifecycle issues are resolved.
Sources/FileExplorerStore.swift Adds download protocol method to SSHFileExplorerTransport, new FileExplorerError cases with fully localized descriptions, and per-store defaultLocalDownloadDirectory property with validated setter. ProcessSSHFileExplorerTransport moved to dedicated file.
Sources/SSHCommandArgumentSupport.swift New shared helpers for SSH option normalization, key lookup, value extraction, background filtering (ControlMaster/ControlPersist), and IPv6 host bracketing. Correctly handles both = and whitespace-delimited option formats with maxSplits:1.
Resources/Localizable.xcstrings All 10+ new user-facing strings (context menu, panel UI, completion, errors) include translated entries for all 19 supported locales. Previously flagged missing-locale issues for sshFailed and remoteCommandExited are now resolved.
Sources/ShellArgumentQuoting.swift New shared POSIX single-quoting helper (replaces four separate private implementations). Correctly uses the ''' escape pattern and is now used consistently across upload, download, and general shell-escaping paths.
Sources/LocalDirectoryPathNormalization.swift New helper that validates a path string is an existing local directory (tilde-expanded, existence + isDirectory checked). Used by FileExplorerStore to validate and persist the default download directory.
Sources/Workspace.swift Removes four duplicated private SSH helpers (shellSingleQuoted, hasSSHOptionKey, backgroundSSHOptions, sshOptionKey) and replaces all call sites with the new shared utilities. No behavioral changes.
cmuxTests/FileExplorerStoreTests.swift Adds tests for shell quoting, downloadTarget path construction, scp argument generation (including ControlPath=value-with-=, path-with-spaces cases), SCP launch failure wrapping, and transport invocation via mock.

Sequence Diagram

sequenceDiagram
    participant User
    participant Coordinator as FileExplorerView.Coordinator (@MainActor)
    participant Store as FileExplorerStore
    participant Provider as SSHFileExplorerProvider
    participant Transport as ProcessSSHFileExplorerTransport (nonisolated)
    participant SCP as /usr/bin/scp

    User->>Coordinator: Right-click → "Download to Local…"
    Coordinator->>User: NSOpenPanel (sheet/modal)
    User->>Coordinator: Choose destination directory (URL)
    Coordinator->>Store: setDefaultLocalDownloadDirectory(localDirectory)
    Coordinator->>Coordinator: cancel activeDownloadTask (if any)
    Coordinator->>Coordinator: "activeDownloadTask = Task @MainActor"
    Coordinator->>Provider: await provider.download(...)
    Provider->>Transport: await transport.download(...)
    Transport->>Transport: downloadTarget() — validate dest, check collision
    Transport->>SCP: CommandProcess.run(timeout: 1800s)
    Note over Transport,SCP: OutputCollector readability handlers + TerminationWaiter
    SCP-->>Transport: terminationHandler → TerminationWaiter.finish(status:)
    Transport->>Transport: outputCollector.finish()
    alt "terminationStatus == 0"
        Transport-->>Coordinator: localPath
        Coordinator->>User: Notification or NSAlert Download Complete
    else "terminationStatus != 0"
        Transport-->>Coordinator: throw FileExplorerError.downloadFailed
        Coordinator->>User: Notification or NSAlert Download Failed
    else timeout 30 min
        Transport->>SCP: SIGTERM then SIGKILL grace race
        Transport-->>Coordinator: throw FileExplorerError.downloadTimedOut
        Coordinator->>User: Download timed out
    else Task cancelled
        Coordinator->>Transport: terminate() via withTaskCancellationHandler
        Transport->>SCP: SIGTERM + detached SIGKILL grace
        Coordinator->>Coordinator: cancelDownloadTask suppress UI
    end
Loading

Reviews (18): Last reviewed commit: "fix: localize remote ssh error strings" | Re-trigger Greptile

Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerView.swift
Comment thread Sources/FileExplorerView.swift Outdated
Comment thread Sources/FileExplorerView.swift
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerView.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
Sources/FileExplorerStore.swift (1)

427-1017: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Extract the SCP/process transport out of FileExplorerStore.swift.

This file is already 1.7k+ lines, and this change adds another large responsibility: subprocess lifecycle, SSH/SCP argument building, timeout handling, output draining, and kill semantics. Please move ProcessSSHFileExplorerTransport / CommandProcess into dedicated source file(s) so FileExplorerStore stays focused on explorer state. As per coding guidelines: “do not accept more than 250 lines added to an existing production Swift file that is already over 800 lines” and “Flag Swift files that mix UI rendering, state ownership, persistence, networking, parsing, subprocess/socket protocol, and platform bridge code in one place.”

🤖 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 `@Sources/FileExplorerStore.swift` around lines 427 - 1017, The file now
contains a large subprocess/SSH/SCP transport implementation
(ProcessSSHFileExplorerTransport and nested
CommandProcess/OutputCollector/TerminationWaiter) that should be extracted into
one or more dedicated source files; move ProcessSSHFileExplorerTransport and its
helper types (CommandProcess, OutputCollector, TerminationWaiter,
SSHCommandResult) into a new file (or files) and keep only the public API
surface used by FileExplorerStore (resolveHomePath, listDirectory, download, and
scpDownloadArgumentsForTesting) exported with appropriate access control; update
references in FileExplorerStore to import/instantiate
ProcessSSHFileExplorerTransport as before, ensure all helper methods used
externally (scpDownloadArgumentsForTesting, shouldBracketIPv6Literal,
scpRemoteDestination, optionKey, normalizedSSHOptions, backgroundSSHOptions,
hasSSHOptionKey, bestErrorLine) have the correct access level or are moved
alongside the transport, preserve existing semantics (timeouts,
termination/force-kill behavior, error types), add any required imports, and run
the build to adjust visibility (fileprivate -> internal/public) and tests.
🤖 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 `@Sources/FileExplorerStore.swift`:
- Around line 862-878: The code builds targetPath but never checks for an
existing local file/dir, risking silent overwrite; before calling runSCPCommand
(the block using scpDownloadArguments and returning targetPath), stat the
filesystem for targetPath and if it exists either throw
FileExplorerError.downloadFailed with a clear message or generate a
non-conflicting target (e.g., append a numeric suffix) and use that new path;
ensure the existence check covers both files and directories and update the
thrown error detail to include the existing path so callers can handle/confirm
before proceeding.

In `@Sources/FileExplorerView.swift`:
- Around line 637-643: The localized message uses String(format:) with a
localized template containing "%@", which is not locale-aware; update the
assignment to build panel.message using String.localizedStringWithFormat so
positional arguments are formatted per locale (i.e., replace the String(format:
String(localized:..., defaultValue:...), node.name) usage in the panel.message
assignment with a call to String.localizedStringWithFormat using the same
localized template and node.name); apply the same change to the other occurrence
that formats with node.name.

---

Outside diff comments:
In `@Sources/FileExplorerStore.swift`:
- Around line 427-1017: The file now contains a large subprocess/SSH/SCP
transport implementation (ProcessSSHFileExplorerTransport and nested
CommandProcess/OutputCollector/TerminationWaiter) that should be extracted into
one or more dedicated source files; move ProcessSSHFileExplorerTransport and its
helper types (CommandProcess, OutputCollector, TerminationWaiter,
SSHCommandResult) into a new file (or files) and keep only the public API
surface used by FileExplorerStore (resolveHomePath, listDirectory, download, and
scpDownloadArgumentsForTesting) exported with appropriate access control; update
references in FileExplorerStore to import/instantiate
ProcessSSHFileExplorerTransport as before, ensure all helper methods used
externally (scpDownloadArgumentsForTesting, shouldBracketIPv6Literal,
scpRemoteDestination, optionKey, normalizedSSHOptions, backgroundSSHOptions,
hasSSHOptionKey, bestErrorLine) have the correct access level or are moved
alongside the transport, preserve existing semantics (timeouts,
termination/force-kill behavior, error types), add any required imports, and run
the build to adjust visibility (fileprivate -> internal/public) and tests.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 21e3361d-bfdd-4164-b5e0-beb6a84d52a5

📥 Commits

Reviewing files that changed from the base of the PR and between 5829da2 and a8f376d.

📒 Files selected for processing (7)
  • Resources/Localizable.xcstrings
  • Sources/ContentView.swift
  • Sources/FileExplorerStore.swift
  • Sources/FileExplorerView.swift
  • Sources/RightSidebarPanelView.swift
  • Sources/Workspace.swift
  • cmuxTests/FileExplorerStoreTests.swift

Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/FileExplorerView.swift Outdated
Comment thread Sources/FileExplorerStore.swift Outdated
Comment thread Sources/ProcessSSHFileExplorerTransport.swift
Comment thread Sources/ProcessSSHFileExplorerTransport.swift
Comment thread Sources/ProcessSSHFileExplorerTransport.swift Outdated
Comment thread Sources/Workspace.swift
Comment thread Sources/ProcessSSHFileExplorerTransport.swift
Comment thread Sources/ProcessSSHFileExplorerTransport.swift

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit dfe7538. Configure here.

Comment thread Sources/FileExplorerStore.swift
Comment thread Sources/SSHCommandArgumentSupport.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 9 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/SSHCommandArgumentSupport.swift">

<violation number="1" location="Sources/SSHCommandArgumentSupport.swift:43">
P2: Parse SSH option values using the first key/value separator (whitespace or `=`), not the first `=` anywhere in the string. The current logic misparses space-separated options whose values contain `=` (for example `ControlPath /tmp/path=foo`), which can break SSH option matching.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/SSHCommandArgumentSupport.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 20 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/FileExplorerView.swift">

<violation number="1" location="Sources/FileExplorerView.swift:837">
P2: Update the default download directory after a successful download so the next picker opens in the user’s last chosen destination.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/FileExplorerView.swift
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 66b7d502 Deployed May 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Download remote files from File Explorer (remote → local)

3 participants