Add macterm tab move to reorder tabs from the CLI - #233
Conversation
Scripts that organize tabs had no way to change their order. The new verb speaks final positions — `tab move tab:4 2` makes the tab second in `tab list` order — because a drop-offset coordinate space (what Workspace.moveTab takes, where a move toward the end lands one slot short of the number you pass) is drag-and-drop plumbing no caller should have to know about. The handler converts and delegates to the same AppState.reorderTab the sidebar drag uses. Out-of-range slots are a typed bad_request, never a silent clamp, matching pane resize-split's up-front ratio validation.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
macterm | 898d0d3 | Commit Preview URL Branch Preview URL |
Aug 07 2026, 10:04 AM |
Window-state benchmark
Reported value is the median of 3×10s windows per state (splitting the window and taking the median keeps one co-scheduled spike from skewing a state); CPU % is the process CPU-time delta over a window. Runs land on different shared runners, so treat small deltas as noise — 🔺/🔻 marks changes ≥25% that also clear the metric's absolute noise floor (CPU % ≥0.5, Memory (RSS MB) ≥25, CPU ms/s ≥5, Wakeups/s ≥50); CPU deltas off a noise-dominated baseline aren't flagged (CPU % baseline ≥1.5, CPU ms/s baseline ≥15). The |
What
A new
macterm tab move <tab> <slot>verb that reorders a tab within its project —tab move tab:4 2makes tab 4 second. The tab selector takes the usual forms (title, UUID, index,tab:N), and--projectscopes it exactly liketab list.Why
Scripts that clean/organize tabs had no way to change tab order — the one workspace mutation the CLI couldn't reach, with no workaround.
Closes #224
How
slotis the tab's final 1-based position intab listorder, in both directions. That's the contract worth reviewing: the existingWorkspace.moveTab(which backs sidebar drag-reorder) speaks SwiftUI's pre-removal drop-offset coordinates, where a move toward the end lands one slot before the number you pass.ControlHandler.tabMoveconverts (slot > fromIndex ? slot : slot - 1) and then delegates to the sameAppState.reorderTabthe sidebar uses — no new reorder or persistence logic anywhere.bad_request, never a silent clamp — the same up-front rejectionpane resize-splitapplies to its ratio bounds.tab.movecommand plus an additive optionalslotfield onControlArgs, so old and new clients stay compatible per the protocol's additive-field convention.Verified
mise run format,mise run lint, andmise run testall passmise run e2epasses, including a newtest_tab_move_places_tab_at_its_final_slotthat swaps two live tabs back and forth through the real app and asserts the out-of-range refusalControlHandlerTestscover both move directions (the toward-end direction is the one that would regress if the coordinate conversion were dropped), the same-slot no-op, and selector/slot validationNotes for reviewers
Docs updated in the CLI reference table (
website/docs/pages/80-cli.md) and AGENTS.md's verb list.