fix(tui): show background shell completion (#36534)

This commit is contained in:
Kit Langton 2026-07-12 21:01:36 -04:00 committed by GitHub
commit c0ed0106b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 54 additions and 8 deletions

View file

@ -1231,21 +1231,27 @@ function SessionSwitchMessageV2(props: { message: SessionMessageInfo }) {
}
function SessionNoticeMessageV2(props: { message: SessionMessageInfo }) {
const ctx = use()
const { theme } = useTheme()
const metadata = () => (props.message.type === "synthetic" ? props.message.metadata : undefined)
const completion = () => metadata()?.source === "subagent"
const source = () => stringValue(metadata()?.source)
const completion = () => source() === "subagent" || source() === "shell"
const state = () => stringValue(metadata()?.state)
const agent = () => Locale.titlecase(stringValue(metadata()?.agent) ?? "Subagent")
const actor = () => (source() === "shell" ? "Shell" : Locale.titlecase(stringValue(metadata()?.agent) ?? "Subagent"))
const text = () => {
if (props.message.type === "system") return props.message.text
if (props.message.type === "synthetic") return props.message.description ?? ""
return ""
}
const description = () => (source() === "shell" ? text().replace(/\s+/g, " ").trim() : text())
const status = () => {
if (state() === "completed") return "finished"
if (state() === "error") return "failed"
return state() ?? "finished"
}
const heading = () => `${state() === "completed" ? "↳" : "!"} ${actor()} ${status()}`
const suffix = () =>
Locale.truncateWidth(` · ${description()}`, Math.max(0, ctx.width - 3 - Bun.stringWidth(heading())))
const color = () => {
if (state() === "error") return theme.error
if (state() === "cancelled") return theme.warning
@ -1261,11 +1267,9 @@ function SessionNoticeMessageV2(props: { message: SessionMessageInfo }) {
}
>
<box marginLeft={3}>
<text>
<span style={{ fg: color() }}>
{state() === "completed" ? "↳" : "!"} {agent()} {status()}
</span>
<span style={{ fg: theme.textMuted }}> · {text()}</span>
<text wrapMode="none">
<span style={{ fg: color() }}>{heading()}</span>
<span style={{ fg: theme.textMuted }}>{suffix()}</span>
</text>
</box>
</Show>

View file

@ -63,6 +63,24 @@ export function truncate(str: string, len: number): string {
return str.slice(0, len - 1) + "…"
}
const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" })
export function truncateWidth(str: string, width: number): string {
if (width <= 0) return ""
if (Bun.stringWidth(str) <= width) return str
if (width === 1) return "…"
const result: string[] = []
let used = 0
for (const item of graphemeSegmenter.segment(str)) {
const next = Bun.stringWidth(item.segment)
if (used + next > width - 1) break
result.push(item.segment)
used += next
}
return result.join("") + "…"
}
export function truncateLeft(str: string, len: number): string {
if (str.length <= len) return str
return "…" + str.slice(-(len - 1))