@@ -896,28 +896,40 @@ proc liveLabel*(base: string, slurped: int): string =
896896 parts.join (" " )
897897
898898proc paintInitialPrompt * (p: Profile ) =
899- # # Welcome-time paint when starting fresh. The first prompt is intentionally
900- # # prompt-only; the token bar appears after the first response has real usage
901- # # to display.
899+ # # Welcome-time paint when starting fresh: gap row + token bar at zero
900+ # # usage + idle prompt, the same typing-ready shape `endTurn` and the
901+ # # resume path leave behind. The bar always shows the context percentage
902+ # # (design contract), so it is primed at `○0%` rather than hidden until
903+ # # the first response; `pendingHint` is primed with zeroed usage so the
904+ # # first user submit converts the bar into a receipt row exactly like
905+ # # every later turn.
902906 # #
903- # # Leaves `currentBarLabel = ""` and `currentBarHasGap = false` —
904- # # the signals `readInput`, `emitUserSubmit`, and the slash-command
905- # # repaint use to detect prompt-only mode. Paints through the engine's
906- # # frame model when the live editor is anchored so `paintedFooterRows`
907- # # tracks the prompt row; the pre-input-thread path (no editor yet)
908- # # falls back to a raw paint, cleared later by the walk-up's erase.
909- discard p
910- emitFatPromptEvent clearBarEvent ()
907+ # # Paints through the engine's frame model when the live editor is
908+ # # anchored so `paintedFooterRows` tracks the chrome; the
909+ # # pre-input-thread path (no editor yet) falls back to a raw paint,
910+ # # cleared later by the walk-up's erase.
911+ let window = contextWindowFor (p)
912+ emitFatPromptEvent setBarEvent (contextLabel (0 , window),
913+ hasGap = true )
914+ emitFatPromptEvent setPendingHintEvent (Usage (), window, - 1 )
915+ # The gap row between the welcome's last line and the bar: the same
916+ # blank row `endTurn` and the resume path leave above the bar. Without
917+ # it the bar paints flush against the hint line, and the first
918+ # keystroke's walk-up (sized from paintedFooterRows) erases the hint
919+ # instead of the gap.
920+ termengine.syncWrite (" \r\n " )
911921 if liveEditorFooterAnchored ():
912922 termengine.renderFooter (footerFrame (fatPromptState),
913923 inputThreadRunning, inputEditor,
914924 currentTermW ())
915925 else :
916- # Raw gap + prompt. Register the reserved gap row so the first later
917- # walk-up (spinner/bar paint, submit erase) does not under-count and
918- # overwrite the line above the prompt.
919- termengine.writeRaw (" \n\x1b [?25l" & promptOnlyResetBytes ())
920- termengine.noteFooterPainted (1 )
926+ # Raw gap + bar + prompt. Register the reserved rows so the first
927+ # later walk-up (spinner/bar paint, submit erase) does not under-count
928+ # and overwrite the line above the prompt.
929+ termengine.syncWrite (hideRealCaretBytes () &
930+ barPromptStartupBytes (fatPromptState.footer.barLabel, currentTermW ()))
931+ termengine.noteFooterPainted (
932+ footerRowsAboveEditor (fatPromptState, currentTermW ()))
921933
922934proc paintResumedBarPrompt * (label: string ) =
923935 # # Startup paint for --resume with prior usage: bar + idle prompt in the
0 commit comments