Skip to content

Add --panel flag to new-split command - #10

Merged
lawrencecchen merged 2 commits into
mainfrom
feature/new-split-panel-flag
Feb 4, 2026
Merged

lawrencecchen merged 2 commits into
mainfrom
feature/new-split-panel-flag

Conversation

@lawrencecchen

Copy link
Copy Markdown
Contributor

Summary

  • Adds optional --panel flag to new-split command to split a specific panel without changing focus first
  • Previously, to split a specific panel you had to: focus-panel --panel 1 then new-split down
  • Now you can: new-split down --panel 1

Usage

# Split focused panel (existing behavior)
cmuxterm new-split right

# Split a specific panel by index
cmuxterm new-split down --panel 1

# Split a specific panel by UUID
cmuxterm new-split left --panel 7CB1D503-CD85-47CC-9DA6-E403D723DC73

Test plan

  • Tested locally: created right split, then used --panel 1 to split only the right panel downward
  • Test on cmux-vm (VM currently offline)

Allows splitting a specific panel without changing focus first.

Usage: cmuxterm new-split <direction> [--panel <id|index>]

Example: cmuxterm new-split down --panel 1
@vercel

vercel Bot commented Feb 4, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmuxterm-docs Ready Ready Preview, Comment Feb 4, 2026 4:38am

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07b95df910

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +323 to +341
let directionArg = parts[0]
let panelArg = parts.count > 1 ? parts[1] : ""

guard let direction = parseSplitDirection(directionArg) else {
return "ERROR: Invalid direction. Use left, right, up, or down."
}

var result = "ERROR: Failed to create split"
DispatchQueue.main.sync {
guard let tabId = tabManager.selectedTabId,
let tab = tabManager.tabs.first(where: { $0.id == tabId }),
let surfaceId = tab.focusedSurfaceId else {
let tab = tabManager.tabs.first(where: { $0.id == tabId }) else {
return
}
success = tabManager.newSplit(tabId: tabId, surfaceId: surfaceId, direction: direction)

// If panel arg provided, resolve it; otherwise use focused surface
let surfaceId: UUID?
if !panelArg.isEmpty {
surfaceId = resolveSurfaceId(from: panelArg, tab: tab)
if surfaceId == nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Trim panel arg before resolving surface id

When new_split is sent over the socket with multiple spaces (e.g., new_split right 1), parts[1] retains the leading whitespace because split(maxSplits: 1) preserves the remainder as-is. resolveSurfaceId expects a clean UUID or integer, so the lookup fails and returns ERROR: Panel not found even though the panel is valid. Trimming panelArg before resolving would make the new --panel feature robust to common whitespace formatting in socket clients.

Useful? React with 👍 / 👎.

new-split now returns the UUID of the newly created panel, enabling
reliable chaining of split operations without index drift issues.

Before: OK
After:  OK F2675177-3838-49AF-A1A0-1744C0048E99

Example workflow to create left + 2x2 grid on right:
  RIGHT=$(cmuxterm new-split right | awk '{print $2}')
  BOTTOM=$(cmuxterm new-split down --panel $RIGHT | awk '{print $2}')
  cmuxterm new-split right --panel $RIGHT
  cmuxterm new-split right --panel $BOTTOM
@lawrencecchen
lawrencecchen merged commit 600683c into main Feb 4, 2026
4 checks passed
@lawrencecchen
lawrencecchen deleted the feature/new-split-panel-flag branch February 4, 2026 05:37
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
* Add --panel flag to new-split command

Allows splitting a specific panel without changing focus first.

Usage: cmuxterm new-split <direction> [--panel <id|index>]

Example: cmuxterm new-split down --panel 1

* Return new panel ID from new-split command

new-split now returns the UUID of the newly created panel, enabling
reliable chaining of split operations without index drift issues.

Before: OK
After:  OK F2675177-3838-49AF-A1A0-1744C0048E99

Example workflow to create left + 2x2 grid on right:
  RIGHT=$(cmuxterm new-split right | awk '{print $2}')
  BOTTOM=$(cmuxterm new-split down --panel $RIGHT | awk '{print $2}')
  cmuxterm new-split right --panel $RIGHT
  cmuxterm new-split right --panel $BOTTOM
heyitaki added a commit to heyitaki/casper that referenced this pull request May 12, 2026
Bumps the ghostty submodule to c6302d022 which splits Termio.resize into
visual and pty legs and adds an IO-thread xev.Timer to coalesce SIGWINCH
during a live sidebar/divider drag. Resolves the starship-prompt
re-render that ran on every drag frame; the visual grid still reflows
per frame.

Also documents the new fork patches in docs/ghostty-fork.md (manaflow-ai#10 resize
debounce, manaflow-ai#11 per-RunStep DEVELOPER_DIR helper, manaflow-ai#12 lazy iOS xcframework
slices).

Note: c6302d022 lives on local branch cmux-prompt-flicker-pty-coalesce
and has not yet been pushed to manaflow-ai/ghostty main (heyitaki lacks
push access). The xcframework pin reference at the bottom of
docs/ghostty-fork.md still points at 22fa801 — regenerate the
xcframework release + ghosttykit-checksums.txt entry once the new pin
is upstreamed.

Claude-Session: 3604552a-5f21-4c2d-90f6-e1c51667d079
Co-Authored-By: Claude <noreply@anthropic.com>
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request May 22, 2026
…-ai#2 manaflow-ai#3 + tests)

Three real bugs from the review of bc76ffe, all fixed in one
go since they touch the same per-binding state machine:

manaflow-ai#1 — HerdrTabRegistry.remove now calls
HerdrInboundLayoutSync.forgetBinding (and HerdrDividerSync.reset).
The throttle/suppress commit added three static maps keyed by
binding.rootCmuxPaneId (lastDividerApplyAt, pendingDividerSpec,
dividerApplyScheduled, plus the new pendingResizeRetries / per-
binding suppression state) — none of them were cleared on
teardown. A future binding reusing the same UUID inherited stale
throttle timestamps and could have applied dividers from a tree
that no longer existed.

manaflow-ai#3 — Suppression is now per-binding instead of one global static.
inboundApplyActiveByBinding + inboundApplySuppressUntilByBinding
are keyed by binding.rootCmuxPaneId; shouldSuppressOutboundResize
takes an optional binding key (nil falls back to the global
aggregate, used by the legacy getter and the unresolved-binding
defensive path in forwardPanelSize). HerdrPanelOpener.
forwardPanelSize resolves the binding key for the panel via
HerdrTabRegistry.binding(forCmuxPaneId:) and consults the
per-binding state. A drag in workspace A no longer suppresses
legitimate user-driven cmux window resizes in workspace B.

manaflow-ai#2 — When forwardPanelSize gets suppressed, it now hands a retry
closure to markPendingResize. After the trailing window closes we
re-fire the latest pending retry per panel so the user-driven
resize is not silently dropped. Each markPendingResize schedules a
flush Task that waits inboundApplySuppressTrailingMs + 50ms; if
the suppression window has been re-armed by another apply, the
flush no-ops and the next apply schedules another. forgetBinding
also drains the pendingResizeRetries dict so a torn-down panel
doesn't leak its closure.

Tests:

- testPerBindingSuppressionDoesNotBleedToOtherBindings — locks
  contract that workspace A's drag doesn't suppress workspace B.
- testForgetBindingClearsSuppressionState — locks the teardown
  cleanup that manaflow-ai#1 was missing.
- testPendingResizeFiresAfterSuppressionReleases — locks that a
  suppressed user resize is re-fired exactly once after the
  trailing window expires.

Test seam `_withInboundApplyActiveForTesting` now accepts an
optional bindingKey so the per-binding-scoping test can drive
both the global and per-binding state from one helper.

Open items from the review NOT addressed in this commit:

- Throttle still has no test (reviewer manaflow-ai#7). Next.
- 33ms/250ms hardcoded constants undocumented (reviewer manaflow-ai#10).
- The trailing window deadline can shrink across re-entrant apply
  boundaries on wall-clock backwards step (reviewer manaflow-ai#5). Use a
  monotonic clock; deferred.
- Bandwidth premise still unproven (reviewer A). Need
  instrumentation pass to confirm SSH-master is actually the
  bottleneck before claiming this commit "fixes" the symptom.
MasonStation added a commit to ashlrai/ashlr-mux that referenced this pull request Jul 7, 2026
…oop checkpoint

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ejc3 added a commit to ejc3/cmux that referenced this pull request Jul 15, 2026
…low-ai#1, manaflow-ai#4, manaflow-ai#8, manaflow-ai#9, manaflow-ai#10, manaflow-ai#12, manaflow-ai#14)

Several linked defects in the mirror sizing transaction:

- manaflow-ai#1: applyAssignedGrids re-pinned a stale grid during a WINDOW live-resize
  (or interactive geometry drag), painting past the shrinking pane. The
  divider-drag early return does not cover a window resize, so gate the
  stale re-pin on the same suppression the view path uses.
- manaflow-ai#8: under zoom the visible tree is the single zoomed leaf, so hidden but
  live base panes were unpinned and rendered on a stale grid. Pin each pane
  from the visible tree or the base tree; clear only panes in neither.
- manaflow-ai#9: the pin-grow repaint went through the attach-only redraw kick
  (armed only at .enter), so late-granted cells stayed blank mid-session.
  Extract the shrink/restore SIGWINCH body into forceRedrawKick(windowIds:)
  and call it directly on a pin grow.
- manaflow-ai#10: the stale-repin else-if and gridParityMismatch tested only the
  under direction, so an over-render (rendered > assigned) was an invisible
  no-op. Compare with != on both axes; reapplyAssignedGrid clamps either way.
- manaflow-ai#12: gridParityMismatch read only the ledger, which goes stale because a
  same-size re-apply returns early before reporting. Read the surface's live
  grid first, falling back to the ledger.
- manaflow-ai#4: the parked-container consumer clamped an oversized parked reading to
  the bound and banked it, overwriting a correct size. Reject it (as the
  sibling oversized consumer does) and keep the last good container.
- manaflow-ai#14: rearmIfOutputMissedPlan gated on the plain isVisibleForSizing, which
  goes stale-true when a hidden tab's view is dismantled; gate on
  isEffectivelyVisibleForSizing so an offscreen mirror cannot spin re-arms.

Tests: parkedHiddenReadingOverTheBoundIsRejectedNotClamped (manaflow-ai#4),
gridParityFlagsAnOverRenderedPane (manaflow-ai#10, manaflow-ai#12), and the reworked grid-lag
test now pins that an offscreen mirror does not re-arm (manaflow-ai#14).

This branch was successfully deployed

1 active deployment
Preview — 78778d35 Deployed Feb 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant