Skip to content

feat(command): add /clear slash command#20

Merged
remarkablemark merged 9 commits into
masterfrom
feat/clear
May 7, 2026
Merged

feat(command): add /clear slash command#20
remarkablemark merged 9 commits into
masterfrom
feat/clear

Conversation

@remarkablemark
Copy link
Copy Markdown
Member

What is the motivation for this pull request?

Add a /clear command that fully resets the current chat session in the TUI without restarting the CLI, then fix the rendering regressions uncovered while wiring that flow.

What is the current behavior?

There is no in-app command to clear the active chat session. Resetting the UI can leave behind stale agent system state, duplicate cursor artifacts, missing header/footer content, lost terminal scrollback, and visible flicker while typing.

What is the new behavior?

The CLI now supports /clear to reset the chat session and TUI state in place. Clearing also restores the agent system message correctly, keeps the header and footer rendered, preserves terminal scrollback, removes the duplicate cursor issue, and smooths TUI updates by enabling incremental rendering and raising Ink's max FPS.

Checklist:

Implemented `/clear` as a slash command that resets the current chat
session and clears the terminal so the TUI redraws like a fresh launch.

The behavior is wired in `src/components/App.tsx`: `/clear` now calls
`screen.clear()`, closes any picker state, and increments a `sessionId`.

`src/components/Chat/Chat.tsx` listens for that `sessionId` change and
resets messages, loading, pending tool approval, and pending plan approval
back to a fresh session.
The duplicate cursor came from the `/clear` path resetting the terminal
directly with `\x1Bc`, which bypassed Ink’s own cursor/render management.

Changed `src/utils/screen.ts` to support a registered clear handler, and
`src/tui.tsx` now wires that handler to Ink’s `render(...).clear()` API.

That means `/clear` still wipes the visible session, but it does
it through Ink instead of hard-resetting the terminal underneath it.
Fixed the duplicate cursor that came from `/clear` path resetting the
terminal directly with `\x1Bc`, which bypassed Ink’s own cursor/render
management.

`src/tui.tsx` now uses Ink’s `render(...).clear()` API, which means
`/clear` wipes the visible session through Ink instead of hard-resetting
the terminal underneath it.

On startup, it does a one-time `process.stdout.write('\x1Bc')` in
`src/cli.ts` before Ink renders in an alternate screen. This allows
the app to open onto a truly fresh terminal and restore the original
terminal content when the app exits.
Enabled `incrementalRendering` in `src/tui.tsx` to try to stop the
occasional flickering because it changes how Ink redraws lines.
Bug: the explicit clear operation is what’s fighting
incremental rendering.

Fix: removed the in-app `screen.clear()` call from `/clear` in
`src/components/App.tsx`.

`/clear` now just resets the session state, which lets Ink
reconcile the frame normally under `incrementalRendering`
instead of wiping the output and leaving unchanged chrome
like the header behind.
The committed transcript no longer stores the hidden system message, the
active assistant response now lives in separate `streamingMessage` state
until it’s committed, and Ollama requests cache and prepend the system
prompt at call time. That removes the sentinel first message and avoids
rewriting the full transcript array for every streamed chunk.

Updated `src/components/Messages.tsx` so committed rows are memoized and
the live streaming row is rendered separately. That means unchanged history
doesn’t rerender on every token.

`src/components/Messages.test.tsx` was expanded for the streaming row path.
The flicker was coming from the renderer path, not from chat state
churn.

`Input.tsx` keeps typing local to `@inkjs/ui`’s `TextInput`, so the
whole chat transcript is not re-rendering on every keypress.

The actual hot path is `tui.tsx`, where Ink renders the terminal UI
and throttles frame updates.

TextInput redraws the line on each keystroke, including the inverse-video
cursor; when you type faster than the default render cadence, some
terminals show that as flicker/skipped repaint.

Raising `maxFps` does not change app behavior, just lets the TUI flush
input updates more smoothly.
@remarkablemark remarkablemark self-assigned this May 7, 2026
@remarkablemark remarkablemark added the enhancement New feature or request label May 7, 2026
@remarkablemark remarkablemark changed the title feat(command): add /clear command feat(command): add /clear command May 7, 2026
@remarkablemark remarkablemark changed the title feat(command): add /clear command feat(command): add /clear slash command May 7, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
src/cli.ts 100.00% <100.00%> (ø)
src/components/App.tsx 100.00% <100.00%> (ø)
src/components/Chat/Chat.tsx 100.00% <100.00%> (ø)
src/components/Messages.tsx 100.00% <100.00%> (ø)
src/constants/command.ts 100.00% <ø> (ø)
src/tui.tsx 100.00% <100.00%> (ø)
src/utils/agents.ts 100.00% <100.00%> (ø)
src/utils/screen.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@remarkablemark remarkablemark merged commit cc09441 into master May 7, 2026
15 checks passed
@remarkablemark remarkablemark deleted the feat/clear branch May 7, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant