fix(tui): tighten composer — status sits directly above input, overlays anchor to input

Three bugs rolled together, all in the composer area:

- StatusRule was measuring as 2 rows in Yoga due to a quirk with the
  complex nested <Text wrap="truncate-end"> content. Lock the outer box
  to height={1} so 'top' mode actually abuts the input instead of
  leaving a phantom blank row between them
- FloatingOverlays (slash completions, /model picker, /resume, /skills
  browser, pager) was anchored to the status box. In 'bottom' mode the
  status box moved away, so overlays vanished. Move the overlays into
  the input row (which is position:relative) so they always pop up
  above the input regardless of status position
- Drop the <Text> </Text> fallback in the sticky-prompt slot (only
  render a row when there's an actual sticky prompt to show) and
  collapse the now-unused Box column wrapping the input. Saves two
  rows of dead vertical space in the default layout
This commit is contained in:
Brooklyn Nicholson 2026-04-22 14:19:01 -05:00
parent ea32364c96
commit 408fc893e9
2 changed files with 14 additions and 18 deletions

View file

@ -187,7 +187,7 @@ export function StatusRule({
const leftWidth = Math.max(12, cols - cwdLabel.length - 3)
return (
<Box>
<Box flexShrink={0} height={1}>
<Box flexShrink={1} width={leftWidth}>
<Text color={t.color.bronze} wrap="truncate-end">
{'─ '}

View file

@ -173,31 +173,18 @@ const ComposerPane = memo(function ComposerPane({
</Text>
)}
{status.showStickyPrompt ? (
{status.showStickyPrompt && (
<Text color={ui.theme.color.dim} wrap="truncate-end">
<Text color={ui.theme.color.label}> </Text>
{status.stickyPrompt}
</Text>
) : (
<Text> </Text>
)}
<Box flexDirection="column" position="relative">
<StatusRulePane at="top" composer={composer} status={status} />
<FloatingOverlays
cols={composer.cols}
compIdx={composer.compIdx}
completions={composer.completions}
onModelSelect={actions.onModelSelect}
onPickerSelect={actions.resumeById}
pagerPageSize={composer.pagerPageSize}
/>
</Box>
<StatusRulePane at="top" composer={composer} status={status} />
{!isBlocked && (
<Box flexDirection="column" marginBottom={ui.statusBar === 'bottom' ? 0 : 1}>
<>
{composer.inputBuf.map((line, i) => (
<Box key={i}>
<Box width={3}>
@ -209,6 +196,15 @@ const ComposerPane = memo(function ComposerPane({
))}
<Box position="relative">
<FloatingOverlays
cols={composer.cols}
compIdx={composer.compIdx}
completions={composer.completions}
onModelSelect={actions.onModelSelect}
onPickerSelect={actions.resumeById}
pagerPageSize={composer.pagerPageSize}
/>
<Box width={pw}>
{sh ? (
<Text color={ui.theme.color.shellDollar}>$ </Text>
@ -234,7 +230,7 @@ const ComposerPane = memo(function ComposerPane({
</Box>
</Box>
</Box>
</Box>
</>
)}
{!composer.empty && !ui.sid && <Text color={ui.theme.color.dim}> {ui.status}</Text>}