Skip to content

Tags: flipbit03/forestui

Tags

v1.3.0

Toggle v1.3.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Add custom Claude buttons configurable in settings (#23)

Users can now configure arbitrary "New Session: X" buttons that spawn
claude with any custom command. Each button has a display label, a
tmux window prefix (auto-derived from label, independently editable),
and a command string used as-is when the button is pressed. Buttons
containing --dangerously-skip-permissions are auto-styled red like the
existing YOLO button.

Buttons render in the CLAUDE section (wrapping 4-per-row) and as
compact pills on each row of the recent-sessions list. The resume path
reuses the custom command/prefix with `-r <session-id>` appended.

Also:
- Drop the pre-existing (unused) per-repo/per-worktree/global
  custom_claude_command override — custom buttons subsume the use case
- Move Add Worktree out of the CLAUDE section to sit next to Git Pull
  in the repo header, where it belongs
- Widen Settings + Manage modals (new modal-wide class) and let them
  fill available vertical space so the Manage button is always visible
- Bump textual to >=8.2.4

v1.2.0

Toggle v1.2.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix window renaming on reattach after forestui is killed (#22)

* Fix window renaming on reattach after forestui is killed

When forestui was killed and then re-launched to reattach to an existing
tmux session, it would incorrectly rename the first window (e.g., "ssh")
to "forestui" in addition to creating the correct new forestui window.

Root cause: TmuxService.current_window used session.active_window (the
window the user is viewing) instead of the window the forestui process
is actually running in. On reattach, the active window is window 1, not
the newly created forestui window.

Fix: Use TMUX_PANE env var to find the process's own window. Also fix
the hardcoded "forestui" name in the recreated window to respect dev mode.

Additionally improves the test-forestui skill with lessons learned:
- Never call tmux directly, always go through tu
- Use a parent bash shell for detach/reattach test flows
- Check .tmux.conf for rename-window prompt behavior
- Proactively test visual/behavioral changes

Strengthens CLAUDE.md to require make check before pushing/opening PRs.

* Add CI workflow to run make check on PRs and pushes to main

* test: deliberate type error to verify CI catches failures

* Revert deliberate type error used to verify CI failure detection

* test: deliberate formatting error to verify CI catches it

* Add format check to make check and CI

Adds `ruff format --check` as a `format-check` target to the Makefile,
included in `make check`. CI now catches lint, type errors, and
unformatted code.

v1.1.0

Toggle v1.1.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Use grouped tmux sessions for independent window navigation (#21)

* Use grouped tmux sessions for independent window navigation (#20)

Replace `tmux attach-session` with `tmux new-session -t` when
reattaching to an existing session. This creates a grouped session
that shares windows but allows each terminal to independently select
the active window. The `destroy-unattached` option ensures grouped
sessions are cleaned up when the terminal disconnects.

* Fix grouped tmux session creation by splitting into separate commands

The semicolon command separator in os.execvp doesn't work reliably with
tmux. Instead, create the grouped session detached with a PID-based
unique name, set destroy-unattached on it, then attach.

* Use tmux hook to defer destroy-unattached until after client attaches

Setting destroy-unattached on a detached session causes tmux to destroy
it immediately. Use a client-attached hook instead so the option is set
only after the client connects, avoiding the race condition.

* Fix TmuxService.session to resolve the actual current session

Use tmux display-message to get the session ID of the process's own
session instead of picking the first attached one. In grouped session
setups, multiple sessions are attached simultaneously, and the old
approach would always find the original session, causing window
operations (open editor, terminal, claude) to switch the active window
in the wrong terminal.

* Fix TmuxService.session to resolve the actual current session

The forestui process runs in the original session's pane, so
display-message always returned the original session ID regardless of
which grouped session the user is viewing from. Instead, use
list-clients sorted by client_activity to find the most recently active
client's session — that's the terminal the user just interacted with.

Remove session caching since the active client can change between
grouped sessions at any time.

* Hide PID-suffixed session name in tmux status bar for grouped sessions

Override status-left on grouped sessions to show the base session name
(e.g. forestui-forest) instead of the internal PID-suffixed name
(e.g. forestui-forest-23116). The grouped session is an implementation
detail that should be transparent to the user.

* Address PR review: fix injection, side effects, and session scoping

1. Fix shell injection via unquoted forest_path (shlex.quote)
2. Replace select-window existence check with read-only list-windows
   to avoid switching the active window in the original session
3. Scope list-clients to our session_group so unrelated tmux sessions
   don't cause forestui to resolve to the wrong session
4. Use destroy-unattached keep-last instead of on, preventing the
   last session in the group from being destroyed
5. Use show-options -gv for status-left to get just the value without
   option name prefix or quoting
6. Add error handling for grouped session creation with fallback to
   direct attach

* Fix forestui window detection for dev mode window names

The existence check used exact match on "forestui", missing dev mode
windows named "forestui-dev-HHMM". This caused a second terminal to
spawn a duplicate forestui process instead of just attaching.

* Preserve trailing space in status-left template for grouped sessions

strip() was removing a trailing space that's part of the tmux
status-left template, causing the separator between the session name
and the first window tab to disappear. Use rstrip('\n') to only
remove the subprocess newline.

* Add test-forestui skill for self-driven visual testing with tu

Provides a skill that lets Claude launch forestui in headless virtual
terminals via tu, visually verify UI behavior, and interact with the
running app. Supports multi-terminal testing with isolated tmux servers
for verifying grouped session behavior.

* Warn against running forestui without tmux isolation in test skill

The user is likely running their own tmux/forestui session. Without
TMUX_TMPDIR isolation the agent would interfere with their live session.

* Use exact-match session targeting to avoid tmux prefix matching

tmux's -t flag does prefix matching by default, so
has-session -t forestui-forest would match orphaned grouped sessions
like forestui-forest-12345. The = prefix forces exact match on all
session targets: has-session, list-windows, new-window, new-session.

* Enforce PNG screenshots in test-forestui skill

Plain text screenshots lose colors and highlighting, making it
impossible to tell which tmux window is active. PNG mode captures
the full terminal with color for accurate visual verification.

v1.0.1

Toggle v1.0.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Add fuzzy branch search with dropdown for existing branch selection (#19

)

* Add fuzzy branch search with dropdown for existing branch selection

Replace the prefix-only SuggestFromList inline suggestion with a
BranchSearchInput widget that shows a visible dropdown of matches.
Matching uses substring search on any portion of the branch name
(including through remote prefixes like origin/) plus Levenshtein
distance for typo tolerance.

* Address PR review: use rapidfuzz, dynamic remotes, extract utils

- Replace hand-rolled Levenshtein with rapidfuzz library
- Use actual git remotes (from `git remote`) instead of hardcoded
  prefixes like "origin"/"upstream" for stripping remote prefixes
- Move matching functions to forestui/utils.py, keeping only widget
  classes in branch_search.py
- Thread remotes list from git service through app -> modals -> widgets
- Update _compute_default_base_branch to iterate actual remotes

* Drop rapidfuzz dependency, use hand-rolled Levenshtein

rapidfuzz is a compiled C extension that may lack wheels for some
architectures. The Levenshtein DP implementation is ~15 lines and
perfectly adequate for matching short branch name strings.

v1.0.0

Toggle v1.0.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Add base branch selection and worktree origin tracking (#18)

Features:
- Add base branch selector with autocomplete to "Create Worktree from Issue" modal
- Add Fetch button to refresh remote branches before creating worktree
- Replace Select dropdown with Input + autocomplete for existing branch selection
- Track base_branch and created_from_ref on worktrees
- Display "Based on: <branch> (<ref>)" in worktree detail view

Improvements:
- list_branches() now includes all remotes (not just origin/upstream)
- Wider modal container (60 -> 80 chars) for better readability
- Clear error messages when user types in Add Worktree modal
- Validate existing branch exists before creating worktree
- Better error messages with branch name context

v0.9.9

Toggle v0.9.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Use worktree name instead of branch name for tmux window titles (#17)

Fixes tmux window names to use the shorter worktree directory name
(e.g., "title-is-wt-name-not-branch") instead of the full git branch
name (e.g., "feat/title-is-wt-name-not-branch"). Also renames the
helper function to _get_tmux_window_name since it's used for all
tmux windows, not just Claude sessions.

v0.9.8

Toggle v0.9.8's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Remove forestui label from sidebar header (#16)

* Remove forestui label from sidebar, keep only gh cli status

* Update screenshot to reflect sidebar header changes

v0.9.7

Toggle v0.9.7's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Remove forestui label from sidebar header (#16)

* Remove forestui label from sidebar, keep only gh cli status

* Update screenshot to reflect sidebar header changes

v0.9.6

Toggle v0.9.6's commit message
Fix auto-update to use uv tool upgrade for cleaner detection

Switch from `uv tool install --force --upgrade` to `uv tool upgrade`
which provides consistent output for detecting update status:
- "Nothing to upgrade" when already on latest
- "Updated" with version info when upgraded

v0.9.5

Toggle v0.9.5's commit message
Fix auto-update to use uv tool upgrade for cleaner detection

Switch from `uv tool install --force --upgrade` to `uv tool upgrade`
which provides consistent output for detecting update status:
- "Nothing to upgrade" when already on latest
- "Updated" with version info when upgraded