fix(tui): polish /status diagnostics card
This commit is contained in:
@@ -104,7 +104,7 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
|||||||
// Gating /status on it keeps the assertion race-free; the diagnostics
|
// Gating /status on it keeps the assertion race-free; the diagnostics
|
||||||
// card is then exercised through the same real Loader/PTY composition.
|
// card is then exercised through the same real Loader/PTY composition.
|
||||||
{ waitFor: 'scripted session title — DeepSeek Harness', send: '/status\r' },
|
{ waitFor: 'scripted session title — DeepSeek Harness', send: '/status\r' },
|
||||||
{ waitFor: 'Session diagnostics', send: '/exit\r' },
|
{ waitFor: 'Session status', send: '/exit\r' },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
expect(output).toContain('I need one decision before I continue.')
|
expect(output).toContain('I need one decision before I continue.')
|
||||||
@@ -116,12 +116,12 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
|||||||
expect(output).not.toContain('\u009B31mMODEL_C1')
|
expect(output).not.toContain('\u009B31mMODEL_C1')
|
||||||
expect(output).toContain('Safe')
|
expect(output).toContain('Safe')
|
||||||
expect(output).toContain('\u001B]0;scripted session title — DeepSeek Harness\u0007')
|
expect(output).toContain('\u001B]0;scripted session title — DeepSeek Harness\u0007')
|
||||||
expect(output).toContain('Session diagnostics')
|
expect(output).toContain('Session status')
|
||||||
expect(output).toContain('Title')
|
expect(output).toContain('Title')
|
||||||
expect(output).toContain('scripted session title')
|
expect(output).toContain('scripted session title')
|
||||||
expect(output).toContain('Model')
|
expect(output).toContain('Model')
|
||||||
expect(output).toContain('tui-scripted/tui-scripted-model-pro')
|
expect(output).toContain('tui-scripted/tui-scripted-model-pro')
|
||||||
expect(output).toContain('KV cache hit')
|
expect(output).toContain('KV cache')
|
||||||
expect(output).toContain('Context')
|
expect(output).toContain('Context')
|
||||||
expect(output).toContain('128,000')
|
expect(output).toContain('128,000')
|
||||||
expect(output).toContain('\u001B[?2004l')
|
expect(output).toContain('\u001B[?2004l')
|
||||||
|
|||||||
+102
-29
@@ -945,7 +945,70 @@ function formatDiagnosticNumber(value: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatDiagnosticTime(value: number): string {
|
function formatDiagnosticTime(value: number): string {
|
||||||
return new Date(value).toISOString()
|
return new Date(value).toISOString().replace('T', ' ').replace(/\.\d{3}Z$/u, ' UTC')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDiagnosticCount(value: number, singular: string): string {
|
||||||
|
return `${String(value)} ${singular}${value === 1 ? '' : 's'}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function diagnosticMeter(percent: number, palette: Palette): string {
|
||||||
|
const width = 16
|
||||||
|
const filled = Math.round(Math.min(100, Math.max(0, percent)) / 100 * width)
|
||||||
|
return `${palette.dim('[')}${palette.accent('█'.repeat(filled))}${palette.dim(`${'░'.repeat(width - filled)}]`)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatusCardRow = readonly [label: string, value: string]
|
||||||
|
|
||||||
|
/** Bordered, grouped field card for one point-in-time status snapshot. */
|
||||||
|
class StatusCardComponent implements Component {
|
||||||
|
constructor(
|
||||||
|
private readonly groups: readonly (readonly StatusCardRow[])[],
|
||||||
|
private readonly palette: Palette,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
invalidate(): void {}
|
||||||
|
|
||||||
|
render(width: number): string[] {
|
||||||
|
const labels = this.groups.flatMap(group => group.map(([label]) => `${label}:`))
|
||||||
|
const naturalLabelWidth = Math.max(...labels.map(label => label.length))
|
||||||
|
const naturalBodyWidth = Math.max(...this.groups.flatMap(group => group.map(([, value]) =>
|
||||||
|
1 + naturalLabelWidth + 2 + visibleWidth(value))))
|
||||||
|
const cardWidth = Math.min(
|
||||||
|
Math.max(8, width),
|
||||||
|
Math.max('Session status'.length + 5, naturalBodyWidth + 4),
|
||||||
|
)
|
||||||
|
const innerWidth = Math.max(1, cardWidth - 4)
|
||||||
|
const labelWidth = Math.min(
|
||||||
|
naturalLabelWidth,
|
||||||
|
Math.max(1, Math.floor(innerWidth / 3)),
|
||||||
|
)
|
||||||
|
const body: string[] = []
|
||||||
|
for (const [groupIndex, group] of this.groups.entries()) {
|
||||||
|
if (groupIndex > 0) body.push('')
|
||||||
|
for (const [label, value] of group) {
|
||||||
|
const plainLabel = truncateToWidth(`${label}:`, labelWidth, '')
|
||||||
|
const prefix = ` ${this.palette.muted(plainLabel.padEnd(labelWidth))} `
|
||||||
|
const continuation = ' '.repeat(1 + labelWidth + 2)
|
||||||
|
const valueWidth = Math.max(1, innerWidth - visibleWidth(prefix))
|
||||||
|
const wrapped = wrapTextWithAnsi(value, valueWidth)
|
||||||
|
for (const [lineIndex, line] of wrapped.entries()) {
|
||||||
|
body.push(`${lineIndex === 0 ? prefix : continuation}${line}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = truncateToWidth('Session status', Math.max(1, cardWidth - 5), '')
|
||||||
|
const topTail = '─'.repeat(Math.max(0, cardWidth - visibleWidth(title) - 5))
|
||||||
|
const top = `${this.palette.dim('╭─ ')}${this.palette.bold(this.palette.accent(title))}${this.palette.dim(` ${topTail}╮`)}`
|
||||||
|
const lines = [top]
|
||||||
|
for (const line of body) {
|
||||||
|
const clipped = truncateToWidth(line, innerWidth, '')
|
||||||
|
lines.push(`${this.palette.dim('│')} ${clipped}${' '.repeat(Math.max(0, innerWidth - visibleWidth(clipped)))} ${this.palette.dim('│')}`)
|
||||||
|
}
|
||||||
|
lines.push(this.palette.dim(`╰${'─'.repeat(Math.max(0, cardWidth - 2))}╯`))
|
||||||
|
return lines
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FooterComponent implements Component {
|
class FooterComponent implements Component {
|
||||||
@@ -1965,35 +2028,45 @@ export function createTuiChat(
|
|||||||
const events = agent.session.events
|
const events = agent.session.events
|
||||||
const latestActivity = events.at(-1)?.time ?? agent.session.header.createdAt
|
const latestActivity = events.at(-1)?.time ?? agent.session.header.createdAt
|
||||||
const usedContext = Math.max(0, Math.round(ctx.tokenMeter.measure(agent.session).totalTokens))
|
const usedContext = Math.max(0, Math.round(ctx.tokenMeter.measure(agent.session).totalTokens))
|
||||||
const context = contextWindow === undefined
|
let context = `${formatDiagnosticNumber(usedContext)} used · capacity unknown`
|
||||||
? `${formatDiagnosticNumber(usedContext)} used · capacity unknown`
|
if (contextWindow !== undefined) {
|
||||||
: `${formatDiagnosticNumber(usedContext)} / ${formatDiagnosticNumber(contextWindow)} (${String(Math.round(usedContext / contextWindow * 100))}%)`
|
const contextPercent = Math.round(usedContext / contextWindow * 100)
|
||||||
|
context = `${diagnosticMeter(contextPercent, palette)} ${String(contextPercent)}% used (${formatDiagnosticNumber(usedContext)} / ${formatDiagnosticNumber(contextWindow)})`
|
||||||
|
}
|
||||||
const rate = cacheHitRate(tokens)
|
const rate = cacheHitRate(tokens)
|
||||||
const rows = [
|
const turns = events.filter(event => event.type === 'turn/start').length
|
||||||
['Session', agent.session.id],
|
const steps = events.filter(event => event.type === 'step/start').length
|
||||||
['Title', sessionTitle ?? 'untitled'],
|
const toolCalls = events.filter(event => event.type === 'tool/call').length
|
||||||
['Working dir', cwd],
|
const model = target.current === undefined ? 'unset' : displayText(targetLabel(target.current))
|
||||||
['Model', target.current === undefined ? 'unset' : targetLabel(target.current)],
|
const groups: readonly (readonly StatusCardRow[])[] = [
|
||||||
['Reasoning view', showReasoning ? 'shown' : 'hidden'],
|
[
|
||||||
['Agent', agent.status],
|
['Session', displayText(agent.session.id)],
|
||||||
['Activity', [
|
['Title', displayText(sessionTitle ?? 'untitled')],
|
||||||
`events ${String(events.length)}`,
|
['Directory', displayText(cwd)],
|
||||||
`turns ${String(events.filter(event => event.type === 'turn/start').length)}`,
|
['Model', `${model} ${palette.dim(`(reasoning ${showReasoning ? 'shown' : 'hidden'})`)}`],
|
||||||
`steps ${String(events.filter(event => event.type === 'step/start').length)}`,
|
],
|
||||||
`tool calls ${String(events.filter(event => event.type === 'tool/call').length)}`,
|
[
|
||||||
].join(' · ')],
|
['Agent', [
|
||||||
['Tokens', `input ${formatDiagnosticNumber(tokens.input)} · output ${formatDiagnosticNumber(tokens.output)}`],
|
agent.status,
|
||||||
['Cache tokens', `read ${formatDiagnosticNumber(tokens.cacheRead)} · write ${formatDiagnosticNumber(tokens.cacheWrite)}`],
|
formatDiagnosticCount(events.length, 'event'),
|
||||||
['KV cache hit', rate === undefined ? 'n/a' : `${String(rate)}%`],
|
formatDiagnosticCount(turns, 'turn'),
|
||||||
['Context', context],
|
formatDiagnosticCount(steps, 'step'),
|
||||||
['Created', formatDiagnosticTime(agent.session.header.createdAt)],
|
formatDiagnosticCount(toolCalls, 'tool call'),
|
||||||
['Last active', formatDiagnosticTime(latestActivity)],
|
].join(' · ')],
|
||||||
] as const
|
],
|
||||||
const labelWidth = Math.max(...rows.map(([label]) => label.length))
|
[
|
||||||
const card = new GutterBox(text => palette.accent(text), 0)
|
['Tokens', `${formatDiagnosticNumber(tokens.input)} input + ${formatDiagnosticNumber(tokens.output)} output`],
|
||||||
card.addChild(new Text(palette.bold(palette.accent('Session diagnostics')), 0, 0))
|
['KV cache', rate === undefined
|
||||||
card.addChild(new Text(rows.map(([label, value]) =>
|
? `n/a (${formatDiagnosticNumber(tokens.cacheRead)} read + ${formatDiagnosticNumber(tokens.cacheWrite)} write)`
|
||||||
`${palette.muted(label.padEnd(labelWidth))} ${displayText(value)}`).join('\n'), 0, 0))
|
: `${diagnosticMeter(rate, palette)} ${String(rate)}% hit (${formatDiagnosticNumber(tokens.cacheRead)} read + ${formatDiagnosticNumber(tokens.cacheWrite)} write)`],
|
||||||
|
['Context', context],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
['Created', formatDiagnosticTime(agent.session.header.createdAt)],
|
||||||
|
['Active', formatDiagnosticTime(latestActivity)],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
const card = new StatusCardComponent(groups, palette)
|
||||||
chat.addChild(new Spacer(1))
|
chat.addChild(new Spacer(1))
|
||||||
chat.addChild(card)
|
chat.addChild(card)
|
||||||
requestRender()
|
requestRender()
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
terminal 56x36 buffer=normal length=36 base=0 viewport=0
|
||||||
|
lifecycle started=1 stopped=0 progress=inactive
|
||||||
|
title "Inspect session diagnostics — DSH snapshot"
|
||||||
|
cursor hidden column=1 viewportRow=32 bufferRow=32
|
||||||
|
buffer
|
||||||
|
0| " DEEPSEEK HARNESS"
|
||||||
|
style 1-8 fg=bright-blue bold
|
||||||
|
style 10-16 bold
|
||||||
|
1| " Inspect session diagnostics"
|
||||||
|
style 1-27 fg=bright-black
|
||||||
|
2| " deepseek-v4-pro • main-session"
|
||||||
|
style 1-32 dim
|
||||||
|
3| <blank>
|
||||||
|
4| "▌ "
|
||||||
|
style 0-0 fg=bright-blue
|
||||||
|
5| "▌ You "
|
||||||
|
style 0-0 fg=bright-blue
|
||||||
|
style 2-4 fg=bright-blue bold
|
||||||
|
6| "▌ inspect this session "
|
||||||
|
style 0-0 fg=bright-blue
|
||||||
|
7| "▌ "
|
||||||
|
style 0-0 fg=bright-blue
|
||||||
|
8| <blank>
|
||||||
|
9| " Assistant "
|
||||||
|
style 1-9 fg=bright-magenta bold
|
||||||
|
10| " Session inspected. "
|
||||||
|
11| <blank>
|
||||||
|
12| "╭─ Session status ─────────────────────────────────────╮"
|
||||||
|
style 0-2 dim
|
||||||
|
style 3-16 fg=bright-blue bold
|
||||||
|
style 17-55 dim
|
||||||
|
13| "│ Session: main-session │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
14| "│ Title: Inspect session diagnostics │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
15| "│ Directory: /workspace/project │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
16| "│ Model: deepseek/deepseek-v4-pro (reasoning │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 40-55 dim
|
||||||
|
17| "│ shown) │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 15-20 dim
|
||||||
|
style 55-55 dim
|
||||||
|
18| "│ │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
19| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
20| "│ tool call │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
21| "│ │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
22| "│ Tokens: 1,250 input + 340 output │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
23| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 15-15 dim
|
||||||
|
style 16-26 fg=bright-blue
|
||||||
|
style 27-32 dim
|
||||||
|
style 55-55 dim
|
||||||
|
24| "│ + 250 write) │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
25| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 15-15 dim
|
||||||
|
style 16-20 fg=bright-blue
|
||||||
|
style 21-32 dim
|
||||||
|
style 55-55 dim
|
||||||
|
26| "│ 128,000) │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
27| "│ │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 55-55 dim
|
||||||
|
28| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
29| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 55-55 dim
|
||||||
|
30| "╰──────────────────────────────────────────────────────╯"
|
||||||
|
style 0-55 dim
|
||||||
|
31| "────────────────────────────────────────────────────────"
|
||||||
|
style 0-55 dim
|
||||||
|
32| " "
|
||||||
|
style 1-1 inverse
|
||||||
|
33| "────────────────────────────────────────────────────────"
|
||||||
|
style 0-55 dim
|
||||||
|
34| "deepseek-v4-pro /workspace/project ↑1.3k ↓340 cache 6"
|
||||||
|
style 0-55 dim
|
||||||
|
35| <blank>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||||
lifecycle started=1 stopped=0 progress=inactive
|
lifecycle started=1 stopped=0 progress=inactive
|
||||||
title "Inspect session diagnostics — DSH snapshot"
|
title "Inspect session diagnostics — DSH snapshot"
|
||||||
cursor hidden column=1 viewportRow=27 bufferRow=27
|
cursor hidden column=1 viewportRow=28 bufferRow=28
|
||||||
buffer
|
buffer
|
||||||
0| " DEEPSEEK HARNESS"
|
0| " DEEPSEEK HARNESS"
|
||||||
style 1-8 fg=bright-blue bold
|
style 1-8 fg=bright-blue bold
|
||||||
@@ -25,55 +25,75 @@ buffer
|
|||||||
style 1-9 fg=bright-magenta bold
|
style 1-9 fg=bright-magenta bold
|
||||||
10| " Session inspected. "
|
10| " Session inspected. "
|
||||||
11| <blank>
|
11| <blank>
|
||||||
12| "▌ Session diagnostics "
|
12| "╭─ Session status ─────────────────────────────────────────────────╮"
|
||||||
style 0-0 fg=bright-blue
|
style 0-2 dim
|
||||||
style 2-20 fg=bright-blue bold
|
style 3-16 fg=bright-blue bold
|
||||||
13| "▌ Session main-session "
|
style 17-67 dim
|
||||||
style 0-0 fg=bright-blue
|
13| "│ Session: main-session │"
|
||||||
style 2-15 fg=bright-black
|
style 0-0 dim
|
||||||
14| "▌ Title Inspect session diagnostics "
|
style 3-12 fg=bright-black
|
||||||
style 0-0 fg=bright-blue
|
style 67-67 dim
|
||||||
style 2-15 fg=bright-black
|
14| "│ Title: Inspect session diagnostics │"
|
||||||
15| "▌ Working dir /workspace/project "
|
style 0-0 dim
|
||||||
style 0-0 fg=bright-blue
|
style 3-12 fg=bright-black
|
||||||
style 2-15 fg=bright-black
|
style 67-67 dim
|
||||||
16| "▌ Model deepseek/deepseek-v4-pro "
|
15| "│ Directory: /workspace/project │"
|
||||||
style 0-0 fg=bright-blue
|
style 0-0 dim
|
||||||
style 2-15 fg=bright-black
|
style 3-12 fg=bright-black
|
||||||
17| "▌ Reasoning view shown "
|
style 67-67 dim
|
||||||
style 0-0 fg=bright-blue
|
16| "│ Model: deepseek/deepseek-v4-pro (reasoning shown) │"
|
||||||
style 2-15 fg=bright-black
|
style 0-0 dim
|
||||||
18| "▌ Agent idle "
|
style 3-12 fg=bright-black
|
||||||
style 0-0 fg=bright-blue
|
style 40-56 dim
|
||||||
style 2-15 fg=bright-black
|
style 67-67 dim
|
||||||
19| "▌ Activity events 6 · turns 1 · steps 1 · tool calls 1 "
|
17| "│ │"
|
||||||
style 0-0 fg=bright-blue
|
style 0-0 dim
|
||||||
style 2-15 fg=bright-black
|
style 67-67 dim
|
||||||
20| "▌ Tokens input 1,250 · output 340 "
|
18| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 tool call │"
|
||||||
style 0-0 fg=bright-blue
|
style 0-0 dim
|
||||||
style 2-15 fg=bright-black
|
style 3-12 fg=bright-black
|
||||||
21| "▌ Cache tokens read 3,000 · write 250 "
|
style 67-67 dim
|
||||||
style 0-0 fg=bright-blue
|
19| "│ │"
|
||||||
style 2-15 fg=bright-black
|
style 0-0 dim
|
||||||
22| "▌ KV cache hit 67% "
|
style 67-67 dim
|
||||||
style 0-0 fg=bright-blue
|
20| "│ Tokens: 1,250 input + 340 output │"
|
||||||
style 2-15 fg=bright-black
|
style 0-0 dim
|
||||||
23| "▌ Context 42,000 / 128,000 (33%) "
|
style 3-12 fg=bright-black
|
||||||
style 0-0 fg=bright-blue
|
style 67-67 dim
|
||||||
style 2-15 fg=bright-black
|
21| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read + 250 write) │"
|
||||||
24| "▌ Created 2026-07-22T09:10:11.000Z "
|
style 0-0 dim
|
||||||
style 0-0 fg=bright-blue
|
style 3-12 fg=bright-black
|
||||||
style 2-15 fg=bright-black
|
style 15-15 dim
|
||||||
25| "▌ Last active 2026-07-22T09:10:11.000Z "
|
style 16-26 fg=bright-blue
|
||||||
style 0-0 fg=bright-blue
|
style 27-32 dim
|
||||||
style 2-15 fg=bright-black
|
style 67-67 dim
|
||||||
26| "────────────────────────────────────────────────────────────────────────────────────────────"
|
22| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / 128,000) │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 15-15 dim
|
||||||
|
style 16-20 fg=bright-blue
|
||||||
|
style 21-32 dim
|
||||||
|
style 67-67 dim
|
||||||
|
23| "│ │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 67-67 dim
|
||||||
|
24| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 67-67 dim
|
||||||
|
25| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||||
|
style 0-0 dim
|
||||||
|
style 3-12 fg=bright-black
|
||||||
|
style 67-67 dim
|
||||||
|
26| "╰──────────────────────────────────────────────────────────────────╯"
|
||||||
|
style 0-67 dim
|
||||||
|
27| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||||
style 0-91 dim
|
style 0-91 dim
|
||||||
27| " "
|
28| " "
|
||||||
style 1-1 inverse
|
style 1-1 inverse
|
||||||
28| "────────────────────────────────────────────────────────────────────────────────────────────"
|
29| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||||
style 0-91 dim
|
style 0-91 dim
|
||||||
29| "deepseek-v4-pro /workspace/project ↑1.3k ↓340 cache 67% 33% context tools:collapsed"
|
30| "deepseek-v4-pro /workspace/project ↑1.3k ↓340 cache 67% 33% context tools:collapsed"
|
||||||
style 0-57 dim
|
style 0-57 dim
|
||||||
style 64-91 dim
|
style 64-91 dim
|
||||||
30-31| <blank>
|
31| <blank>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const CHECKPOINTS = [
|
|||||||
'disposed-terminal',
|
'disposed-terminal',
|
||||||
'resume-sessions',
|
'resume-sessions',
|
||||||
'status-diagnostics',
|
'status-diagnostics',
|
||||||
|
'status-diagnostics-narrow',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
type Checkpoint = typeof CHECKPOINTS[number]
|
type Checkpoint = typeof CHECKPOINTS[number]
|
||||||
@@ -672,6 +673,8 @@ describe('TUI terminal-state snapshots', () => {
|
|||||||
harness.terminal.send('\r')
|
harness.terminal.send('\r')
|
||||||
})
|
})
|
||||||
await checkpoint('status-diagnostics', harness.terminal, { includeScrollback: true })
|
await checkpoint('status-diagnostics', harness.terminal, { includeScrollback: true })
|
||||||
|
await renderAfter(harness, () => { harness.terminal.resize(56, 36) })
|
||||||
|
await checkpoint('status-diagnostics-narrow', harness.terminal, { includeScrollback: true })
|
||||||
await disposeSnapshot(harness)
|
await disposeSnapshot(harness)
|
||||||
dateNow.mockRestore()
|
dateNow.mockRestore()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -880,22 +880,23 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
|||||||
result.terminal.send('\r')
|
result.terminal.send('\r')
|
||||||
await tick()
|
await tick()
|
||||||
|
|
||||||
expect(result.terminal.output).toContain('Session diagnostics')
|
expect(result.terminal.output).toContain('Session status')
|
||||||
expect(result.terminal.output).toContain('Session main-session')
|
expect(result.terminal.output).toContain('main-session')
|
||||||
expect(result.terminal.output).toContain('Title Inspect status \\x1b]2;unsafe\\x07')
|
expect(result.terminal.output).toContain('Inspect status \\x1b]2;unsafe\\x07')
|
||||||
expect(result.terminal.output).toContain('Working dir /workspace/status')
|
expect(result.terminal.output).toContain('/workspace/status')
|
||||||
expect(result.terminal.output).toContain('Model deepseek/deepseek-v4-pro')
|
expect(result.terminal.output).toContain('deepseek/deepseek-v4-pro (reasoning hidden)')
|
||||||
expect(result.terminal.output).toContain('Reasoning view hidden')
|
expect(result.terminal.output).toContain('running · 6 events · 1 turn · 1 step · 2 tool calls')
|
||||||
expect(result.terminal.output).toContain('Agent running')
|
expect(result.terminal.output).toContain('1,250 input + 340 output')
|
||||||
expect(result.terminal.output).toContain('Activity events 6 · turns 1 · steps 1 · tool calls 2')
|
expect(result.terminal.output).toContain('[███████████░░░░░] 67% hit (3,000 read + 250 write)')
|
||||||
expect(result.terminal.output).toContain('Tokens input 1,250 · output 340')
|
expect(result.terminal.output).toContain('[█████░░░░░░░░░░░] 33% used (42,000 / 128,000)')
|
||||||
expect(result.terminal.output).toContain('Cache tokens read 3,000 · write 250')
|
expect(result.terminal.output).toContain('2026-07-22 09:10:11 UTC')
|
||||||
expect(result.terminal.output).toContain('KV cache hit 67%')
|
|
||||||
expect(result.terminal.output).toContain('Context 42,000 / 128,000 (33%)')
|
|
||||||
expect(result.terminal.output).toContain('Created 2026-07-22T09:10:11.000Z')
|
|
||||||
expect(result.terminal.output).toContain('Last active 2026-07-22T09:10:11.000Z')
|
|
||||||
expect(result.terminal.output).not.toContain('\u001B]2;unsafe\u0007')
|
expect(result.terminal.output).not.toContain('\u001B]2;unsafe\u0007')
|
||||||
|
|
||||||
|
result.terminal.resize(56)
|
||||||
|
result.terminal.send('/redraw')
|
||||||
|
result.terminal.send('\r')
|
||||||
|
await tick()
|
||||||
|
|
||||||
await dispose(result)
|
await dispose(result)
|
||||||
dateNow.mockRestore()
|
dateNow.mockRestore()
|
||||||
})
|
})
|
||||||
@@ -918,15 +919,12 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
|||||||
result.terminal.send('\r')
|
result.terminal.send('\r')
|
||||||
await tick()
|
await tick()
|
||||||
|
|
||||||
expect(result.terminal.output).toContain('Title untitled')
|
expect(result.terminal.output).toContain('untitled')
|
||||||
expect(result.terminal.output).toContain('Model unset')
|
expect(result.terminal.output).toContain('unset (reasoning shown)')
|
||||||
expect(result.terminal.output).toContain('Reasoning view shown')
|
expect(result.terminal.output).toContain('idle · 0 events · 0 turns · 0 steps · 0 tool calls')
|
||||||
expect(result.terminal.output).toContain('Agent idle')
|
expect(result.terminal.output).toContain('n/a (0 read + 0 write)')
|
||||||
expect(result.terminal.output).toContain('Activity events 0 · turns 0 · steps 0 · tool calls 0')
|
expect(result.terminal.output).toContain('7 used · capacity unknown')
|
||||||
expect(result.terminal.output).toContain('KV cache hit n/a')
|
expect(result.terminal.output).toContain('2026-07-22 10:11:12 UTC')
|
||||||
expect(result.terminal.output).toContain('Context 7 used · capacity unknown')
|
|
||||||
expect(result.terminal.output).toContain('Created 2026-07-22T10:11:12.000Z')
|
|
||||||
expect(result.terminal.output).toContain('Last active 2026-07-22T10:11:12.000Z')
|
|
||||||
await dispose(result)
|
await dispose(result)
|
||||||
dateNow.mockRestore()
|
dateNow.mockRestore()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user