Addresses 30+ issues found in a full review of the interactive TUI spanning
layout/visual, user flow, message rendering, and state management dimensions.
Critical (state/memory):
- Fix onBranchChange unsubscribe function being discarded; store and call in stop()
- Add onThemeChange cleanup in stop() to prevent stale callback retention
- Resolve getUserInput() Promise on shutdown so run() while-loop exits cleanly
- Serialize concurrent message_update event handlers via Promise chain to prevent
duplicate ToolExecutionComponent creation under rapid streaming
- Add cleanup of customFooter, customHeader, autocompleteProvider, and extension
widgets in stop() to prevent timer/watcher leaks
Major (UX/flow):
- Add two-step confirmation for provider auth removal (r key) — matches session
delete pattern; first press shows confirm hint, second press executes
- Normalize list navigation wrapping: oauth-selector and session-selector now
wrap at boundaries, consistent with all other selectors
- Ctrl+C in scoped-models-selector now always cancels modal immediately instead
of clearing search first
- Config-selector position indicator now counts only selectable items, excluding
non-selectable group headers from both numerator and denominator
- user-message-selector auto-dismiss replaced setTimeout(100) with
Promise.resolve().then() to eliminate 100ms flicker
- Add "Unknown command: /foo. Type /help for available commands." feedback for
unrecognized slash commands instead of silently submitting as chat
- Fix dead-end input path: submitPromptsDirectly=false now dispatches prompt
- Wrap session.prompt in isCompacting path with try/catch (was missing, other
path had it)
- Add Esc-to-close hint to provider-manager footer (was undocumented)
Rendering bugs:
- Remove identical dead-code else branch in assistant-message spacing logic
- Add 20-line truncation to generic/unknown tool JSON rendering (was unbounded)
- bash-execution updateDisplay() now uses stored _borderColorKey so
excludeFromContext dim styling is preserved on re-render
- Fix countdown-timer dispose race: _disposed flag prevents extra tick after
clearInterval
- extension-selector nextSelectable() guard prevents cursor landing on separator
- extension-input now rejects empty/whitespace-only submissions
- Normalize bordered-loader spacing: non-cancellable variant no longer adds
orphaned spacer before bottom border
Visual/theme:
- daxnuts.ts center() replaced naive ANSI regex with visibleWidth() from
@gsd/pi-tui for correct true-color sequence handling
- Remove incorrect mistral.ai URL from daxnuts component
- armin.ts now centers art using same visibleWidth approach as daxnuts
- Dark theme warning color: #ffff00 → #e6b800 (muted amber, less harsh)
- dynamic-border default color function wrapped in try/catch to guard against
undefined theme in jiti-loaded extension contexts
- Footer stats grouped with · separator; cache labels changed from R/W to cr:/cw:
- Replace raw \x1b[1m ANSI codes in custom-message, branch-summary-message,
compaction-summary-message, skill-invocation-message with theme.bold()
- welcome-screen visLen now uses strip-ansi instead of hand-rolled regex
Performance:
- diff.ts parseDiffLine regex: [+-\s] → [+\- ] (space only, not all whitespace)
- tab replacement width: 3 spaces → 4 spaces (standard) in both diff.ts and
tool-execution.ts
- chat-controller message_update: skip already-processed content blocks using
lastProcessedContentIndex to reduce O(n) scan per event
Vendor all 4 Pi packages (tui, ai, agent-core, coding-agent) from
pi-mono v0.57.1 as @gsd/* workspace packages under packages/. This
replaces the compiled npm dependency (@mariozechner/pi-coding-agent)
and patch-package workflow, giving direct source access for
modifications.
- Copy Pi source from pi-mono v0.57.1 into packages/
- Create workspace package.json + tsconfig.json for each package
- Rename ~240 imports from @mariozechner/pi-* to @gsd/pi-*
- Apply existing patches as source edits (setModel persist, VT input)
- Remove @mariozechner/pi-coding-agent dep and patch-package
- Update build pipeline to build packages in dependency order
- Add pi-upstream git remote for future selective syncing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>