feat(tui): /details Tab toggles apply immediately
Drop the pending state and confirm step: Tab cycles the highlighted entry and applies at once, so the transcript behind the dialog is the live preview; Enter/Esc/Ctrl+C just close.
This commit is contained in:
@@ -20,41 +20,53 @@ buffer
|
||||
8| "You "
|
||||
style 0-2 fg=bright-magenta bold underline
|
||||
9| "Inspect the renderer. "
|
||||
10| "Model wait 0.0s · Completed 2026-07-30 18:00:00 "
|
||||
style 0-46 dim
|
||||
11| <blank>
|
||||
12| "Reasoning blocks hidden. "
|
||||
10| <blank>
|
||||
11| "Assistant "
|
||||
style 0-8 fg=bright-magenta bold underline
|
||||
12| <blank>
|
||||
13| "● Tool / bash / Run the coverage gate"
|
||||
style 0-36 fg=green
|
||||
14| "$ pnpm run test:coverage "
|
||||
style 0-23 dim
|
||||
13| <blank>
|
||||
14| "Tool cards hidden. "
|
||||
15| "/workspace/project "
|
||||
style 0-17 dim
|
||||
15| <blank>
|
||||
16| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
|
||||
style 0-17 fg=bright-magenta bold
|
||||
style 18-31 dim
|
||||
style 34-50 dim
|
||||
style 53-57 dim
|
||||
style 60-69 dim
|
||||
17| " dsh > ╭ Transcript details ──────────────────────────────────────────────────╮ "
|
||||
style 1-3 fg=bright-magenta bold
|
||||
style 5-6 dim
|
||||
style 7-7 inverse
|
||||
16| "… +4 lines (Ctrl+O to expand) "
|
||||
style 0-28 dim
|
||||
17| "[exit 0] ╭ Transcript details ──────────────────────────────────────────────────╮ "
|
||||
style 0-7 dim
|
||||
style 14-85 fg=bright-magenta
|
||||
18| " │ → Tool cards hidden → collapsed │ "
|
||||
18| "Model wait 0.0│ → Tool cards collapsed │ "
|
||||
style 0-13 dim
|
||||
style 14-14 fg=bright-magenta
|
||||
style 16-67 fg=bright-magenta inverse
|
||||
style 16-58 fg=bright-magenta inverse
|
||||
style 85-85 fg=bright-magenta
|
||||
19| " │ Reasoning hidden │ "
|
||||
style 14-14 fg=bright-magenta
|
||||
style 27-55 dim
|
||||
style 85-85 fg=bright-magenta
|
||||
20| " │ │ "
|
||||
20| "Reasoning bloc│ │ "
|
||||
style 0-13 dim
|
||||
style 14-14 fg=bright-magenta
|
||||
style 85-85 fg=bright-magenta
|
||||
21| " │ ↑/↓ move • Tab cycle • Enter apply • Esc cancel │ "
|
||||
21| " │ ↑/↓ move • Tab toggle • Enter/Esc close │ "
|
||||
style 14-14 fg=bright-magenta
|
||||
style 16-62 dim
|
||||
style 16-54 dim
|
||||
style 85-85 fg=bright-magenta
|
||||
22| " ╰──────────────────────────────────────────────────────────────────────╯ "
|
||||
22| "Tool cards hid╰──────────────────────────────────────────────────────────────────────╯ "
|
||||
style 0-13 dim
|
||||
style 14-85 fg=bright-magenta
|
||||
23-39| <blank>
|
||||
23| <blank>
|
||||
24| "Tool and context cards collapsed. "
|
||||
style 0-32 dim
|
||||
25| <blank>
|
||||
26| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
|
||||
style 0-17 fg=bright-magenta bold
|
||||
style 18-31 dim
|
||||
style 34-50 dim
|
||||
style 53-57 dim
|
||||
style 60-69 dim
|
||||
27| " dsh > "
|
||||
style 1-3 fg=bright-magenta bold
|
||||
style 5-6 dim
|
||||
style 7-7 inverse
|
||||
28-39| <blank>
|
||||
|
||||
@@ -663,9 +663,10 @@ describe('TUI terminal-state snapshots', () => {
|
||||
harness.terminal.send('\r')
|
||||
})
|
||||
await checkpoint('details-command', harness.terminal, { includeScrollback: true })
|
||||
// Bare /details opens the two-entry selector seeded with the current
|
||||
// hidden/reasoning-off state; one Tab renders the tool-card entry's
|
||||
// pending cycle as `hidden → collapsed`.
|
||||
// Bare /details opens the two-entry toggle seeded with the current
|
||||
// hidden/reasoning-off state; one Tab immediately cycles tool cards
|
||||
// hidden -> collapsed, so the frame pins the applied notice, the restored
|
||||
// tool card behind the dialog, and the updated entry value together.
|
||||
await renderAfter(harness, () => {
|
||||
harness.terminal.send('/details')
|
||||
harness.terminal.send('\r')
|
||||
|
||||
@@ -2544,7 +2544,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('bare /details opens the transcript-details selector and applies the confirmed state', async () => {
|
||||
it('bare /details opens the transcript-details toggle and Tab applies immediately', async () => {
|
||||
const result = await setup()
|
||||
const open = async (): Promise<number> => {
|
||||
const from = result.terminal.output.length
|
||||
@@ -2563,50 +2563,40 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
await result.ctx.commands.execute(result.agent, '/details', new AbortController().signal)
|
||||
await tick()
|
||||
|
||||
// Esc cancels without touching the state.
|
||||
const cancelOutput = result.terminal.output.length
|
||||
result.terminal.send('\x1b')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(cancelOutput)).not.toContain('Tool and context cards')
|
||||
|
||||
// Tab cycles the highlighted entry's pending value; Enter applies it.
|
||||
const cycled = await open()
|
||||
// Each Tab applies one step immediately while the dialog stays open:
|
||||
// collapsed -> expanded -> hidden -> collapsed (wraparound).
|
||||
result.terminal.send('\t')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(cycled)).toContain('collapsed → expanded')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Tool and context cards expanded.')
|
||||
|
||||
// Both entries apply in one confirm: cycle tool cards through the
|
||||
// wraparound back to collapsed and toggle reasoning off.
|
||||
const reopened = await open()
|
||||
result.terminal.send('\t')
|
||||
result.terminal.send('\t')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(reopened)).toContain('expanded → collapsed')
|
||||
expect(result.terminal.output).toContain('Tool cards hidden.')
|
||||
result.terminal.send('\t')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Tool and context cards collapsed.')
|
||||
|
||||
// The reasoning entry toggles the same way.
|
||||
result.terminal.send('\x1b[B')
|
||||
result.terminal.send('\t')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(reopened)).toContain('shown → hidden')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Reasoning blocks hidden.')
|
||||
expect(result.terminal.output).toContain('Tool and context cards collapsed.')
|
||||
|
||||
// Enter with no pending change closes without a notice.
|
||||
const unchanged = await open()
|
||||
// Enter closes without further changes.
|
||||
const entered = result.terminal.output.length
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(unchanged)).not.toContain('Tool and context cards')
|
||||
expect(result.terminal.output.slice(unchanged)).not.toContain('Reasoning blocks')
|
||||
expect(result.terminal.output.slice(entered)).not.toContain('Reasoning blocks')
|
||||
|
||||
// Ctrl+C also cancels.
|
||||
const ctrlCOutput = result.terminal.output.length
|
||||
await open()
|
||||
// Esc and Ctrl+C also close; the reopened dialog shows the live values.
|
||||
const reopened = await open()
|
||||
expect(result.terminal.output.slice(reopened)).toContain('collapsed')
|
||||
expect(result.terminal.output.slice(reopened)).toContain('hidden')
|
||||
result.terminal.send('\x1b')
|
||||
await tick()
|
||||
const ctrlCOutput = await open()
|
||||
result.terminal.send('\x03')
|
||||
await tick()
|
||||
expect(result.terminal.output.slice(ctrlCOutput)).not.toContain('Reasoning blocks shown.')
|
||||
expect(result.terminal.output.slice(ctrlCOutput)).not.toContain('Reasoning blocks')
|
||||
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user