fix: worktree session UI safety and visibility (review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 20:49:12 -04:00
parent 9efa270422
commit ace537e3d6
3 changed files with 32 additions and 15 deletions
+12 -6
View File
@@ -287,8 +287,15 @@ class HqtApp(App):
async def _open() -> None:
# is_git_repo is async; resolve it before pushing so the dialog can
# disable the worktree control for non-repo projects.
# disable the worktree control for non-repo projects. This worker is
# run raw (not via _run_service_worker), so it must never raise: any
# failure (e.g. git not on PATH) falls back to False, which simply
# disables the worktree checkbox in the dialog.
try:
is_git_repo = await worktree.is_git_repo(Path(project_path))
except Exception as exc: # noqa: BLE001 - keep the worker from crashing the TUI
log.warning("is_git_repo check failed for %s: %s", project_path, exc)
is_git_repo = False
self.push_screen(NewSessionScreen(harness_names, is_git_repo), on_dismiss)
self.run_worker(_open())
@@ -343,11 +350,10 @@ class HqtApp(App):
parts.append("uncommitted changes")
if state and state.unique_commits > 0:
parts.append(f"{state.unique_commits} unmerged commit(s)")
warning = (
" and ".join(parts).capitalize() + " — work will be lost"
if parts
else None
)
warning = None
if parts:
joined = " and ".join(parts)
warning = joined[:1].upper() + joined[1:] + " — work will be lost"
def on_dismiss(result: tuple[bool, bool] | None) -> None:
if result is None:
+8 -3
View File
@@ -37,9 +37,14 @@ def format_session_text(
) -> str:
color = _STATUS_COLORS.get(status_text, "#c6d0f5") # default: Text
name = nickname
# Mark worktree sessions with their branch. The nickname defaults to the
# branch at creation, so only append the marker when it adds information.
if worktree_branch and nickname != worktree_branch:
# Worktree sessions always carry the ⎇ marker so they're visually distinct
# from plain sessions. The nickname defaults to the branch at creation, so
# when they match we show the glyph once (no duplicated branch); when they
# differ we show both so the branch is still visible.
if worktree_branch:
if nickname == worktree_branch:
name = f"{nickname}"
else:
name = f"{nickname}{worktree_branch}"
label = escape(f"{name} [{harness_name}]")
return f"[{color}]{symbol}[/] {label} {status_text}"
+10 -4
View File
@@ -1404,18 +1404,24 @@ async def test_confirm_delete_cancel_returns_none():
def test_format_session_text_appends_worktree_branch_marker():
"""nickname != branch → show both nickname and branch around the ⎇ glyph."""
from hqt.tui.widgets.session_list import format_session_text
text = format_session_text("mywork", "claude", "idle", "", "feature-x")
assert "⎇ feature-x" in text
assert "mywork ⎇ feature-x" in text
def test_format_session_text_no_marker_when_nickname_equals_branch():
"""Avoid duplication: when nickname already equals the branch, no marker."""
def test_format_session_text_marker_shows_once_when_nickname_equals_branch():
"""nickname == branch (the common case) → ⎇ still appears, glyph once, no
duplicated branch name."""
from hqt.tui.widgets.session_list import format_session_text
text = format_session_text("feature-x", "claude", "idle", "", "feature-x")
assert "" not in text
assert "" in text
# Glyph appears exactly once, and the branch is not duplicated.
assert text.count("") == 1
assert "⎇ feature-x" in text
assert "feature-x ⎇" not in text
def test_format_session_text_no_marker_for_plain_session():