chore: uptick

This commit is contained in:
Brooklyn Nicholson 2026-04-06 18:40:21 -05:00
parent afd670a36f
commit 39878aff00
3 changed files with 72 additions and 49 deletions

View file

@ -185,29 +185,38 @@ export function App({ gw }: { gw: GatewayClient }) {
const sys = useCallback((text: string) => setMessages(prev => [...prev, { role: 'system' as const, text }]), []) const sys = useCallback((text: string) => setMessages(prev => [...prev, { role: 'system' as const, text }]), [])
const rpc = (method: string, params: Record<string, unknown> = {}) => const colsRef = useRef(cols)
gw.request(method, params).catch((e: Error) => { colsRef.current = cols
sys(`error: ${e.message}`)
})
const newSession = (msg?: string) => const rpc = useCallback(
rpc('session.create', { cols }).then((r: any) => { (method: string, params: Record<string, unknown> = {}) =>
if (!r) { gw.request(method, params).catch((e: Error) => {
return sys(`error: ${e.message}`)
} }),
[gw, sys]
)
setSid(r.session_id) const newSession = useCallback(
setMessages([]) (msg?: string) =>
setUsage(ZERO) rpc('session.create', { cols: colsRef.current }).then((r: any) => {
setStatus('ready') if (!r) {
lastStatusNoteRef.current = '' return
protocolWarnedRef.current = false }
stderrWarnedRef.current = false
if (msg) { setSid(r.session_id)
sys(msg) setMessages([])
} setUsage(ZERO)
}) setStatus('ready')
lastStatusNoteRef.current = ''
protocolWarnedRef.current = false
stderrWarnedRef.current = false
if (msg) {
sys(msg)
}
}),
[rpc, sys]
)
const idle = () => { const idle = () => {
setThinking(false) setThinking(false)

View file

@ -1,4 +1,5 @@
import { Box, Text } from 'ink' import { Box, Text } from 'ink'
import { memo } from 'react'
import { LONG_MSG, ROLE } from '../constants.js' import { LONG_MSG, ROLE } from '../constants.js'
import { hasAnsi, userDisplay } from '../lib/text.js' import { hasAnsi, userDisplay } from '../lib/text.js'
@ -7,7 +8,7 @@ import type { Msg } from '../types.js'
import { Md } from './markdown.js' import { Md } from './markdown.js'
export function MessageLine({ compact, msg, t }: { compact?: boolean; msg: Msg; t: Theme }) { export const MessageLine = memo(function MessageLine({ compact, msg, t }: { compact?: boolean; msg: Msg; t: Theme }) {
const { body, glyph, prefix } = ROLE[msg.role](t) const { body, glyph, prefix } = ROLE[msg.role](t)
const content = (() => { const content = (() => {
@ -47,4 +48,4 @@ export function MessageLine({ compact, msg, t }: { compact?: boolean; msg: Msg;
{content} {content}
</Box> </Box>
) )
} })

View file

@ -1,12 +1,26 @@
import { Box, Text } from 'ink' import { Text } from 'ink'
import { useEffect, useState } from 'react' import { memo, useEffect, useRef, useState } from 'react'
import { FACES, SPINNER, TOOL_VERBS, VERBS } from '../constants.js' import { FACES, SPINNER, TOOL_VERBS, VERBS } from '../constants.js'
import { pick } from '../lib/text.js' import { pick } from '../lib/text.js'
import type { Theme } from '../theme.js' import type { Theme } from '../theme.js'
import type { ActiveTool } from '../types.js' import type { ActiveTool } from '../types.js'
export function Thinking({ function SpinnerChar({ color }: { color: string }) {
const ref = useRef(0)
useEffect(() => {
const id = setInterval(() => {
ref.current = (ref.current + 1) % SPINNER.length
}, 80)
return () => clearInterval(id)
}, [])
return <Text color={color}>{SPINNER[ref.current]}</Text>
}
export const Thinking = memo(function Thinking({
reasoning, reasoning,
t, t,
thinking, thinking,
@ -17,35 +31,34 @@ export function Thinking({
thinking?: string thinking?: string
tools: ActiveTool[] tools: ActiveTool[]
}) { }) {
const [frame, setFrame] = useState(0)
const [verb] = useState(() => pick(VERBS)) const [verb] = useState(() => pick(VERBS))
const [face] = useState(() => pick(FACES)) const [face] = useState(() => pick(FACES))
useEffect(() => {
const id = setInterval(() => setFrame(f => (f + 1) % SPINNER.length), 80)
return () => clearInterval(id)
}, [])
const tail = (reasoning || thinking || '').slice(-120).replace(/\n/g, ' ') const tail = (reasoning || thinking || '').slice(-120).replace(/\n/g, ' ')
return ( if (tools.length) {
<Box flexDirection="column"> return (
{tools.length ? ( <>
tools.map(tool => ( {tools.map(tool => (
<Text color={t.color.dim} key={tool.id}> <Text color={t.color.dim} key={tool.id}>
{SPINNER[frame]} {TOOL_VERBS[tool.name] ?? '⚡ ' + tool.name} {TOOL_VERBS[tool.name] ?? tool.name}
</Text> </Text>
)) ))}
) : tail ? ( </>
<Text color={t.color.dim} dimColor wrap="truncate-end"> )
{SPINNER[frame]} 💭 {tail} }
</Text>
) : ( if (tail) {
<Text color={t.color.dim}> return (
{SPINNER[frame]} {face} {verb} <Text color={t.color.dim} dimColor wrap="truncate-end">
</Text> 💭 {tail}
)} </Text>
</Box> )
}
return (
<Text color={t.color.dim}>
<SpinnerChar color={t.color.dim} /> {face} {verb}
</Text>
) )
} })