Skip to content

feat: fixed-bottom status bar with adaptive layout and resize watcher#245

Open
MicalLee0415 wants to merge 14 commits into
AI-Shell-Team:mainfrom
MicalLee0415:feat/statusbar
Open

feat: fixed-bottom status bar with adaptive layout and resize watcher#245
MicalLee0415 wants to merge 14 commits into
AI-Shell-Team:mainfrom
MicalLee0415:feat/statusbar

Conversation

@MicalLee0415

@MicalLee0415 MicalLee0415 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: No persistent status display in the terminal — users cannot see token usage, current model, context budget, or API latency at a glance. Additionally, resizing the terminal during read_line causes the prompt and output to break visually. (Issue [Feature] Token额度显示 #35)
  • Changes: Add a fixed-bottom status bar with adaptive 3-tier layout (wide/medium/narrow), pinned via ANSI DECSTBM scroll region. A 200ms polling watcher thread keeps the scroll region correct during terminal resize while read_line is blocking. Fields include model, cwd, context tokens, in/out token counts, request latency, and session state.
  • Related Issue: [Feature] Token额度显示 #35

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Other

Scope

  • Core shell / PTY
  • AI agent / LLM
  • Skills / Tools
  • Security
  • Configuration
  • CLI / Interface
  • Packaging / Installation
  • CI/CD
  • Documentation

User-visible Changes

  • New fixed-bottom status bar showing: model name, current working directory, context token budget, input/output token counts, API request count + latency, and session state
  • Adaptive 3-tier layout based on terminal width: wide (≥100 cols) shows all fields, medium (70–99) shows condensed layout, narrow (<70) shows tokens + state only
  • Ctrl+T keybinding toggles status bar visibility
  • /token show and /token hide slash commands for explicit control
  • Fixed: terminal resize during read_line no longer leaves the prompt/status bar stranded mid-screen

Compatibility

  • Backward compatible? Yes — status bar is visible by default but fully togglable; existing behavior is unchanged
  • Config changes? Yes — new optional StatusBarConfig section added to config.yaml (fields: visible, style, refresh_interval_ms, pricing). Existing configs without this section get sensible defaults; no migration needed

Testing

  • cargo check --workspace — clean (1 pre-existing dead_code warning, unrelated)
  • 23/23 statusbar unit tests pass
  • tmux QA — all resize scenarios verified:
    • Resize taller (24→30 rows): status bar snaps to new bottom, no duplication
    • Resize shorter (30→18 rows): old status bar rows cleared, prompt repositioned correctly
    • Resize back (18→24 rows): clean state restored, no visual artifacts
  • Manual: Ctrl+T toggle, /token show, /token hide all confirmed working

Checklist

  • Code follows project style
  • Tests added (23 unit tests)
  • Documentation updated (i18n strings in all 6 locales)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a fixed bottom status bar showing token usage, context budget/progress, policy info, and AI/tool activity (latency included), with Ctrl+T to toggle.
    • Integrated built-in LLM cost estimation into the token panel, with optional per-model pricing overrides.
    • Added /token hide and /token show commands.
    • Expanded token/status bar translations (en-US, de-DE, es-ES, fr-FR, ja-JP, zh-CN).
  • Bug Fixes

    • Improved status bar behavior: reliably pinned across terminal resizes and restored after slash interactions.
  • Tests

    • Updated slash-command table count expectations.
  • Chores

    • Updated the ignore list to exclude AGENTS.md.

MicalLee0415 and others added 8 commits June 15, 2026 17:26
Add ModelPricing struct, lookup_pricing(), and estimate_cost() for computing API costs based on model name, input/output token counts, and optional per-model pricing overrides.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add StatusBarConfig struct with visible/style/refresh_interval_ms fields and optional per-model pricing overrides. Register in ConfigModel with serde defaults.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add statusbar.notice.hidden key across all 6 locales (en/zh/ja/de/fr/es).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add statusbar module with Plan C adaptive layout (cwd, context tokens, I/O split, cost, request count, latency, state), ANSI scroll region management (enter/exit/reassert_after_resize), Ctrl+T toggle rendering, and 23 unit tests covering latency formatting, cwd shortening, progress bars, and state segments.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bind Ctrl+T to a StatusToggleHandler that interrupts read_line so the main loop can toggle status bar visibility. Also add /token show and /token hide to slash command list.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add context_budget_state() accessor so the status bar can display current token usage and budget percentage.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Wire status bar into the main REPL loop: enter/exit fixed mode on startup/shutdown, render status bar each iteration, time AI API calls for latency display, detect terminal resize, and spawn a background polling thread (200ms interval) that re-asserts the ANSI scroll region during read_line when the terminal is resized — preventing the prompt and status bar from being stranded mid-screen.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@github-actions github-actions Bot added ci-cd CI/CD workflow issue size: XL labels Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Template check passed. Thanks for updating the pull request description.

Resolve conflict in crates/aish-shell/src/lib.rs: keep both
pub mod status (from PR AI-Shell-Team#242) and pub mod statusbar (this PR).
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 89cfa542-0af0-4172-a902-add7ea583168

📥 Commits

Reviewing files that changed from the base of the PR and between c58908c and d21b226.

📒 Files selected for processing (2)
  • crates/aish-llm/src/pricing.rs
  • crates/aish-shell/src/app.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/aish-llm/src/pricing.rs
  • crates/aish-shell/src/app.rs

📝 Walkthrough

Walkthrough

Adds a persistent fixed-bottom ANSI status bar to the shell REPL displaying token usage, estimated cost, context budget, AI activity state, and API latency. New StatusBarConfig and PricingEntry config types, a pricing module in aish-llm with a hardcoded pricing table, a new statusbar module in aish-shell, Ctrl+T toggle, /token hide//token show commands, and i18n strings for six locales are introduced.

Changes

Status Bar Feature

Layer / File(s) Summary
Config types and pricing data contract
crates/aish-config/src/model.rs, crates/aish-config/src/lib.rs, crates/aish-llm/src/lib.rs, crates/aish-llm/src/pricing.rs
PricingEntry and StatusBarConfig (with serde defaults) are added to aish-config and re-exported. aish-llm gains a pricing module exporting ModelPricing, lookup_pricing (multi-step model ID resolution: exact → lowercase → last-segment → substring family), and estimate_cost, backed by a hardcoded pricing table across many provider/model families, with unit tests.
statusbar.rs: state types, rendering, and ANSI terminal control
crates/aish-shell/src/lib.rs, crates/aish-shell/src/statusbar.rs
New statusbar module declares StatusBarState, StatusBarVisible, and formatting helpers (tokens K/M, cost USD, progress bar, model/cwd shortening, latency). render_content produces a single-line bar in "single" or "minimal" style. Fixed-bottom ANSI terminal functions (enter_fixed_mode, reassert_after_resize, exit_fixed_mode, render_fixed, clear_fixed) manage DECSTBM scroll regions. render_token_panel renders the /token detail panel. Comprehensive unit tests are included.
Ctrl+T toggle and /token hide/show in readline
crates/aish-shell/src/readline.rs, crates/aish-shell/tests/slash_popup_commands.rs
Adds STATUS_TOGGLE_REQUESTED AtomicBool and StatusToggleHandler that issues Cmd::Interrupt on Ctrl+T. Binds the handler in ShellReadline::new and exposes was_status_toggle_requested(). Adds /token hide and /token show to the SLASH_COMMANDS completion list with updated test assertions.
AiHandler context budget accessor
crates/aish-shell/src/ai_handler.rs
Adds context_budget_state() on AiHandler to expose the context manager's budget state snapshot for status bar state construction.
REPL lifecycle integration
crates/aish-shell/src/app.rs
Adds statusbar_visible, statusbar_visible_atomic, ai_active, last_api_latency_ms, and last_term_size to AishShell. On startup, enters fixed-bottom mode and spawns a resize-watcher thread. Updates the bar on AI turn start/end for both error-correction and NL-to-AI routing paths, handles Ctrl+T, restores bar after slash-popup and plan-approval, extends /token with hide/show, and calls exit_fixed_mode on shutdown. handle_token_command and helpers build_statusbar_state, render_statusbar_fixed, restore_statusbar_if_visible are added.
i18n locale strings and .gitignore
crates/aish-i18n/locales/en-US.yaml, crates/aish-i18n/locales/de-DE.yaml, crates/aish-i18n/locales/es-ES.yaml, crates/aish-i18n/locales/fr-FR.yaml, crates/aish-i18n/locales/ja-JP.yaml, crates/aish-i18n/locales/zh-CN.yaml, .gitignore
Statusbar UI strings (title, context budget, estimated cost, policy, Ctrl+T hint, hidden/shown messages) are added to all six locale YAML files. AGENTS.md is added to .gitignore.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ShellReadline
  participant AishShell
  participant statusbar
  participant ResizeWatcher
  participant AiHandler
  participant aish_llm_pricing

  AishShell->>statusbar: enter_fixed_mode(lines)
  AishShell->>statusbar: render_fixed(state, config)
  AishShell->>ResizeWatcher: spawn(atomic_visible, term_h)
  loop every 200ms
    ResizeWatcher->>statusbar: reassert_after_resize(old_h, lines)
  end

  User->>ShellReadline: Ctrl+T
  ShellReadline-->>AishShell: was_status_toggle_requested() = true
  AishShell->>statusbar: exit_fixed_mode() or enter_fixed_mode()

  User->>AishShell: AI command
  AishShell->>statusbar: render_fixed(ai_active=true)
  AishShell->>AiHandler: run AI turn
  AiHandler-->>AishShell: result + token stats
  AishShell->>aish_llm_pricing: estimate_cost(model, input, output)
  aish_llm_pricing-->>AishShell: Option<f64>
  AishShell->>statusbar: render_fixed(ai_active=false, latency_ms)

  User->>AishShell: /token
  AishShell->>statusbar: render_token_panel(state, config)
  AishShell->>statusbar: exit_fixed_mode() [on shutdown]
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • AI-Shell-Team/aish#187: The main PR's new AiHandler::context_budget_state() accessor depends on the context-budget types/manager API introduced in this PR.
  • AI-Shell-Team/aish#219: The main PR's aish-shell/src/app.rs integrates status-bar rendering into the REPL interruption/slash-popup lifecycle introduced in this PR, sharing slash-command interrupt and popup dismissal flow.
  • AI-Shell-Team/aish#240: Both PRs modify crates/aish-shell/src/readline.rs's SLASH_COMMANDS list (main adds /token hide//token show, this PR adds /doctor), directly overlapping in slash-command table behavior.

Suggested labels

config, experienced-contributor


🐇 A bar at the bottom, glowing with care,
Tokens and costs floating there in the air!
Press Ctrl+T to hide, or /token show
The rabbit renders it row by row.
From pricing tables to ANSI bright,
A fixed-bottom friend that shines just right! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main feature: a fixed-bottom status bar with adaptive layout and automatic resize handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 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 `@crates/aish-llm/src/pricing.rs`:
- Around line 57-62: The substring fallback matching in the loop that iterates
over table.iter() returns the first HashMap match, but HashMap iteration order
is non-deterministic which causes the same model string to map to different
prices across different runs. To fix this, collect the matching keys from the
HashMap iteration (where either lower.contains(key) or key.contains(&lower)),
sort them by specificity such as by length (preferring longer/more specific
matches), and return the pricing for the most specific match rather than
returning immediately on the first match found. This ensures deterministic and
specificity-based pricing selection regardless of HashMap iteration order.

In `@crates/aish-shell/src/app.rs`:
- Around line 3077-3080: The budget_policy field is hardcoded to "sliding" but
should reflect the actual active context budget behavior. Replace the hardcoded
"sliding".to_string() value for the budget_policy field with a dynamic value
derived from either context_budget_state() or self.config.context_auto_compact
so that the status display accurately reports whether context auto-compact is
enabled or disabled. Apply this fix to both occurrences of the budget_policy
field assignment around lines 3077-3080 and 3096-3099.
- Around line 1731-1749: The status bar toggle logic currently only handles
Ctrl+T in the top-level read_line method, but the read_line_after_slash_dismiss
method does not check for was_status_toggle_requested() before falling through
to handle_ctrl_c(). Add the same Ctrl+T status bar toggle check (matching the
logic shown in the diff with statusbar_visible toggling, enter_fixed_mode,
exit_fixed_mode, and render calls) in the read_line_after_slash_dismiss method
before the code that calls handle_ctrl_c(), so that interrupts matching the
status toggle condition are handled properly instead of being treated as Ctrl+C.
- Around line 1981-1987: The error-correction branch that calls
`handle_error_correction(...)` is missing the AI-active status tracking and
latency recording that exists in the main AI branch shown in the diff. Apply the
same pattern to the error-correction branch by setting `self.ai_active = true`,
conditionally calling `self.render_statusbar_fixed()` if
`self.statusbar_visible` is true, and capturing the start time with
`std::time::Instant::now()` before the error correction call. Alternatively,
extract the status initialization and latency tracking logic into a shared
helper method and call it from both the main AI branch and the error-correction
branch to reduce duplication.
- Around line 2379-2383: The resize watcher continues to monitor
statusbar_visible_atomic even during shutdown, which can cause it to reassert
the fixed scroll region after exit_fixed_mode() has reset it if a resize event
occurs. Before calling statusbar::exit_fixed_mode() in the shutdown sequence,
disable or stop the resize watcher first to prevent it from interfering with the
scroll region reset, then proceed with setting statusbar_visible to false and
calling exit_fixed_mode().
- Around line 2623-2635: The "hide" and "show" command handlers only update the
statusbar_visible field but fail to synchronize the resize-watcher atomic field,
causing inconsistency with Ctrl+T behavior. In both the "hide" handler (where
statusbar_visible is set to false) and the "show" handler (where
statusbar_visible is set to true), add corresponding updates to the
resize-watcher atomic field to ensure both visibility tracking mechanisms remain
in sync and prevent the watcher from reasserting the previous state on terminal
resize.
🪄 Autofix (Beta)

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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c897f97-5de8-4252-a0ed-ece4ab8464c4

📥 Commits

Reviewing files that changed from the base of the PR and between 0312ca5 and c29e2cb.

📒 Files selected for processing (16)
  • .gitignore
  • crates/aish-config/src/lib.rs
  • crates/aish-config/src/model.rs
  • crates/aish-i18n/locales/de-DE.yaml
  • crates/aish-i18n/locales/en-US.yaml
  • crates/aish-i18n/locales/es-ES.yaml
  • crates/aish-i18n/locales/fr-FR.yaml
  • crates/aish-i18n/locales/ja-JP.yaml
  • crates/aish-i18n/locales/zh-CN.yaml
  • crates/aish-llm/src/lib.rs
  • crates/aish-llm/src/pricing.rs
  • crates/aish-shell/src/ai_handler.rs
  • crates/aish-shell/src/app.rs
  • crates/aish-shell/src/lib.rs
  • crates/aish-shell/src/readline.rs
  • crates/aish-shell/src/statusbar.rs

Comment thread crates/aish-llm/src/pricing.rs Outdated
Comment thread crates/aish-shell/src/app.rs
Comment thread crates/aish-shell/src/app.rs
Comment thread crates/aish-shell/src/app.rs
Comment thread crates/aish-shell/src/app.rs
Comment thread crates/aish-shell/src/app.rs
- pricing.rs: deterministic substring fallback (sort by specificity)
- app.rs: sync statusbar_visible_atomic in /token hide/show
- app.rs: set atomic=false before exit_fixed_mode on shutdown
- app.rs: handle Ctrl+T in read_line_after_slash_dismiss
- app.rs: add ai_active/latency tracking to error correction branch
- app.rs: derive budget_policy from config instead of hardcoding
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cd CI/CD workflow issue size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant