Repository navigation
Fix tmux compat store decoding, layout cleanup, and cross-workspace fallback #2207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
493da5c
e73ee78
2034079
1e11f5b
2a5e6e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10032,10 +10032,14 @@ struct CMUXCLI { | |
| // Claude's agent teams targets arbitrary panes (from list-panes), | ||
| // not necessarily the leader pane from TMUX_PANE. Override the | ||
| // target to anchor all teammate splits to the leader surface. | ||
| // Only apply caller anchoring when the caller's workspace resolves | ||
| // successfully. Falling back to target.workspaceId would pair | ||
| // the caller's surface with a different workspace, creating an | ||
| // invalid cross-workspace split. | ||
| let store = loadTmuxCompatStore() | ||
| if let callerSurface = tmuxCallerSurfaceHandle(), | ||
| let callerWorkspace = tmuxCallerWorkspaceHandle() { | ||
| let wsId = (try? resolveWorkspaceId(callerWorkspace, client: client)) ?? target.workspaceId | ||
| let callerWorkspace = tmuxCallerWorkspaceHandle(), | ||
| let wsId = try? resolveWorkspaceId(callerWorkspace, client: client) { | ||
| if let mvState = store.mainVerticalLayouts[wsId], | ||
| let lastColumn = mvState.lastColumnSurfaceId { | ||
| // Main-vertical active: stack in right column. | ||
|
|
@@ -10079,6 +10083,14 @@ struct CMUXCLI { | |
| try saveTmuxCompatStore(updatedStore) | ||
| } | ||
|
|
||
| // Equalize vertical splits so teammate panes are evenly distributed. | ||
| // Use orientation: "vertical" to only equalize the agent column, | ||
| // preserving the leader/column horizontal divider position. | ||
| _ = try? client.sendV2(method: "workspace.equalize_splits", params: [ | ||
| "workspace_id": target.workspaceId, | ||
| "orientation": "vertical" | ||
| ]) | ||
|
Comment on lines
+10098
to
+10104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add deferred equalization to avoid post-split layout races. Line 10089 should include 💡 Proposed fix _ = try? client.sendV2(method: "workspace.equalize_splits", params: [
"workspace_id": target.workspaceId,
- "orientation": "vertical"
+ "orientation": "vertical",
+ "deferred": true
])🤖 Prompt for AI Agents |
||
|
|
||
| if let text = tmuxShellCommandText(commandTokens: parsed.positional, cwd: parsed.value("-c")) { | ||
| _ = try client.sendV2(method: "surface.send_text", params: [ | ||
| "workspace_id": target.workspaceId, | ||
|
|
@@ -10369,6 +10381,14 @@ struct CMUXCLI { | |
| ) | ||
| try saveTmuxCompatStore(store) | ||
| } | ||
| } else if !layoutName.isEmpty { | ||
| // Non-main-vertical layout selected: clear stale state so | ||
| // future splits don't incorrectly redirect to the old column. | ||
| let workspaceId = try tmuxResolveWorkspaceTarget(parsed.value("-t"), client: client) | ||
| var store = loadTmuxCompatStore() | ||
| if store.mainVerticalLayouts.removeValue(forKey: workspaceId) != nil { | ||
| try saveTmuxCompatStore(store) | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||
| } | ||
|
Comment on lines
+10412
to
10421
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The comment says "clear stale state," but only This matters on the path: Consider also removing |
||
|
|
||
| case "set-option", "set", "set-window-option", "setw", "source-file", "refresh-client", "attach-session", "detach-client": | ||
|
|
@@ -10400,6 +10420,19 @@ struct CMUXCLI { | |
| /// Used to seed lastColumnSurfaceId when select-layout main-vertical | ||
| /// is called after the first split. | ||
| var lastSplitSurface: [String: String] = [:] | ||
|
|
||
| /// Custom decoder so older store files missing newer keys | ||
| /// (mainVerticalLayouts, lastSplitSurface) decode gracefully | ||
| /// instead of throwing and resetting the entire store. | ||
| init(from decoder: Decoder) throws { | ||
| let container = try decoder.container(keyedBy: CodingKeys.self) | ||
| buffers = try container.decodeIfPresent([String: String].self, forKey: .buffers) ?? [:] | ||
| hooks = try container.decodeIfPresent([String: String].self, forKey: .hooks) ?? [:] | ||
| mainVerticalLayouts = try container.decodeIfPresent([String: MainVerticalState].self, forKey: .mainVerticalLayouts) ?? [:] | ||
| lastSplitSurface = try container.decodeIfPresent([String: String].self, forKey: .lastSplitSurface) ?? [:] | ||
| } | ||
|
|
||
| init() {} | ||
| } | ||
|
|
||
| private func tmuxCompatStoreURL() -> URL { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadTmuxCompatStore()(a file-system read) is executed unconditionally on everysplit-windowcall, even whentmuxCallerSurfaceHandle(),tmuxCallerWorkspaceHandle(), orresolveWorkspaceIdfail and the store is never consulted. The store load is only needed when theif letblock below actually executes.Consider moving the
let store = loadTmuxCompatStore()line inside theif letbody (before themainVerticalLayoutslookup) to avoid the unnecessary I/O on every non-agent-team split:(This is a pre-existing pattern, not a regression from this PR, but the fix here is a good moment to address it.)