135 lines
4.1 KiB
Markdown
135 lines
4.1 KiB
Markdown
# Reset tmux window indexes
|
|
|
|
**Date:** 2026-06-11
|
|
**Status:** Approved
|
|
|
|
## Goal
|
|
|
|
Add reusable functionality that compacts tmux window indexes inside the `hqt`
|
|
tmux session so keyboard shortcuts such as `Alt+1`, `Alt+2`, and `Alt+3` stay
|
|
useful after windows have been closed.
|
|
|
|
This reset affects only tmux window indexes. It does not change database session
|
|
IDs, `tmux_session_name`, harness conversation IDs, nicknames, panes, or running
|
|
processes.
|
|
|
|
## Behavior
|
|
|
|
The reset operation works on the configured `hqt` tmux session:
|
|
|
|
- The home/TUI window always ends at tmux index `0`.
|
|
- Every non-home window keeps its current name, pane, process, and content.
|
|
- Non-home windows are sorted by their current tmux index.
|
|
- Those non-home windows are moved into contiguous indexes starting at `1`.
|
|
|
|
Example:
|
|
|
|
```text
|
|
0: ⌂ HQT
|
|
1: hqt-foo
|
|
4: hqt-bar
|
|
9: hqt-baz
|
|
```
|
|
|
|
becomes:
|
|
|
|
```text
|
|
0: ⌂ HQT
|
|
1: hqt-foo
|
|
2: hqt-bar
|
|
3: hqt-baz
|
|
```
|
|
|
|
If the home window is not already at `0`, it is moved to `0` first, then the
|
|
remaining windows are compacted after it in their original index order.
|
|
|
|
## Architecture
|
|
|
|
Add the reset at the tmux layer rather than the session or database layer.
|
|
Existing app and service code targets windows by name, so changing tmux indexes
|
|
should not disturb attach, stop, delete, status polling, or label syncing.
|
|
|
|
### Runner
|
|
|
|
Add a low-level method on `TmuxRunner`, for example:
|
|
|
|
```python
|
|
async def reset_window_indexes(self, home_window: str) -> bool:
|
|
...
|
|
```
|
|
|
|
The method should:
|
|
|
|
1. List windows for `self.session_name` with `#{window_id}`,
|
|
`#{window_index}`, and `#{window_name}`.
|
|
2. Find the row whose name matches `home_window`.
|
|
3. Move the home window to index `0` if needed.
|
|
4. Sort all other windows by their original index.
|
|
5. Move each non-home window to `1..N` in that order.
|
|
|
|
Use `move-window` with `window_id` as the source target so changing one index
|
|
cannot make a later move target the wrong window. The destination should target
|
|
the configured tmux session and explicit index.
|
|
|
|
The implementation should be idempotent: running it against an already compact
|
|
session should return success without changing anything meaningful.
|
|
|
|
### Manager
|
|
|
|
Add a thin delegate on `TmuxManager`, for example:
|
|
|
|
```python
|
|
async def reset_window_indexes(self, home_window: str) -> bool:
|
|
return await self.runner.reset_window_indexes(home_window)
|
|
```
|
|
|
|
No `SessionService` change is needed for the initial implementation. This is a
|
|
tmux maintenance operation, not a session lifecycle operation.
|
|
|
|
### Command Surface
|
|
|
|
Implement the reusable operation now and defer user-facing wiring. A command
|
|
palette is planned separately, so this feature should expose a callable method
|
|
that the future command can invoke.
|
|
|
|
Do not add a TUI keybinding or footer item in this change.
|
|
|
|
## Error Handling
|
|
|
|
- If the configured tmux session does not exist or cannot be listed, return
|
|
failure and leave the database untouched.
|
|
- If the home window is missing, return failure rather than guessing which
|
|
window should become index `0`.
|
|
- If a `move-window` command fails, return failure. The operation may have
|
|
partially moved tmux windows before the failure; this is acceptable because
|
|
tmux indexes are maintenance metadata and no persisted hqt state is changed.
|
|
- Log tmux stderr for failed operations to aid debugging.
|
|
|
|
## Testing
|
|
|
|
Add focused tests in `tests/test_tmux.py`:
|
|
|
|
- Missing home window returns failure and performs no moves.
|
|
- Already compact windows return success.
|
|
- Sparse indexes compact in current index order:
|
|
`0 home, 1 foo, 4 bar, 9 baz` moves `bar` to `2` and `baz` to `3`.
|
|
- Home initially not at `0` is moved to `0`, and all other windows compact to
|
|
`1..N` in original order.
|
|
- Moves target stable window identities, not mutable index-only targets.
|
|
|
|
The implementation must pass the project checks after code changes:
|
|
|
|
```bash
|
|
uv run ruff format src tests
|
|
uv run ruff check src tests
|
|
uv run ty check
|
|
```
|
|
|
|
## Out of Scope
|
|
|
|
- Changing database primary keys.
|
|
- Changing `Session.tmux_session_name`.
|
|
- Changing harness session IDs or resume behavior.
|
|
- Adding command palette UI, keybindings, or footer labels.
|
|
- Enabling permanent tmux automatic renumbering.
|