feat: ensure feature parity once again

This commit is contained in:
Brooklyn Nicholson 2026-04-11 14:02:36 -05:00
parent bf6af95ff5
commit e2ea8934d4
6 changed files with 922 additions and 112 deletions

View file

@ -39,8 +39,12 @@ export const MessageLine = memo(function MessageLine({
return <Text color={t.color.dim}>{msg.text}</Text>
}
if (msg.role !== 'user' && hasAnsi(msg.text)) {
return <Text wrap="wrap">{msg.text}</Text>
}
if (msg.role === 'assistant') {
return hasAnsi(msg.text) ? <Text wrap="wrap">{msg.text}</Text> : <Md compact={compact} t={t} text={msg.text} />
return <Md compact={compact} t={t} text={msg.text} />
}
if (msg.role === 'user' && msg.text.length > LONG_MSG && isPasteBackedText(msg.text)) {
@ -63,7 +67,11 @@ export const MessageLine = memo(function MessageLine({
})()
return (
<Box flexDirection="column" marginTop={msg.role === 'user' || msg.kind === 'slash' ? 1 : 0}>
<Box
flexDirection="column"
marginBottom={msg.role === 'user' ? 1 : 0}
marginTop={msg.role === 'user' || msg.kind === 'slash' ? 1 : 0}
>
{msg.thinking && (
<Text color={t.color.dim} dimColor wrap="truncate-end">
💭 {msg.thinking.replace(/\n/g, ' ').slice(0, 200)}

View file

@ -25,6 +25,12 @@ const activityGlyph = (item: ActivityItem) => (item.tone === 'error' ? '✗' : i
const TreeFork = ({ last }: { last: boolean }) => <Text dimColor>{last ? '└─ ' : '├─ '}</Text>
const fmtElapsed = (ms: number) => {
const sec = Math.max(0, ms) / 1000
return sec < 10 ? `${sec.toFixed(1)}s` : `${Math.round(sec)}s`
}
export function Spinner({ color, variant = 'think' }: { color: string; variant?: 'think' | 'tool' }) {
const [spin] = useState(() => {
const raw = spinners[pick(variant === 'tool' ? TOOL : THINK)]
@ -48,16 +54,26 @@ export const ToolTrail = memo(function ToolTrail({
tools = [],
trail = [],
activity = [],
animateCot = false,
padAfter = false
animateCot = false
}: {
t: Theme
tools?: ActiveTool[]
trail?: string[]
activity?: ActivityItem[]
animateCot?: boolean
padAfter?: boolean
}) {
const [now, setNow] = useState(() => Date.now())
useEffect(() => {
if (!tools.length) {
return
}
const id = setInterval(() => setNow(Date.now()), 200)
return () => clearInterval(id)
}, [tools.length])
if (!trail.length && !tools.length && !activity.length) {
return null
}
@ -70,7 +86,6 @@ export const ToolTrail = memo(function ToolTrail({
<>
{trail.map((line, i) => {
const lastInBlock = i === rowCount - 1
const suffix = padAfter && lastInBlock ? '\n' : ''
if (isToolTrailResultLine(line)) {
return (
@ -81,7 +96,6 @@ export const ToolTrail = memo(function ToolTrail({
>
<TreeFork last={lastInBlock} />
{line}
{suffix}
</Text>
)
}
@ -91,7 +105,6 @@ export const ToolTrail = memo(function ToolTrail({
<Text color={t.color.dim} key={`c-${i}`}>
<TreeFork last={lastInBlock} />
<Spinner color={t.color.amber} variant="think" /> {line}
{suffix}
</Text>
)
}
@ -100,34 +113,30 @@ export const ToolTrail = memo(function ToolTrail({
<Text color={t.color.dim} dimColor key={`c-${i}`}>
<TreeFork last={lastInBlock} />
{line}
{suffix}
</Text>
)
})}
{tools.map((tool, j) => {
const lastInBlock = trail.length + j === rowCount - 1
const suffix = padAfter && lastInBlock ? '\n' : ''
return (
<Text color={t.color.dim} key={tool.id}>
<TreeFork last={lastInBlock} />
<Spinner color={t.color.amber} variant="tool" /> {TOOL_VERBS[tool.name] ?? tool.name}
{tool.context ? `: ${tool.context}` : ''}
{suffix}
{tool.startedAt ? ` (${fmtElapsed(now - tool.startedAt)})` : ''}
</Text>
)
})}
{act.map((item, k) => {
const lastInBlock = trail.length + tools.length + k === rowCount - 1
const suffix = padAfter && lastInBlock ? '\n' : ''
return (
<Text color={tone(item, t)} dimColor={item.tone === 'info'} key={`a-${item.id}`}>
<TreeFork last={lastInBlock} />
{activityGlyph(item)} {item.text}
{suffix}
</Text>
)
})}