feat(tui): state-tinted tool cards, session status bar, mode borders, cosine shimmer - #58
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThe TUI adds state-specific tool-card backgrounds, a responsive session status bar, deterministic session accents, permission-mode editor borders, and time-based shimmer animation. Tests, theme schemas, documentation, and a changeset cover these updates. ChangesTUI visual surfaces
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Comment |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/pythinker-code/src/tui/components/chrome/status-bar.ts`:
- Around line 12-21: Update StatusBarStatus to include FooterStatus.fastMode,
then adjust renderModesChip so fastMode renders the ↯ fast badge using modeFast
and workflow renders with the appropriate workflow token instead of modeFast.
Add a status-bar test covering fast-mode rendering.
In `@apps/pythinker-code/src/tui/components/messages/tool-call.ts`:
- Around line 668-675: Update the line-mapping condition in the tool-card
rendering path so the first two rendered rows—the leading Spacer and
headerText—remain unchanged; apply the background only from index 2 onward,
preserving the existing padding behavior for body lines.
In `@apps/pythinker-code/test/tui/components/messages/tool-call.test.ts`:
- Around line 65-85: Strengthen the assertions in the tool-call tint test around
component.render(40): for pending, successful, and error results, require at
least one body row before checking every row’s background color. Also assert
that the header row lacks each state-specific background in all three states,
not only while pending, using the existing rendered output for each state.
In `@apps/pythinker-code/test/tui/components/status-bar.test.ts`:
- Around line 63-65: Update the width loop in the status-bar rendering test to
first assert that component.render(width) returns exactly one row, then validate
that row’s visible width does not exceed width. Reuse the rendered result so an
empty array cannot satisfy the width assertion vacuously.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 22ce2320-0f3a-4458-8a92-e8d3fc6f0d0c
📒 Files selected for processing (18)
.changeset/tui-signature-design.mdapps/pythinker-code/src/tui/components/chrome/status-bar.tsapps/pythinker-code/src/tui/components/messages/tool-call.tsapps/pythinker-code/src/tui/pythinker-tui.tsapps/pythinker-code/src/tui/theme/colors.tsapps/pythinker-code/src/tui/theme/theme-schema.jsonapps/pythinker-code/src/tui/tui-state.tsapps/pythinker-code/src/tui/utils/session-accent.tsapps/pythinker-code/src/tui/utils/shimmer.tsapps/pythinker-code/test/tui/components/messages/dynamic-workflow-mission-control.test.tsapps/pythinker-code/test/tui/components/messages/tool-call.test.tsapps/pythinker-code/test/tui/components/status-bar.test.tsapps/pythinker-code/test/tui/pythinker-tui-message-flow.test.tsapps/pythinker-code/test/tui/pythinker-tui-startup.test.tsapps/pythinker-code/test/tui/theme/palette.test.tsapps/pythinker-code/test/tui/utils/session-accent.test.tsdocs/customization/themes.mdpackages/agent-core/src/skill/builtin/custom-theme.md
86ceb3c to
a68cb74
Compare
a68cb74 to
f495c80
Compare
5d80ea7 to
525b3db
Compare
525b3db to
de67ad5
Compare
de67ad5 to
eade981
Compare
eade981 to
4b47377
Compare
4b47377 to
98a175d
Compare
98a175d to
bf66a7c
Compare
… cosine shimmer Port four signature visual elements: tool-call blocks carry a full-width background tint keyed to their state; a one-line status bar above the editor shows model, effort, and mode chips joined by a session-accent rule; the editor border colors yolo and auto permission modes; and the shimmer sweep uses a cosine band at constant velocity.
…r renders validation only
Gate the status bar model, effort, and mode chips on their status_line settings, drop the effort suffix when thinking is off, and paint the yolo badge with the error token. Slow the shimmer sweep and alternate the mission-control peak with a warning highlight; remove the dead frame option in favor of a documented bandHalfWidth.
The prompt box no longer tints by permission mode or thinking effort; it uses the neutral border color, and yolo stays visible as a status bar badge. Token speed returns to the model chip, matching the footer composition, instead of sitting mid-ladder in the extras.
bf66a7c to
ebfb674
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
apps/pythinker-code/src/tui/components/messages/tool-call.ts (1)
662-669: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid the negated condition.
Line 667 triggers Oxlint's
unicorn(no-negated-condition)rule. Check the error case first and keep success as the fallback. This preserves the current behavior, including treatingis_error === undefinedas success.Proposed fix
const background = this.result === undefined ? this.toolCall.truncated === true ? undefined : 'toolPendingBg' - : this.result.is_error !== true - ? 'toolSuccessBg' - : 'toolErrorBg'; + : this.result.is_error === true + ? 'toolErrorBg' + : 'toolSuccessBg';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/pythinker-code/src/tui/components/messages/tool-call.ts` around lines 662 - 669, Update the background selection expression in the tool-call component to check the error case first, using toolErrorBg when result.is_error === true and toolSuccessBg as the fallback; preserve the existing pending/truncated behavior and treat undefined is_error as success.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/pythinker-code/src/tui/pythinker-tui.ts`:
- Line 1339: Update the editor border-color selection logic near the
permission-mode handling and the corresponding theme-token selection around the
`2130-2132` path to explicitly handle `permissionMode` values `auto` and `yolo`
before falling back to the default `border` token, while preserving the
highlighted `primary` behavior.
In `@apps/pythinker-code/test/tui/activity-pane.test.ts`:
- Line 291: Update both assertions in
apps/pythinker-code/test/tui/activity-pane.test.ts at lines 291-291 and 379-381
to match the BRAILLE_SPINNER_FRAMES character set before “Orchestrating” instead
of only quarter-circle frames, ensuring the tests fail when an aggregate Braille
spinner remains after completion or cleanup.
- Line 223: Add the Unicode (u) flag to both Braille-frame regular expressions
in activity-pane.test.ts: the matcher at lines 223-223 and the matcher at lines
372-374.
In `@apps/pythinker-code/test/tui/components/messages/thinking.test.ts`:
- Around line 92-103: Update the thinking component test assertions around
firstHeader and fullCycleHeader to validate each rendered header exists before
comparison, then compare the headers directly without any `?? ''` fallbacks.
Remove the conditional fallbacks from the mapped equality assertion as well,
preserving the existing shimmer and frame-cycle checks.
In `@apps/pythinker-code/test/tui/components/messages/tool-call.test.ts`:
- Around line 106-108: Update the truncated-call assertion in the test around
component.render(40) to first store the rendered lines and assert their length
is greater than zero, then verify none of those lines contain the background
codes. Keep the existing backgrounds check unchanged after establishing a
non-empty render result.
In `@apps/pythinker-code/test/tui/components/panels/footer-bg-agents.test.ts`:
- Around line 56-57: Add the Unicode flag to every affected regular expression:
both badge-match expressions at lines 56-57, 64-65, and 82-83 in
apps/pythinker-code/test/tui/components/panels/footer-bg-agents.test.ts; the NaN
expressions at lines 66 and 75 in
apps/pythinker-code/test/tui/components/panels/footer-context.test.ts; and the
goal expressions at lines 86 and 137 in
apps/pythinker-code/test/tui/components/panels/footer-goal-badge.test.ts.
Preserve each existing pattern and assertions.
In `@apps/pythinker-code/test/tui/components/status-bar.test.ts`:
- Line 62: Update the status-bar tests around component.render(80), including
the assertions at lines 62 and 73-75, to first assert that the render result
contains exactly one row before checking row contents. Keep the existing content
assertions unchanged after establishing the non-empty render result.
---
Nitpick comments:
In `@apps/pythinker-code/src/tui/components/messages/tool-call.ts`:
- Around line 662-669: Update the background selection expression in the
tool-call component to check the error case first, using toolErrorBg when
result.is_error === true and toolSuccessBg as the fallback; preserve the
existing pending/truncated behavior and treat undefined is_error as success.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 749f2919-60a2-4133-895c-7e07beca7695
📒 Files selected for processing (30)
.changeset/tui-signature-design.mdapps/pythinker-code/src/tui/components/chrome/activity-loader.tsapps/pythinker-code/src/tui/components/chrome/footer.tsapps/pythinker-code/src/tui/components/chrome/status-bar.tsapps/pythinker-code/src/tui/components/dialogs/compaction.tsapps/pythinker-code/src/tui/components/messages/dynamic-workflow-mission-control.tsapps/pythinker-code/src/tui/components/messages/thinking.tsapps/pythinker-code/src/tui/components/messages/tool-call.tsapps/pythinker-code/src/tui/constant/rendering.tsapps/pythinker-code/src/tui/pythinker-tui.tsapps/pythinker-code/src/tui/runtime/footer/footer-model.tsapps/pythinker-code/src/tui/tui-state.tsapps/pythinker-code/src/tui/utils/session-accent.tsapps/pythinker-code/src/tui/utils/shimmer.tsapps/pythinker-code/test/tui/activity-pane.test.tsapps/pythinker-code/test/tui/components/chrome/footer.test.tsapps/pythinker-code/test/tui/components/dialogs/compaction.test.tsapps/pythinker-code/test/tui/components/messages/dynamic-workflow-mission-control.test.tsapps/pythinker-code/test/tui/components/messages/thinking.test.tsapps/pythinker-code/test/tui/components/messages/tool-call.test.tsapps/pythinker-code/test/tui/components/panels/footer-bg-agents.test.tsapps/pythinker-code/test/tui/components/panels/footer-context.test.tsapps/pythinker-code/test/tui/components/panels/footer-goal-badge.test.tsapps/pythinker-code/test/tui/components/status-bar.test.tsapps/pythinker-code/test/tui/controllers/session-event-handler-goal-queue.test.tsapps/pythinker-code/test/tui/pythinker-tui-message-flow.test.tsapps/pythinker-code/test/tui/pythinker-tui-startup.test.tsapps/pythinker-code/test/tui/runtime/footer-model.test.tsapps/pythinker-code/test/tui/utils/session-accent.test.tsapps/pythinker-code/test/tui/utils/shimmer.test.ts
💤 Files with no reviewable changes (2)
- apps/pythinker-code/src/tui/components/chrome/activity-loader.ts
- apps/pythinker-code/src/tui/components/dialogs/compaction.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/pythinker-code/test/tui/pythinker-tui-startup.test.ts
- .changeset/tui-signature-design.md
- apps/pythinker-code/src/tui/tui-state.ts
- apps/pythinker-code/test/tui/pythinker-tui-message-flow.test.ts
Assertions that indexed or folded over a render result treated a missing row as an empty string or an empty array, so they passed when the component rendered nothing. They now assert a row exists first. Also match braille loader frames when checking that a terminal workflow stopped animating.
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @pythoughts/pythinker-code@0.16.0 ### Minor Changes - [#59](#59) [`6999b68`](6999b68) - Add an opt-in advisor: a second model reviews the conversation after a completed user turn unless another review is already running, and its notes appear as an `<advisory>` block in the agent's next turn; enable with `[advisor] enabled = true` plus an advisor model (the `advisor` model role or `[advisor] model`), and it runs only when the advisor shares the session model's provider. - [#56](#56) [`b71f094`](b71f094) - Add model roles: lock a model alias to the small, implementer, or advisor slot with `/model <role>`, list assignments with `/model roles`, and reference roles as `@small`, `@implementer`, or `@advisor` wherever a subagent model can be set; an assigned implementer role becomes the default model for subagents. - [#57](#57) [`99c427c`](99c427c) - Show what the agent is doing in the working indicator: eligible tool calls whose input schema accepts the injected field now carry a short model-written intent, streamed live into the spinner label (for example "check failing test…") instead of a rotating placeholder; disable with `PYTHINKER_CODE_EXPERIMENTAL_TOOL_INTENT=0`. - [#58](#58) [`065bf2e`](065bf2e) - Redesign core TUI surfaces: tool cards get state-tinted backgrounds with three new theme tokens, a status bar with a per-session accent color appears between the input box and footer, and the prompt box uses a neutral border while permission mode appears in the status bar. The working-label shimmer uses a calmer constant-velocity sweep with alternating mission-control highlights. ### Patch Changes - [#62](#62) [`7fc36fd`](7fc36fd) - Repair invalid escape sequences and unescaped quotes in model-written tool arguments instead of failing the tool call. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Related Issue
No linked issue — directly requested design work; problem explained below.
Problem
Tool-call blocks, the input chrome, and the working shimmer are visually flat: tool state (running / succeeded / failed) is only distinguishable by a small glyph, parallel sessions look identical, and permission modes are invisible while typing.
What changed
Four signature visual elements ported from an MIT-licensed terminal-agent design:
toolPendingBg,toolSuccessBg,toolErrorBg) added to both palettes, the custom-theme JSON schema, the theme docs, and the custom-theme skill table.Three existing layout/shimmer expectation tests were updated to match the intended new visuals; all other tests pass unchanged.
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.Summary by CodeRabbit
New Features
Documentation