Skip to content

Wrap long task titles, and size the pane to the rows they take - #2

Merged
tzafrir merged 4 commits into
mainfrom
claude/project-thread-m1qzvr
Oct 13, 2026
Merged

tzafrir merged 4 commits into
mainfrom
claude/project-thread-m1qzvr

Conversation

@tzafrir

@tzafrir tzafrir commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Requested by Tzafrir · project thread

Supersedes #1 by @Yuramazyrenko, who found the problem and made the first fix: wrap the title instead of cutting it. Their change is kept here (and they are credited as co-author on the commit); this PR fixes what review found around it.

Before (PR #1, a 44-column terminal): the title wraps, but the age is squeezed into a column of its own and the pane, sized for a one-row title, cuts off everything below the why: the buttons and task #2.

╭────────────────────────────────────────✕─╮
│ ☐ 2 tasks for you                        │
│                                          │
│ ☐#1 Open Instruments    3m · from an     │
│  from Xcode and recordearlier session    │
│  with the Activity                       │
│  Monitor template                        │
│   I need a trace of the launch to see    │
│   where the 4 seconds go.                │
╰──────────────────────────────────────────╯

After (this branch, same terminal, same tasks):

╭────────────────────────────────────────✕─╮
│ ☐ 2 tasks for you                        │
│                                          │
│ ☐ #1 Open Instruments from Xcode and     │
│   record with the Activity Monitor       │
│   template  3m · from an earlier session │
│   I need a trace of the launch to see    │
│   where the 4 seconds go.                │
│   Done when: The .trace file is in       │
│   ~/traces.                              │
│   d: Done   r: Answer…   x: Reject…      │
│ ☐ #2 Run xcodebuild test on your Mac and │
│     paste every failure you see here     │
│     please  3m · from an earlier session │
│                                          │
│ Esc: back to the prompt   Hide           │
╰──────────────────────────────────────────╯

Both screens are tmux capture-pane output from Claude Code 2.1.296, drawn by the new tests/live/screen.py.

The six review findings

  1. The pane was too short for a wrapped title. rowsFor (moved to hooks/pane.ts) now counts every text as the terminal wraps it, at the width the pane is drawn in. The render hook keeps that width and opens the pane again when the rows it needs change, so a narrower terminal gets a taller pane.
  2. The age wrapped into a thin column. The title and its age are now one text, so the age follows the title. I didn't use flexShrink={0} on the age: at 36 columns that leaves the title an 8-column strip.
  3. "Assigned you a task:" could break. The transcript row is now one text too, so the label stays whole and the title wraps after it.
  4. Only the selected task wrapped. Every open task's title wraps now. #2 is the button that selects the task, and the title wraps beside it. A Button with wrapping children clipped its last column, so the title isn't inside the button. Saved responses wrap too, with Send now beside them.
  5. Titles over 80 characters were cut. The pane and transcript draw up to 300 characters. Only titles that an older version left in the store can be that long: assign_task still refuses anything over 80.
  6. The test was weak. See Tests below. Also, rows now keep their height when the tree is taller than the pane, so it scrolls. Before, rows got squeezed into each other.

Tests

  • Kit tests (claude plugin test .):

    • wrapRows and cellsOf against how the terminal actually wrapped spaces, an over-long German word and Japanese text.
    • rowsFor row counts taken from the live screens.
    • The pane opens again with 12 rows at 60 columns and 18 at 32. This fails if the refit is removed.
    • Every title and the transcript row are drawn whole, in one wrapping text.
  • tests/live/test_pane.py runs a real Claude Code in tmux, with a throwaway config and a dummy API key. No model is called. It seeds tasks, opens /my-tasks at 36, 48, 64 and 100 columns, and checks:

    • every title shows whole;
    • the foot is the last row, so nothing is cut off and no row is left empty;
    • the answer field fits;
    • a pane taller than its 18 rows scrolls without squeezing;
    • the transcript row, from a resumed transcript, keeps its label whole.

    It passes on this branch. Every case fails on main, and the fit cases fail on Wrap a long task title instead of cutting it at the pane edge #1.

  • CI gains a render job that runs the live check and then tsc -p .. Loading the plugin lays out its types, so the type-check can run after it.

How

hooks/pane.ts holds the strings the pane draws (title, age, buttons, hint) along with rowsFor, so the drawing and the row count come from the same text. hooks/text.ts gains cellsOf and wrapRows, which follow the terminal's word wrap: break at spaces, keep the space at the end of the row, and hard-break a word longer than the row. The plugin's version isn't bumped here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NWRmPXAvN9BfWZJxsAMvmf


Generated by Claude Code

Supersedes #1, which made the open task's title and the transcript row
wrap. This keeps that change and fixes what review found around it:

- The pane asked for one row per title wherever it was drawn, so a title
  that wrapped cut off the rows below it, the buttons among them.
  rowsFor (now in hooks/pane.ts) counts every text as the terminal wraps
  it at the width the pane is drawn in; the render hook remembers that
  width and opens the pane again when the rows differ.
- A title and its age are one text, so the age follows the title instead
  of being squeezed into a column of its own; the same for the
  "Assigned you a task:" label in the transcript.
- Every open task's title wraps, not only the selected one's: `#2` is the
  button that selects it, and the title wraps beside it. Saved responses
  wrap too, with Send now beside them.
- Titles longer than 80 characters (left in the store by an older version)
  are drawn whole, up to 300.
- The pane's rows keep their height when the tree is taller than the
  pane: it scrolls instead of squeezing rows into each other.

Tests: unit tests for the wrapping and the row counts, kit tests that the
pane re-opens with more rows when drawn narrower and that every title is
drawn whole, and tests/live/test_pane.py, which draws the pane and the
transcript row in a real Claude Code in tmux at 36 to 100 columns and
checks that every title shows whole and the pane fits it exactly. CI runs
it as a second job, then type-checks.

Co-authored-by: Yurii Mazurenko <yuramazyrenko@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWRmPXAvN9BfWZJxsAMvmf
On main the unselected tasks' ages fell into a column one character wide
at 66 columns; this draws the same tasks and checks each title and age
shows whole and the pane fits them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWRmPXAvN9BfWZJxsAMvmf
A session killed after creating the store can still write its slot after
the seed was read back, and the next session then finds no tasks. Opening
the pane now notices that, seeds again and retries.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWRmPXAvN9BfWZJxsAMvmf
The render job failed twice with "No tasks for you right now" while the
status line counted one: /my-tasks ran before the session had loaded the
seeded tasks from the store. Wait for the status line first, in place of
the retry the last commit added on a wrong guess.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWRmPXAvN9BfWZJxsAMvmf
@tzafrir
tzafrir merged commit 644f944 into main Oct 13, 2026
2 checks passed
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.

2 participants