Skip to content

feat(tui): TUI enhancements, security-audit remediation, and multi-instance hardening - #103

Merged
elkaix merged 22 commits into
mainfrom
feat/tui-enhancements-and-hardening
Jun 10, 2026
Merged

feat(tui): TUI enhancements, security-audit remediation, and multi-instance hardening#103
elkaix merged 22 commits into
mainfrom
feat/tui-enhancements-and-hardening

Conversation

@elkaix

@elkaix elkaix commented Jun 10, 2026

Copy link
Copy Markdown
Member

Related Issue

Resolve #(issue_number)

Description

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

elkaix added 20 commits June 9, 2026 18:23
Turn recaps now default off; the agent only recaps when asked. Add a
direct toggle — /config recaps on|off (also /settings recaps ...) —
that persists to the config file and reloads the shell. The interactive
/settings panel keeps its existing turn-recaps item.

Part of the Codex TUI adoption backlog (item 0.1).
Port the Codex terminal-adaptation layer (codex-rs/tui) to Python:

- ui/color_utils.py: hex parse/format, linear RGB blend, BT.601 luma.
- ui/terminal_background.py: OSC 11 background probe (100ms timeout,
  per-process cache, PYTHINKER_NO_BG_PROBE opt-out) and theme = "auto"
  resolution with a dark fallback. /theme and the settings selector
  accept the new value.
- terminal_capabilities.color_depth(): three usable color tiers
  (truecolor/256/16 + none) honoring FORCE_COLOR levels and the
  Windows Terminal WT_SESSION truecolor promotion.
- get_diff_colors(): 16-color terminals now get plain green/red
  foreground diff styles instead of quantized hex background tints.

/theme now compares against the persisted setting rather than the
resolved active theme so users can pin dark/light while on auto.

Backlog items 1.1-1.4.
Adopt the Codex renderer-safety behaviors:

- Syntax-highlight size guard: code blocks beyond 512 KiB or 10k lines
  render as plain text with a 'highlighting skipped (N lines)' notice
  instead of paying an unbounded Pygments cost.
- Large diff guard: expanded diffs are capped at 400 rendered lines
  (head + tail with an explicit omitted-line count) so one huge edit
  cannot freeze or flood the terminal.
- Generic tool output switches from head-only to head-tail truncation,
  keeping the start (identifies the result) and the end (the actionable
  part) with an omitted-line notice.
- Fence unwrapping for tables: ```md/```markdown fences whose body
  contains a header+delimiter table pair now render as markdown instead
  of opaque code. Conservative Codex heuristics: other languages,
  untagged fences, md fences without tables, and unclosed fences pass
  through unchanged.

Backlog items 2.6, 3.1, 6.2, 7.5.
User-directed design wave on top of the Codex adoption Phase 1:

- Transcript marker is now ⏺ (U+23FA) on macOS/Linux — Windows keeps the
  text circle, ASCII mode keeps the star. Tool/assistant rows blink the
  marker while running (reduced-motion pins it static) and settle to the
  solid green marker when finished; thinking rows carry the marker too.
- Activity coral muted to a clay ramp (#C68D7E/#D8AC9E/#E9CDC2 dark,
  #B26A52/#9E563E/#82412D light). Shimmer simplified from wave+splash to a
  calm bidirectional sweep with settle beats; truecolor terminals get a
  continuous cosine-blended sheen via ui.color_utils.blend, lower tiers
  keep the discrete ramp.
- Activity/todo headers share one metadata design:
  'Verb… (12s, ↓ 2.4k tokens, 45 t/s)' — parenthesized, comma-separated,
  with a live tokens/sec readout on the working indicator and the pinned
  todo header (sliding-window rate over the turn's context tokens).
- Thinking-effort frame colors form a cold→hot gradient ending on dark red
  for xhigh (slate→blue→teal→amber→orange→red).
- Pinned todos: the active task title+box are coral; concurrent in-progress
  rows read light grey so the running task stays unmistakable.
- Diff word-level highlights drop reverse-video for the theme's add/del
  highlight backgrounds (GitHub-style emphasis, no glare).
- Turn recap is padded to the card inset instead of spanning edge-to-edge.

Hardening (findings from the in-app review validated and fixed):
- Terminal probe: catch select's ValueError (fd >= FD_SETSIZE), suppress
  tcsetattr restore failures, cap the OSC reply buffer at 4 KiB, and
  serialize the probe cache behind a lock.
- Generic tool-output head/tail truncation halves the char budget per side
  so combined output can never exceed the limit.
- /settings arg parsing splits the mode string once.
- Added ~~~md tilde-fence unwrap coverage.
Second design wave driven by side-by-side comparison with the reference
transcripts:

- Tool headers use the parenthesized single-line form — ⏺ Bash(cmd…),
  ⏺ Update(path) — ellipsizing at the terminal edge instead of wrapping.
- Result gutters no longer pad rows with trailing spaces to the terminal
  edge (copy-clean, ragged-right like the reference).
- Todo list matches the reference: coral ■ box with bold default-color
  (white) title for in-progress rows, green ✓ with struck muted titles
  for done rows; coral stays on the top activity line.
- Diff palette set to the specified values: row tints #052e05/#3a0808,
  sign/line-number accents #81C784/#E57373, content in the terminal's
  default (white) over the tint. Also fixes a span-layering bug where
  the row restyle buried word-level highlights.
- Dark text hierarchy: primary output #D4D4D4; UI chrome (gutters, line
  numbers, expand hints, toolbar metadata) #6F6F6F.
- Thinking-effort input bars dim their gradient color 30% toward the
  background pole so the frame hints without shouting.
- The 'N background agents' line is gone everywhere — the bottom toolbar
  owns that count; the verb spinner + todos remain. Background subagent
  status rows hang-indent under their label.
- Welcome banner gains a bold /init tip when the repo has no AGENTS.md
  or CLAUDE.md.
The pinned todo list is drawn by two code paths — the live view during a
foreground turn and the prompt-side background status between turns —
and they had drifted apart (◼/◻/✔ vs ■/□/✓ glyphs, hex off-white vs
terminal-default bold titles, bright pending rows, no strikethrough).
That made running tasks appear to change style mid-session.

Both paths now render identically: coral ■ with a bold default-color
(white) title for running rows, muted □ pending, green ✓ with struck
muted titles when done.
… consistency

Three fixes from live-session screenshots:

- Pinned todo rows no longer carry a muted base style: the bold
  running-task title sets no color of its own, so the muted base bled
  through and rendered it grey instead of the terminal-default white.
  The base style is gone; prefix/icon/title each carry their own style.
- The background working status line ('Ebbing…') now shows the same
  '(elapsed, ↓ Nk tokens, N t/s)' metadata as the live working
  indicator: elapsed since background work appeared and a 1.5s
  sliding-window token rate over the status snapshot, dropped first on
  narrow terminals and reset when background work drains.
- Word-level diff highlights are gated on line similarity (ratio >= 0.5):
  heavy single-line rewrites previously flooded the whole row with the
  brighter highlight tint, reading as a different palette from plain
  added/removed rows. Such rewrites now render as plain rows.
Completes the c8c0f05 commit: the prompt.py change was clobbered from
the index by a concurrent session's git operation before that commit
landed, leaving the renderer half-committed.

The background working status line ('Ebbing…') now carries the same
'(elapsed, ↓ Nk tokens, N t/s)' metadata as the live working indicator:
elapsed since background work first appeared and a 1.5s sliding-window
token rate over the status snapshot's context tokens. The metadata is
dropped first on narrow terminals and both trackers reset when
background work drains.
Notification, progress-note, question-answered, and suggestion rows in
the transcript still rendered with BulletColumns' default list bullet.
They now carry the record marker in the block's accent color (severity
for notifications, green for progress/answers, accent for suggestions).
Genuine list rows — /help sections and nested subagent detail lines —
deliberately keep the list dot.
Refactor all default agent YAML prompts with explicit Mission / Hard
Constraints / Workflow / Output Contract sections for consistency and
clarity. Update system.md overlay accordingly.

Harden background manager, subagent runner, and agent tool to align
with the Codex TUI adoption (Phase 1) gap map: stale-record
reconciliation, resume contract enforcement, and interactive-visualizer
fixes. Update all affected unit and e2e tests.
Implements the remediation plan for the validated audit findings
(1 Critical, 15 High, 29 Medium, 20 Low) across five phases, each fix
behind a TDD test and gated by `make check` plus a security review.

Phase 0 — shell permission classifier: close the read-only / auto-mode
  bypass cluster (interior &/|& separators, casefolded base commands,
  wrapper value-options, find/xargs/awk payloads, glued output
  redirection, unsafe `git -c`, uv sub-namespaces and `uv run`
  option-prefix bypass).
Phase 1 — confinement, egress, telemetry: symlink-resolve file
  read/write/edit and grep before workspace/sensitive checks; fail-closed
  SSRF with a connection-pinned resolver; bounded shell wait; Sentry
  path/home redaction; invisible-char and case-folded sensitive-file
  handling; sensitive-import gate; untrusted-output wrapping; subagent-id
  path validation.
Phase 2 — tool dispatch, lifecycle, context integrity: MCP-vs-builtin
  tool collisions; run_soul task-leak cleanup; restore-id/path traversal
  guards; compaction rollback; mid-tool-cancel turn balance; cyclic-extend
  detection.
Phase 3 — wire server, auth, web-server: wire read-loop hardening; OAuth
  refresh / device-id / 403 handling; provider base_url validation; replay
  watermark; session-leak cleanup; ZIP-import validation.
Phase 4 — UI/usage/CLI: ANSI sanitization at render boundaries (incl.
  generic tool arg-key names); usage-meter consumed-vs-remaining;
  reset-window loop guard; RunAgents approval fingerprint over child
  prompts; owner-only MCP config; live Typer help; /restore traversal and
  error handling; bounded approval-request store.

Review-found gaps were fixed with regression tests: uv-run option bypass,
grep symlink escape, SSH-key import gate, ANSI arg-key injection, and the
MCP-config / share-dir permission race. Also hardens auth JSON parsing.
- app.py: detect AGENTS.md/CLAUDE.md in the session work_dir (awaiting the
  async HostPath.exists) instead of process cwd, so the /init tip is correct
  when cwd differs from the session path.
- color_utils.py: replace EN DASH with ASCII hyphen in the luma docstring.
- slash.py: clarify the recaps config-flag guidance (--config vs --config-file).
- terminal_background.py: debug-log swallowed OSC11 probe failures instead of
  silently degrading, per the exception-handling rule.
- tests: annotate the autouse fixture return type; tighten the thinking-status
  metadata assertion to validate the token-count block, not just any paren.
Qwen3.x/3.7 are hybrid thinking models: reasoning is toggleable per request
via the standard Anthropic thinking block, which the OpenCode Go
@ai-sdk/anthropic route (and Alibaba Model Studio's Anthropic-compatible
endpoint) accepts as {"type": "enabled", "budget_tokens": N} /
{"type": "disabled"}.

Previously OpenCode Go Qwen models got no thinking capability, so their
effort was uncontrollable — while the Alibaba plan already exposed it. Give
the Qwen family the controllable 'thinking' capability so create_llm routes
the selected effort through with_thinking, which (for these non-Claude
models) emits the budget-based payload and clamps xhigh/max -> high,
minimal -> low. GLM/MiniMax remain always_thinking (effort can't be turned
off); Qwen can.

Adds a clamp regression case pinning the budget-safe mapping for qwen3.7-max
so the budgets[...] lookup can never KeyError.
Stop recoloring the whole input border by thinking effort. The border is now
one static frame grey at every level; the effort signal moves to a small
label flushed right on the input's top border — a level-colored dot
(off->max: slate->blue->teal->amber->orange->red) plus the muted level word.

The dot carries the cold->hot color at full strength (it's a single glyph),
while the word uses a muted class so it never competes with the typed text.
The label is hidden for native-thinking models (always_thinking with no user
dial) and non-thinking models, and the rule auto-shortens by the measured
label width so the top line never wraps.

_prompt_separator_style no longer borrows thinking_frame_style, so all input
separators (top border and footer) render the same static frame grey.
…king

Two related thinking-effort changes:

1. Remove the duplicated effort indicator from the footer (the
   'agent <model> • <effort>' / 'native reasoning' text under the input).
   Effort now shows in exactly one place — the top-border label added
   earlier. The footer mode line is just 'agent <model>', degrading to the
   bare mode on narrow terminals. Drops the now-orphaned
   _thinking_footer_label helper.

2. Mark all Qwen models (qwen3.7-max/plus, qwen3.6-plus/flash, qwen3 coder
   plus/flash on Alibaba; qwen* on OpenCode Go) as always_thinking instead
   of the controllable 'thinking' capability. Qwen now matches GLM/MiniMax:
   reasoning is native and always on, with no user effort dial and no
   top-border effort label. Reasoning still flows over the Anthropic
   thinking block both Anthropic-compatible routes accept.
Critical permission-classifier bypasses:
- sudo long value-options (`sudo --user alice rm -rf /`) were not consumed, so
  the wrapped destructive payload classified as the option's value. Add the long
  forms to _SUDO_VALUE_OPTS.
- uv global options before `run` (`uv --directory repo run rm -rf /`) hid the
  subcommand; the global flag's value was mistaken for it. Add
  _uv_strip_global_opts and apply it in both mutation and destructive paths.

Major:
- file_restore: treat missing (None) or malformed-base64 content as a corrupt
  restore point instead of silently writing an empty/garbage file.
- web/fetch: _ip_is_blocked now fails closed (blocks) on an unparseable address.
- scratchpad: stop unlinking the advisory lock file (split-inode race); keep it
  persistent and add *.scratchpad.lock to the written .gitignore patterns.
- soul shutdown: don't re-await an already-finished task in the cleanup loop —
  retrieve its exception without re-raising so the rest of shutdown still runs.
- pythinkersoul: on mid-tool interruption, keep the real results of calls that
  already completed (captured via on_tool_result) and only synthesize the
  interruption marker for still-pending calls.

Minor / nitpick:
- /import arg parsing now uses shlex via a shared parse_import_args helper
  (soul/slash + ui/shell/export_import), preserving quoted paths.
- web/runner: offload the blocking wire-file stat with asyncio.to_thread;
  document the intentional broad except at the per-message dispatch boundary.
- cli/vis: rename unused callback param to _ctx.
- tests: regression cases for both bypasses; strengthened import token-count
  assertions; lock-file persistence test; minor annotations.
Security/correctness (multi-agent review of the branch; every finding
verified against the live code before fixing):
- permission gate: classify awk shell-outs (print | "cmd", getline) as
  mutating AND destructive; recognize xargs -L payloads
- Glob: resolve symlinks before the workspace boundary check
- transcript: sanitize ANSI in progress-note titles
- Grep: control-char field separators end path/lineno misparsing
  (utf-8-codec.py) and make sensitive-file attribution exact
- StrReplaceFile: CRLF-translate LF-joined multi-line old strings
- /import: parse --force from the raw string; paths byte-preserved
- compaction restore: keep --add-dir files in reminders
- soul: settle shielded context writes across repeated cancellations
- web replay: stat failure replays full history instead of none
- Agent resume: malformed ids return a clean 'Agent not found'
- oauth: fail loud on missing refresh_token at login; carry expires_in
  forward on refresh; never read an empty device id
- /theme auto: failed background probe can be re-probed via /theme
- markdown: fence walker honors CommonMark close rules (no info string)
- /restore: cheap id-format guard replaces loading every snapshot

Multi-instance robustness:
- per-session writer lock (.owner.lock) in the CLI and web worker
- pythinker.json mutations go through a locked read-modify-write
- JSONL appenders repair torn final lines; forks materialize atomically
- session/wire scanners skip non-object lines instead of crashing
- project memory: strict reads on mutation (no wipe on transient EIO),
  journal capped at 100 recaps, atomic inbox claim, mtime-based recall
  re-arm, flock acquisition off the event loop

Subagent orchestration:
- summary-continuation failure keeps the completed result
- hallucinated subagent types fail fast with the valid-type list
  (Agent and RunAgents, before any child launches)
- background failures carry an Agent ID + resume hint; finalize is
  guarded; runner crashes are surfaced via the done callback
- copy_for_role shares the live-task registry (no false orphans)

Cleanup: shared blink_visible() (12 copies), used_from_remaining()
(6 copies), is_local_host reuse, single realpath pass in write/replace,
cached thinking-frame blend, MCP cross-server shadow warning.
Mechanical, behavior-preserving split by responsibility: constants,
catalog, oauth_client, browser_flow, models, config_apply, login, plus
a package __init__ re-exporting the existing import surface. Applies
the accepted clean-code review items: JsonObject boundary typing with
narrow casts, _parse_chatgpt_model_item extraction,
_default_config_error / _handled_error_event helpers, and
private-helper renames (_first_present_field /
_first_non_empty_string_field). Test monkeypatch targets follow the
moved definitions. Includes the audit's 401/403 login message split,
which now lives in login.py.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 222 files, which is 72 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8b78bed2-3484-4391-abf5-da8b27aa0d7f

📥 Commits

Reviewing files that changed from the base of the PR and between 00e7b67 and 5fd2fd0.

📒 Files selected for processing (222)
  • .gitignore
  • CHANGELOG.md
  • packages/pythinker-core/tests/test_anthropic_thinking.py
  • packages/pythinker-host/src/pythinker_host/__init__.py
  • packages/pythinker-host/src/pythinker_host/local.py
  • packages/pythinker-host/src/pythinker_host/path.py
  • packages/pythinker-host/src/pythinker_host/ssh.py
  • packages/pythinker-review/tests/unit/test_security_intel.py
  • src/pythinker_code/__main__.py
  • src/pythinker_code/acp/host.py
  • src/pythinker_code/agents/default/ask.yaml
  • src/pythinker_code/agents/default/code_reviewer.yaml
  • src/pythinker_code/agents/default/coder.yaml
  • src/pythinker_code/agents/default/debug.yaml
  • src/pythinker_code/agents/default/debugger.yaml
  • src/pythinker_code/agents/default/explore.yaml
  • src/pythinker_code/agents/default/implementer.yaml
  • src/pythinker_code/agents/default/judge.yaml
  • src/pythinker_code/agents/default/plan.yaml
  • src/pythinker_code/agents/default/planner.yaml
  • src/pythinker_code/agents/default/review.yaml
  • src/pythinker_code/agents/default/scout.yaml
  • src/pythinker_code/agents/default/security_reviewer.yaml
  • src/pythinker_code/agents/default/system.md
  • src/pythinker_code/agents/default/verifier.yaml
  • src/pythinker_code/agentspec.py
  • src/pythinker_code/app.py
  • src/pythinker_code/approval_runtime/runtime.py
  • src/pythinker_code/auth/alibaba.py
  • src/pythinker_code/auth/lm_studio.py
  • src/pythinker_code/auth/oauth.py
  • src/pythinker_code/auth/ollama.py
  • src/pythinker_code/auth/openai.py
  • src/pythinker_code/auth/openai/__init__.py
  • src/pythinker_code/auth/openai/_shared.py
  • src/pythinker_code/auth/openai/browser_flow.py
  • src/pythinker_code/auth/openai/catalog.py
  • src/pythinker_code/auth/openai/config_apply.py
  • src/pythinker_code/auth/openai/constants.py
  • src/pythinker_code/auth/openai/login.py
  • src/pythinker_code/auth/openai/models.py
  • src/pythinker_code/auth/openai/oauth_client.py
  • src/pythinker_code/auth/opencode_go.py
  • src/pythinker_code/background/agent_runner.py
  • src/pythinker_code/background/manager.py
  • src/pythinker_code/cli/__init__.py
  • src/pythinker_code/cli/export.py
  • src/pythinker_code/cli/mcp.py
  • src/pythinker_code/cli/vis.py
  • src/pythinker_code/cli/web.py
  • src/pythinker_code/config.py
  • src/pythinker_code/file_restore.py
  • src/pythinker_code/hooks/engine.py
  • src/pythinker_code/memory/consolidation.py
  • src/pythinker_code/memory/recall.py
  • src/pythinker_code/metadata.py
  • src/pythinker_code/plugin/manager.py
  • src/pythinker_code/project_memory.py
  • src/pythinker_code/scratchpad.py
  • src/pythinker_code/session.py
  • src/pythinker_code/session_cleanup.py
  • src/pythinker_code/session_fork.py
  • src/pythinker_code/share.py
  • src/pythinker_code/soul/__init__.py
  • src/pythinker_code/soul/compaction_restore.py
  • src/pythinker_code/soul/context.py
  • src/pythinker_code/soul/permission.py
  • src/pythinker_code/soul/pythinkersoul.py
  • src/pythinker_code/soul/slash.py
  • src/pythinker_code/soul/toolset.py
  • src/pythinker_code/subagents/discovery.py
  • src/pythinker_code/subagents/runner.py
  • src/pythinker_code/subagents/store.py
  • src/pythinker_code/telemetry/errors.py
  • src/pythinker_code/telemetry/sentry.py
  • src/pythinker_code/tools/agent/__init__.py
  • src/pythinker_code/tools/background/__init__.py
  • src/pythinker_code/tools/file/glob.py
  • src/pythinker_code/tools/file/grep_local.py
  • src/pythinker_code/tools/file/read.py
  • src/pythinker_code/tools/file/replace.py
  • src/pythinker_code/tools/file/write.py
  • src/pythinker_code/tools/shell/__init__.py
  • src/pythinker_code/tools/web/fetch.py
  • src/pythinker_code/ui/color_utils.py
  • src/pythinker_code/ui/shell/__init__.py
  • src/pythinker_code/ui/shell/components/bash_execution.py
  • src/pythinker_code/ui/shell/components/bordered_loader.py
  • src/pythinker_code/ui/shell/components/diff.py
  • src/pythinker_code/ui/shell/components/markdown.py
  • src/pythinker_code/ui/shell/components/render_utils.py
  • src/pythinker_code/ui/shell/components/tool_execution.py
  • src/pythinker_code/ui/shell/export_import.py
  • src/pythinker_code/ui/shell/glyphs.py
  • src/pythinker_code/ui/shell/mcp_status.py
  • src/pythinker_code/ui/shell/motion.py
  • src/pythinker_code/ui/shell/prompt.py
  • src/pythinker_code/ui/shell/render_constants.py
  • src/pythinker_code/ui/shell/selectors/settings.py
  • src/pythinker_code/ui/shell/slash.py
  • src/pythinker_code/ui/shell/tool_renderers/_file_diff.py
  • src/pythinker_code/ui/shell/tool_renderers/_render_utils.py
  • src/pythinker_code/ui/shell/tool_renderers/agent.py
  • src/pythinker_code/ui/shell/usage.py
  • src/pythinker_code/ui/shell/usage_adapters/alibaba.py
  • src/pythinker_code/ui/shell/usage_adapters/base.py
  • src/pythinker_code/ui/shell/usage_adapters/minimax.py
  • src/pythinker_code/ui/shell/usage_adapters/openai_chatgpt.py
  • src/pythinker_code/ui/shell/visualize/_activity_tree.py
  • src/pythinker_code/ui/shell/visualize/_blocks.py
  • src/pythinker_code/ui/shell/visualize/_btw_panel.py
  • src/pythinker_code/ui/shell/visualize/_interactive.py
  • src/pythinker_code/ui/shell/visualize/_live_view.py
  • src/pythinker_code/ui/shell/visualize/_worklog.py
  • src/pythinker_code/ui/terminal_background.py
  • src/pythinker_code/ui/terminal_capabilities.py
  • src/pythinker_code/ui/theme.py
  • src/pythinker_code/utils/aiohttp.py
  • src/pythinker_code/utils/export.py
  • src/pythinker_code/utils/io.py
  • src/pythinker_code/utils/path.py
  • src/pythinker_code/utils/rich/columns.py
  • src/pythinker_code/utils/sensitive.py
  • src/pythinker_code/utils/trust.py
  • src/pythinker_code/vis/api/sessions.py
  • src/pythinker_code/web/api/config.py
  • src/pythinker_code/web/api/sessions.py
  • src/pythinker_code/web/runner/process.py
  • src/pythinker_code/web/runner/worker.py
  • src/pythinker_code/wire/file.py
  • src/pythinker_code/wire/server.py
  • tasks/todo.md
  • tests/auth/test_alibaba_auth.py
  • tests/auth/test_lm_studio_auth.py
  • tests/auth/test_oauth_device_id.py
  • tests/auth/test_oauth_refresh.py
  • tests/auth/test_ollama_auth.py
  • tests/auth/test_openai_auth.py
  • tests/auth/test_opencode_go_auth.py
  • tests/background/test_manager.py
  • tests/conftest.py
  • tests/core/test_agent_spec.py
  • tests/core/test_approval_auto.py
  • tests/core/test_approval_runtime.py
  • tests/core/test_cli_reload.py
  • tests/core/test_compaction_restore.py
  • tests/core/test_config.py
  • tests/core/test_default_agent.py
  • tests/core/test_export_cli.py
  • tests/core/test_file_restore_points.py
  • tests/core/test_mcp_docker_rm.py
  • tests/core/test_notifications.py
  • tests/core/test_permission_profiles.py
  • tests/core/test_plan_flag.py
  • tests/core/test_project_memory.py
  • tests/core/test_pythinkersoul_turn_balance.py
  • tests/core/test_recall_provider.py
  • tests/core/test_scratchpad.py
  • tests/core/test_session.py
  • tests/core/test_session_fork.py
  • tests/core/test_shell_mcp_status.py
  • tests/core/test_soul_import_command.py
  • tests/core/test_startup_imports.py
  • tests/core/test_subagent_discovery.py
  • tests/core/test_subagent_store.py
  • tests/core/test_toolset.py
  • tests/core/test_wire_file_compat.py
  • tests/core/test_wire_plan_mode.py
  • tests/core/test_wire_server_steer.py
  • tests/e2e/test_cli_error_output.py
  • tests/e2e/test_shell_modal_e2e.py
  • tests/e2e/test_shell_pty_e2e.py
  • tests/hooks/test_engine.py
  • tests/telemetry/test_sentry_filters.py
  • tests/tools/test_agent_tool.py
  • tests/tools/test_background_tools.py
  • tests/tools/test_fetch_url.py
  • tests/tools/test_glob.py
  • tests/tools/test_grep.py
  • tests/tools/test_read_file.py
  • tests/tools/test_shell_bash.py
  • tests/tools/test_smart_search.py
  • tests/tools/test_str_replace_file.py
  • tests/tools/test_untrusted_wrapping.py
  • tests/tools/test_write_file.py
  • tests/ui/test_shell_markdown.py
  • tests/ui/usage_adapters/test_alibaba_adapter.py
  • tests/ui/usage_adapters/test_minimax.py
  • tests/ui/usage_adapters/test_openai_chatgpt.py
  • tests/ui_and_conv/test_color_utils.py
  • tests/ui_and_conv/test_empty_think_part_indicator.py
  • tests/ui_and_conv/test_export_import.py
  • tests/ui_and_conv/test_live_view_notifications.py
  • tests/ui_and_conv/test_live_view_todos.py
  • tests/ui_and_conv/test_markdown_guards.py
  • tests/ui_and_conv/test_modal_lifecycle.py
  • tests/ui_and_conv/test_output_guards.py
  • tests/ui_and_conv/test_prompt_tips.py
  • tests/ui_and_conv/test_settings_recaps_slash.py
  • tests/ui_and_conv/test_shell_export_import_commands.py
  • tests/ui_and_conv/test_shell_motion.py
  • tests/ui_and_conv/test_shell_motion_shimmer.py
  • tests/ui_and_conv/test_shell_switch_slash.py
  • tests/ui_and_conv/test_streaming_content_block.py
  • tests/ui_and_conv/test_terminal_background.py
  • tests/ui_and_conv/test_terminal_capabilities.py
  • tests/ui_and_conv/test_theme.py
  • tests/ui_and_conv/test_thinking_cycle.py
  • tests/ui_and_conv/test_tool_call_block.py
  • tests/ui_and_conv/test_tui_blocks_integration.py
  • tests/ui_and_conv/test_tui_card_tool_renderers.py
  • tests/ui_and_conv/test_tui_components.py
  • tests/ui_and_conv/test_tui_theme_tokens.py
  • tests/ui_and_conv/test_tui_transcript_enhancements.py
  • tests/ui_and_conv/test_visualize_running_prompt.py
  • tests/ui_and_conv/test_worklog_render.py
  • tests/utils/test_sensitive.py
  • tests/utils/test_trust.py
  • tests/vis/test_app.py
  • tests/web/test_config_api_redaction.py
  • tests/web/test_session_error_recovery.py
  • tests_e2e/test_wire_sessions.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tui-enhancements-and-hardening

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

@elkaix elkaix changed the title Feat/tui enhancements and hardening feat(tui): TUI enhancements, security-audit remediation, and multi-instance hardening Jun 10, 2026
…inals

The flushed-right effort label was appended unconditionally; when the rule
was shorter than the label plus its gap, the line overflowed and wrapped,
contradicting the method's stated no-wrap invariant. Fall back to the plain
full-width rule when the label cannot fit, and add a regression test.
@elkaix
elkaix merged commit 9996984 into main Jun 10, 2026
45 checks passed
@elkaix
elkaix deleted the feat/tui-enhancements-and-hardening branch June 10, 2026 14:27
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.

1 participant