Skip to content

Commit e43beca

Browse files
committed
fix(ui): drop both status rows together, and teach the setup agent Windows
- The built-in session bar now respects the same fullscreen height limit as the custom statusLine row, so it stops keeping the flexShrink:0 row the footer just gave back to the ScrollBox; the threshold moves next to the resolver in statusLineDisplay.ts so the two rows cannot drift apart again - The statusline-setup agent no longer hunts for ~/.zshrc and PS1 on Windows, where neither exists, and is told the command always runs through bash (Git Bash on Windows) and that jq is usually absent while node is not
1 parent b12d053 commit e43beca

5 files changed

Lines changed: 68 additions & 5 deletions

File tree

src/components/PromptInput/PromptInputFooter.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { isFullscreenEnvEnabled } from '../../utils/fullscreen.js';
2020
import { isUndercover } from '../../utils/undercover.js';
2121
import { CoordinatorTaskPanel, useCoordinatorTaskCount } from '../CoordinatorAgentStatus.js';
2222
import { getLastAssistantMessageId, StatusLine, statusLineShouldDisplay } from '../StatusLine.js';
23+
import { statusRowFits } from '../statusLineDisplay.js';
2324
import { Notifications } from './Notifications.js';
2425
import { PromptInputFooterLeftSide } from './PromptInputFooterLeftSide.js';
2526
import { PromptInputFooterSuggestions, type SuggestionItem } from './PromptInputFooterSuggestions.js';
@@ -104,11 +105,11 @@ function PromptInputFooter({
104105
messagesRef.current = messages;
105106
const lastAssistantMessageId = useMemo(() => getLastAssistantMessageId(messages), [messages]);
106107
const isNarrow = columns < 80;
107-
// In fullscreen the bottom slot is flexShrink:0, so every row here is a row
108-
// stolen from the ScrollBox. Drop the optional StatusLine first. Non-fullscreen
109-
// has terminal scrollback to absorb overflow, so we never hide StatusLine there.
108+
// Below a certain height fullscreen cannot spare a row for either status
109+
// row — see statusRowFits in statusLineDisplay.ts for why, and so that this
110+
// row and the built-in session bar always drop together.
110111
const isFullscreen = isFullscreenEnvEnabled();
111-
const isShort = isFullscreen && rows < 24;
112+
const isShort = !statusRowFits(isFullscreen, rows);
112113

113114
// Pill highlights when tasks is the active footer item AND no specific
114115
// agent row is selected. When coordinatorTaskIndex >= 0 the pointer has

src/components/PromptInput/PromptInputStatusBar.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import * as React from 'react'
22
import { Box, Text } from 'src/ink.js'
33
import { getSdkBetas } from '../../bootstrap/state.js'
44
import { useSettings } from '../../hooks/useSettings.js'
5+
import { useTerminalSize } from '../../hooks/useTerminalSize.js'
6+
import { isFullscreenEnvEnabled } from '../../utils/fullscreen.js'
7+
import { statusRowFits } from '../statusLineDisplay.js'
58
import { sessionStatusBarShouldDisplay } from '../StatusLine.js'
69
import { useMainLoopModel } from '../../hooks/useMainLoopModel.js'
710
import { analyzeContext } from '../../utils/contextAnalysis.js'
@@ -30,7 +33,10 @@ export function PromptInputStatusBar({
3033
// Hidden when the user runs a custom statusLine command instead, or turns
3134
// the bar off with sessionStatusBar: false. See statusLineDisplay.ts.
3235
const settings = useSettings()
33-
const visible = sessionStatusBarShouldDisplay(settings)
36+
const { rows } = useTerminalSize()
37+
const visible =
38+
sessionStatusBarShouldDisplay(settings) &&
39+
statusRowFits(isFullscreenEnvEnabled(), rows)
3440
const mainLoopModel = useMainLoopModel()
3541
const provider = getAPIProvider()
3642
const contextWindow = getContextWindowForModel(mainLoopModel, getSdkBetas())

src/components/statusLineDisplay.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
*/
66

77
import {
8+
MIN_FULLSCREEN_ROWS_FOR_STATUS,
89
resolveStatusLineDisplay,
910
type StatusLineDisplayInput,
11+
statusRowFits,
1012
} from './statusLineDisplay.js'
1113

1214
let passed = 0
@@ -125,6 +127,29 @@ test('assistant mode hides both rows whatever is configured', () => {
125127
}
126128
})
127129

130+
test('a short fullscreen terminal has no room for a status row', () => {
131+
assert(
132+
!statusRowFits(true, MIN_FULLSCREEN_ROWS_FOR_STATUS - 1),
133+
'one row below the threshold should not fit',
134+
)
135+
assert(
136+
statusRowFits(true, MIN_FULLSCREEN_ROWS_FOR_STATUS),
137+
'the threshold itself should fit',
138+
)
139+
assert(statusRowFits(true, 80), 'a tall fullscreen terminal should fit')
140+
})
141+
142+
test('outside fullscreen a status row always fits', () => {
143+
// Non-fullscreen has terminal scrollback to absorb overflow, so height
144+
// never hides a row there - however short the terminal gets.
145+
for (const rows of [0, 1, 5, 23, 200]) {
146+
assert(
147+
statusRowFits(false, rows),
148+
'rows=' + rows + ' should still fit outside fullscreen',
149+
)
150+
}
151+
})
152+
128153
test('the two rows never both vanish unless asked', () => {
129154
// Guards the regression the gate could introduce: a user who configured a
130155
// custom line must never end up with no status row by accident.

src/components/statusLineDisplay.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@
1313
* mode, workspace trust, hook policy) is resolved by the callers.
1414
*/
1515

16+
/**
17+
* Terminal height below which fullscreen cannot spare a status row.
18+
* Matches the historical threshold in PromptInputFooter.
19+
*/
20+
export const MIN_FULLSCREEN_ROWS_FOR_STATUS = 24
21+
22+
/**
23+
* Does the terminal have room for a status row?
24+
*
25+
* Fullscreen pins the prompt into a flexShrink:0 bottom slot (BottomSlot in
26+
* FullscreenLayout.tsx), so under that height every optional row is one taken
27+
* from the ScrollBox. Both rows answer to this, so they drop together instead
28+
* of one quietly keeping the row the other just gave up. Outside fullscreen
29+
* the terminal has scrollback to absorb overflow and nothing is hidden.
30+
*/
31+
export function statusRowFits(isFullscreen: boolean, rows: number): boolean {
32+
return !isFullscreen || rows >= MIN_FULLSCREEN_ROWS_FOR_STATUS
33+
}
34+
1635
export type StatusLineDisplayInput = {
1736
/**
1837
* A `statusLine` command is present in the settings that apply to this

src/tools/AgentTool/built-in/statuslineSetup.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ import type { BuiltInAgentDefinition } from '../loadAgentsDir.js'
22

33
const STATUSLINE_SYSTEM_PROMPT = `You are a status line setup agent for Tau. Your job is to create or update the statusLine command in the user's Tau settings.
44
5+
Before anything else, know two things about the environment:
6+
7+
- The command you write is always run through bash. Hooks default to
8+
DEFAULT_HOOK_SHELL = 'bash' and statusLine has no "shell" field to override
9+
it, so on Windows it runs in Git Bash. Write bash, never PowerShell or cmd.
10+
- Do not assume jq is installed. It usually is not on Windows. node is always
11+
available, so prefer it for reading the JSON input.
12+
13+
On Windows there is no PS1 - PowerShell uses a prompt function and none of the
14+
files in step 1 exist. Do not read them. Say so and ask the user how they want
15+
the row formatted, or work from the description they already gave you.
16+
517
When asked to convert the user's shell PS1 configuration, follow these steps:
618
1. Read the user's shell configuration files in this order of preference:
719
- ~/.zshrc

0 commit comments

Comments
 (0)