Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions CLI/cmux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3294,6 +3294,7 @@ struct CMUXCLI {
let port: Int?
let identityFile: String?
let workspaceName: String?
let noFocus: Bool
let sshOptions: [String]
let extraArguments: [String]
let localSocketPath: String
Expand Down Expand Up @@ -3464,7 +3465,9 @@ struct CMUXCLI {
if let workspaceWindowId, !workspaceWindowId.isEmpty {
selectParams["window_id"] = workspaceWindowId
}
_ = try client.sendV2(method: "workspace.select", params: selectParams)
if !sshOptions.noFocus {
_ = try client.sendV2(method: "workspace.select", params: selectParams)
}
let remoteState = ((configuredPayload["remote"] as? [String: Any])?["state"] as? String) ?? "unknown"
cliDebugLog(
"cli.ssh.remote.configure.ok workspace=\(String(workspaceId.prefix(8))) state=\(remoteState)"
Expand Down Expand Up @@ -3507,11 +3510,12 @@ struct CMUXCLI {
}
}

private func parseSSHCommandOptions(_ commandArgs: [String], localSocketPath: String = "", remoteRelayPort: Int = 0) throws -> SSHCommandOptions {
func parseSSHCommandOptions(_ commandArgs: [String], localSocketPath: String = "", remoteRelayPort: Int = 0) throws -> SSHCommandOptions {
var destination: String?
var port: Int?
var identityFile: String?
var workspaceName: String?
var noFocus = false
var sshOptions: [String] = []
var extraArguments: [String] = []

Expand Down Expand Up @@ -3550,6 +3554,9 @@ struct CMUXCLI {
}
workspaceName = commandArgs[index + 1]
index += 2
case "--no-focus":
noFocus = true
index += 1
case "--ssh-option":
guard index + 1 < commandArgs.count else {
throw CLIError(message: "ssh: --ssh-option requires a value")
Expand Down Expand Up @@ -3585,6 +3592,7 @@ struct CMUXCLI {
port: port,
identityFile: identityFile,
workspaceName: workspaceName,
noFocus: noFocus,
sshOptions: sshOptions,
extraArguments: extraArguments,
localSocketPath: localSocketPath,
Expand Down Expand Up @@ -6012,6 +6020,7 @@ struct CMUXCLI {
--port <n> SSH port
--identity <path> SSH identity file path
--ssh-option <opt> Extra SSH -o option (repeatable)
--no-focus Create workspace without switching to it

Example:
cmux ssh dev@my-host
Expand Down
19 changes: 19 additions & 0 deletions cmuxTests/CLIProcessRunnerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ final class CLIProcessRunnerTests: XCTestCase {
port: nil,
identityFile: nil,
workspaceName: nil,
noFocus: false,
sshOptions: [],
extraArguments: [],
localSocketPath: "",
Expand Down Expand Up @@ -411,6 +412,24 @@ print(out.decode("utf-8", "replace"), end="")
XCTAssertTrue(remoteCommand.contains("base64"), remoteCommand)
}

func testParseSSHCommandOptionsNoFocusFlag() throws {
let cli = CMUXCLI(args: [])

let withFlag = try cli.parseSSHCommandOptions(["user@host", "--no-focus"])
XCTAssertTrue(withFlag.noFocus)
XCTAssertEqual(withFlag.destination, "user@host")

let withoutFlag = try cli.parseSSHCommandOptions(["user@host"])
XCTAssertFalse(withoutFlag.noFocus)

let withOtherFlags = try cli.parseSSHCommandOptions([
"user@host", "--name", "mybox", "--no-focus", "--port", "2222",
])
XCTAssertTrue(withOtherFlags.noFocus)
XCTAssertEqual(withOtherFlags.workspaceName, "mybox")
XCTAssertEqual(withOtherFlags.port, 2222)
}

func testEncodedRemoteBootstrapCommandEscapesPercentsForSSHRemoteCommand() throws {
let cli = CMUXCLI(args: [])
let remoteCommand = cli.sshPercentEscapedRemoteCommand(
Expand Down