Skip to content
Merged
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
15 changes: 12 additions & 3 deletions CLI/cmux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3576,6 +3576,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 @@ -3761,8 +3762,10 @@ struct CMUXCLI {
}
// `cmux ssh` is an explicit "open this remote workspace now" action,
// so we intentionally select the newly created workspace after wiring
// up the remote connection.
_ = try client.sendV2(method: "workspace.select", params: selectParams)
// up the remote connection — unless --no-focus is passed.
if !sshOptions.noFocus {
_ = try client.sendV2(method: "workspace.select", params: selectParams)
}
Comment on lines 3763 to +3768

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make focus opt-in here, not opt-out.

cmux ssh still calls workspace.select by default, so scripted SSH workspace creation continues to steal selection unless callers know to pass --no-focus. For a non-focus command, the safe behavior should be the default and any focus change should be explicit.

Based on learnings: Socket/CLI commands must not steal macOS app focus; only explicit focus-intent commands may mutate in-app focus/selection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLI/cmux.swift` around lines 3763 - 3768, The code currently calls
client.sendV2("workspace.select", params: selectParams) unless
sshOptions.noFocus is true, which makes focus the default; change this to make
focus opt-in by flipping the flag semantics: add or use an explicit
sshOptions.focus boolean (or invert sshOptions.noFocus to focus) and only call
client.sendV2(method: "workspace.select", params: selectParams) when that
explicit focus flag is true; update the option parsing/CLI flag for `cmux ssh`
to provide a `--focus` (default false) or invert the existing flag behavior, and
adjust any docs/tests that mention --no-focus accordingly so workspace.select is
only invoked when the user explicitly requests focus.

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 @@ -3810,6 +3813,7 @@ struct CMUXCLI {
var port: Int?
var identityFile: String?
var workspaceName: String?
var noFocus = false
var sshOptions: [String] = []
var extraArguments: [String] = []

Expand Down Expand Up @@ -3848,6 +3852,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 @@ -3883,6 +3890,7 @@ struct CMUXCLI {
port: port,
identityFile: identityFile,
workspaceName: workspaceName,
noFocus: noFocus,
sshOptions: sshOptions,
extraArguments: extraArguments,
localSocketPath: localSocketPath,
Expand Down Expand Up @@ -6410,6 +6418,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
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Example:
cmux ssh dev@my-host
Expand Down Expand Up @@ -12608,7 +12617,7 @@ struct CMUXCLI {
workspace-action --action <name> [--workspace <id|ref|index>] [--title <text>] [--color <name|#hex>]
list-workspaces
new-workspace [--name <title>] [--cwd <path>] [--command <text>]
ssh <destination> [--name <title>] [--port <n>] [--identity <path>] [--ssh-option <opt>] [-- <remote-command-args>]
ssh <destination> [--name <title>] [--port <n>] [--identity <path>] [--ssh-option <opt>] [--no-focus] [-- <remote-command-args>]
remote-daemon-status [--os <darwin|linux>] [--arch <arm64|amd64>]
new-split <left|right|up|down> [--workspace <id|ref>] [--surface <id|ref>] [--panel <id|ref>]
list-panes [--workspace <id|ref>]
Expand Down
Loading