test(tui): snapshot semantic terminal state
This commit is contained in:
@@ -38,8 +38,13 @@
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-interaction": "workspace:^",
|
||||
"@deepseek-ai/dsh-workflow": "workspace:^",
|
||||
"@xterm/headless": "5.5.0",
|
||||
"cordis": "^4.0.0-rc.6"
|
||||
}
|
||||
}
|
||||
|
||||
130
packages/ui/tui/tests/harness.ts
Normal file
130
packages/ui/tui/tests/harness.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Context } from 'cordis'
|
||||
import type { Terminal } from '@earendil-works/pi-tui'
|
||||
import AgentRegistry, { AgentId, type Agent, type AgentStatus } from '@deepseek-ai/dsh-agent'
|
||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, { SessionId, type Session } from '@deepseek-ai/dsh-session'
|
||||
import type { ToolDefinition } from '@deepseek-ai/dsh-tools'
|
||||
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
||||
import { createTuiChat, type Config } from '../src/index.ts'
|
||||
|
||||
interface FakeAgent extends Agent {
|
||||
status: AgentStatus
|
||||
sent: ContentBlock[][]
|
||||
steered: ContentBlock[][]
|
||||
cancelled: string[]
|
||||
}
|
||||
|
||||
export interface TuiHarnessOptions {
|
||||
status?: AgentStatus
|
||||
config?: Config
|
||||
tools?: Record<string, ToolDefinition>
|
||||
configureContext?: (ctx: Context) => Promise<void>
|
||||
beforeMount?: (session: Session) => void
|
||||
cwd?: string | null
|
||||
}
|
||||
|
||||
export interface TuiHarness<TerminalType extends Terminal, Exit extends (code: number) => void> {
|
||||
ctx: Context
|
||||
session: Session
|
||||
agent: FakeAgent
|
||||
terminal: TerminalType
|
||||
exit: Exit
|
||||
controller: ReturnType<typeof createTuiChat>
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the production TUI around an in-memory session and controllable agent.
|
||||
* @param terminal - Terminal boundary driven by the test.
|
||||
* @param exit - Process-exit observer.
|
||||
* @param options - Initial session, agent, tool, and TUI configuration.
|
||||
* @returns The mounted TUI and every boundary the test may drive or inspect.
|
||||
*/
|
||||
export async function createTuiTestHarness<TerminalType extends Terminal, Exit extends (code: number) => void>(
|
||||
terminal: TerminalType,
|
||||
exit: Exit,
|
||||
options: TuiHarnessOptions = {},
|
||||
): Promise<TuiHarness<TerminalType, Exit>> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(AgentRegistry)
|
||||
await ctx.plugin(UserInteractionService)
|
||||
if (options.configureContext === undefined) {
|
||||
const tools = options.tools ?? {}
|
||||
ctx.provide('tools', {
|
||||
get(name: string) {
|
||||
return tools[name]
|
||||
},
|
||||
} as never)
|
||||
} else {
|
||||
await options.configureContext(ctx)
|
||||
}
|
||||
const session = ctx.sessions.create(
|
||||
SessionId('main-session'),
|
||||
options.cwd === null ? undefined : { meta: { cwd: options.cwd ?? '/workspace' } },
|
||||
)
|
||||
options.beforeMount?.(session)
|
||||
const sent: ContentBlock[][] = []
|
||||
const steered: ContentBlock[][] = []
|
||||
const cancelled: string[] = []
|
||||
const agent: FakeAgent = {
|
||||
id: AgentId('main'),
|
||||
options: { model: 'deepseek-v4-flash' },
|
||||
session,
|
||||
status: options.status ?? 'idle',
|
||||
ctx,
|
||||
sent,
|
||||
steered,
|
||||
cancelled,
|
||||
send(content) {
|
||||
sent.push(content)
|
||||
},
|
||||
steer(content) {
|
||||
steered.push(content)
|
||||
},
|
||||
inject() {},
|
||||
cancel(reason) {
|
||||
cancelled.push(reason ?? '')
|
||||
},
|
||||
whenIdle() {
|
||||
return Promise.resolve()
|
||||
},
|
||||
}
|
||||
ctx.agents.register(agent)
|
||||
const controller = createTuiChat(ctx, Object.assign({
|
||||
welcome: 'Coding agent ready.',
|
||||
agent: 'main',
|
||||
color: false,
|
||||
}, options.config), { terminal, exit })
|
||||
return { ctx, session, agent, terminal, exit, controller }
|
||||
}
|
||||
|
||||
/** Dispose the mounted TUI before its owning Cordis context. */
|
||||
export async function disposeTuiTestHarness(
|
||||
setup: Pick<TuiHarness<Terminal, (code: number) => void>, 'controller' | 'ctx'>,
|
||||
): Promise<void> {
|
||||
await setup.controller.dispose()
|
||||
await setup.ctx.fiber.dispose()
|
||||
}
|
||||
|
||||
/** Append a production-shaped user message to the active session surface. */
|
||||
export function appendUser(session: Session, text: string): void {
|
||||
session.append('user/message', {
|
||||
content: [{ type: 'text', text }],
|
||||
source: { kind: 'user' },
|
||||
}, { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
/** Append a production-shaped assistant message to the active session surface. */
|
||||
export function appendAssistant(
|
||||
session: Session,
|
||||
content: ContentBlock[],
|
||||
usage?: { inputTokens: number; outputTokens: number },
|
||||
): void {
|
||||
session.append('assistant/message', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
provenance: { provider: 'mock', model: 'deepseek-v4-flash' },
|
||||
content,
|
||||
...usage === undefined ? {} : { usage },
|
||||
}, { surfaceOp: 'append' })
|
||||
}
|
||||
318
packages/ui/tui/tests/headless-terminal.ts
Normal file
318
packages/ui/tui/tests/headless-terminal.ts
Normal file
@@ -0,0 +1,318 @@
|
||||
import type { Terminal } from '@earendil-works/pi-tui'
|
||||
import { Terminal as XtermTerminal, type IBufferCell } from '@xterm/headless'
|
||||
|
||||
const FRAME_END = '\x1b[?2026l'
|
||||
const FRAME_TIMEOUT_MS = 2_000
|
||||
|
||||
const ANSI_COLORS = [
|
||||
'black',
|
||||
'red',
|
||||
'green',
|
||||
'yellow',
|
||||
'blue',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'white',
|
||||
'bright-black',
|
||||
'bright-red',
|
||||
'bright-green',
|
||||
'bright-yellow',
|
||||
'bright-blue',
|
||||
'bright-magenta',
|
||||
'bright-cyan',
|
||||
'bright-white',
|
||||
] as const
|
||||
|
||||
interface FrameWaiter {
|
||||
target: number
|
||||
resolve: () => void
|
||||
reject: (error: Error) => void
|
||||
timer: ReturnType<typeof setTimeout>
|
||||
}
|
||||
|
||||
interface RowSnapshot {
|
||||
text: string
|
||||
wrapped: boolean
|
||||
styles: string[]
|
||||
}
|
||||
|
||||
export interface TerminalSnapshotOptions {
|
||||
/** Include the whole active buffer instead of only the visible viewport. */
|
||||
includeScrollback?: boolean
|
||||
}
|
||||
|
||||
function occurrenceCount(value: string, needle: string): number {
|
||||
let count = 0
|
||||
let offset = 0
|
||||
while (true) {
|
||||
const match = value.indexOf(needle, offset)
|
||||
if (match < 0) return count
|
||||
count += 1
|
||||
offset = match + needle.length
|
||||
}
|
||||
}
|
||||
|
||||
function colorLabel(cell: IBufferCell, kind: 'fg' | 'bg'): string | undefined {
|
||||
const isDefault = kind === 'fg' ? cell.isFgDefault() : cell.isBgDefault()
|
||||
if (isDefault) return undefined
|
||||
const isRgb = kind === 'fg' ? cell.isFgRGB() : cell.isBgRGB()
|
||||
const value = kind === 'fg' ? cell.getFgColor() : cell.getBgColor()
|
||||
if (isRgb) return `${kind}=#${value.toString(16).padStart(6, '0')}`
|
||||
const name = ANSI_COLORS[value]
|
||||
return `${kind}=${name ?? `ansi-${value}`}`
|
||||
}
|
||||
|
||||
function styleLabel(cell: IBufferCell): string {
|
||||
const labels = [
|
||||
colorLabel(cell, 'fg'),
|
||||
colorLabel(cell, 'bg'),
|
||||
cell.isBold() !== 0 ? 'bold' : undefined,
|
||||
cell.isDim() !== 0 ? 'dim' : undefined,
|
||||
cell.isItalic() !== 0 ? 'italic' : undefined,
|
||||
cell.isUnderline() !== 0 ? 'underline' : undefined,
|
||||
cell.isBlink() !== 0 ? 'blink' : undefined,
|
||||
cell.isInverse() !== 0 ? 'inverse' : undefined,
|
||||
cell.isInvisible() !== 0 ? 'invisible' : undefined,
|
||||
cell.isStrikethrough() !== 0 ? 'strike' : undefined,
|
||||
cell.isOverline() !== 0 ? 'overline' : undefined,
|
||||
].filter((label): label is string => label !== undefined)
|
||||
return labels.join(' ')
|
||||
}
|
||||
|
||||
function snapshotRow(terminal: XtermTerminal, row: number): RowSnapshot {
|
||||
const line = terminal.buffer.active.getLine(row)
|
||||
if (line === undefined) return { text: '', wrapped: false, styles: [] }
|
||||
const styles: string[] = []
|
||||
let activeStyle = ''
|
||||
let activeStart = 0
|
||||
for (let column = 0; column <= terminal.cols; column++) {
|
||||
const cell = column < terminal.cols ? line.getCell(column) : undefined
|
||||
const style = cell === undefined ? '' : styleLabel(cell)
|
||||
if (style === activeStyle) continue
|
||||
if (activeStyle !== '') styles.push(`${activeStart}-${column - 1} ${activeStyle}`)
|
||||
activeStyle = style
|
||||
activeStart = column
|
||||
}
|
||||
return {
|
||||
text: line.translateToString(true),
|
||||
wrapped: line.isWrapped,
|
||||
styles,
|
||||
}
|
||||
}
|
||||
|
||||
function renderRows(rows: readonly RowSnapshot[], firstRow: number): string[] {
|
||||
const rendered: string[] = []
|
||||
let blankStart: number | undefined
|
||||
const flushBlanks = (end: number): void => {
|
||||
if (blankStart === undefined) return
|
||||
rendered.push(blankStart === end ? `${blankStart}| <blank>` : `${blankStart}-${end}| <blank>`)
|
||||
blankStart = undefined
|
||||
}
|
||||
for (let index = 0; index < rows.length; index++) {
|
||||
const absoluteRow = firstRow + index
|
||||
const row = rows[index] as RowSnapshot
|
||||
if (row.text === '' && row.styles.length === 0 && !row.wrapped) {
|
||||
blankStart ??= absoluteRow
|
||||
continue
|
||||
}
|
||||
flushBlanks(absoluteRow - 1)
|
||||
rendered.push(`${absoluteRow}${row.wrapped ? '~' : ''}| ${JSON.stringify(row.text)}`)
|
||||
for (const style of row.styles) rendered.push(` style ${style}`)
|
||||
}
|
||||
flushBlanks(firstRow + rows.length - 1)
|
||||
return rendered
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminal emulator used by TUI snapshots. It consumes the same ANSI stream as
|
||||
* a real terminal and exposes completed synchronized frames as an awaitable boundary.
|
||||
*/
|
||||
export class HeadlessTerminal implements Terminal {
|
||||
readonly kittyProtocolActive = false
|
||||
readonly drainInput = (): Promise<void> => Promise.resolve()
|
||||
started = 0
|
||||
stopped = 0
|
||||
title = ''
|
||||
progress = false
|
||||
cursorVisible = true
|
||||
frames = 0
|
||||
private readonly emulator: XtermTerminal
|
||||
private onInput: (data: string) => void = () => {}
|
||||
private onResize: () => void = () => {}
|
||||
private pendingWrite: Promise<void> = Promise.resolve()
|
||||
private readonly frameWaiters = new Set<FrameWaiter>()
|
||||
|
||||
constructor(columns = 80, rows = 24) {
|
||||
this.emulator = new XtermTerminal({
|
||||
cols: columns,
|
||||
rows,
|
||||
scrollback: 1_000,
|
||||
allowProposedApi: true,
|
||||
drawBoldTextInBrightColors: false,
|
||||
logLevel: 'off',
|
||||
})
|
||||
}
|
||||
|
||||
get columns(): number {
|
||||
return this.emulator.cols
|
||||
}
|
||||
|
||||
get rows(): number {
|
||||
return this.emulator.rows
|
||||
}
|
||||
|
||||
start(onInput: (data: string) => void, onResize: () => void): void {
|
||||
this.started += 1
|
||||
this.onInput = onInput
|
||||
this.onResize = onResize
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.stopped += 1
|
||||
}
|
||||
|
||||
write(data: string): void {
|
||||
const completedFrames = occurrenceCount(data, FRAME_END)
|
||||
this.pendingWrite = new Promise((resolve) => {
|
||||
this.emulator.write(data, () => {
|
||||
this.frames += completedFrames
|
||||
for (const waiter of this.frameWaiters) {
|
||||
if (this.frames < waiter.target) continue
|
||||
clearTimeout(waiter.timer)
|
||||
this.frameWaiters.delete(waiter)
|
||||
waiter.resolve()
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
moveBy(lines: number): void {
|
||||
if (lines > 0) this.write(`\x1b[${lines}B`)
|
||||
if (lines < 0) this.write(`\x1b[${-lines}A`)
|
||||
}
|
||||
|
||||
hideCursor(): void {
|
||||
this.cursorVisible = false
|
||||
this.write('\x1b[?25l')
|
||||
}
|
||||
|
||||
showCursor(): void {
|
||||
this.cursorVisible = true
|
||||
this.write('\x1b[?25h')
|
||||
}
|
||||
|
||||
clearLine(): void {
|
||||
this.write('\x1b[K')
|
||||
}
|
||||
|
||||
clearFromCursor(): void {
|
||||
this.write('\x1b[J')
|
||||
}
|
||||
|
||||
clearScreen(): void {
|
||||
this.write('\x1b[2J\x1b[H')
|
||||
}
|
||||
|
||||
setTitle(title: string): void {
|
||||
this.title = title
|
||||
this.write(`\x1b]0;${title}\x07`)
|
||||
}
|
||||
|
||||
setProgress(active: boolean): void {
|
||||
this.progress = active
|
||||
}
|
||||
|
||||
send(data: string): void {
|
||||
this.onInput(data)
|
||||
}
|
||||
|
||||
resize(columns: number, rows = this.rows): void {
|
||||
this.emulator.resize(columns, rows)
|
||||
this.onResize()
|
||||
}
|
||||
|
||||
/** Wait until pi-tui completes a synchronized frame newer than `after`. */
|
||||
async waitForFrame(after = this.frames): Promise<void> {
|
||||
if (this.frames <= after) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const waiter: FrameWaiter = {
|
||||
target: after + 1,
|
||||
resolve,
|
||||
reject,
|
||||
timer: setTimeout(() => {
|
||||
this.frameWaiters.delete(waiter)
|
||||
reject(new Error(`TUI did not complete frame ${after + 1} within ${FRAME_TIMEOUT_MS}ms`))
|
||||
}, FRAME_TIMEOUT_MS),
|
||||
}
|
||||
this.frameWaiters.add(waiter)
|
||||
})
|
||||
}
|
||||
await this.flush()
|
||||
}
|
||||
|
||||
/** Await every terminal write queued through the current task. */
|
||||
async flush(): Promise<void> {
|
||||
let pending: Promise<void>
|
||||
do {
|
||||
pending = this.pendingWrite
|
||||
await pending
|
||||
} while (pending !== this.pendingWrite)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject palette output that would become theme-specific in a user's terminal.
|
||||
* @returns One location per RGB, extended-palette, or explicit-background cell.
|
||||
*/
|
||||
themeViolations(): string[] {
|
||||
const violations: string[] = []
|
||||
const buffer = this.emulator.buffer.active
|
||||
for (let row = 0; row < buffer.length; row++) {
|
||||
const line = buffer.getLine(row)
|
||||
if (line === undefined) continue
|
||||
for (let column = 0; column < this.columns; column++) {
|
||||
const cell = line.getCell(column)
|
||||
if (cell === undefined) continue
|
||||
const reasons = [
|
||||
cell.isFgRGB() ? 'rgb-fg' : undefined,
|
||||
cell.isBgRGB() ? 'rgb-bg' : undefined,
|
||||
cell.isFgPalette() && cell.getFgColor() > 15 ? `extended-fg-${cell.getFgColor()}` : undefined,
|
||||
cell.isBgPalette() && cell.getBgColor() > 15 ? `extended-bg-${cell.getBgColor()}` : undefined,
|
||||
!cell.isBgDefault() ? 'explicit-bg' : undefined,
|
||||
].filter((reason): reason is string => reason !== undefined)
|
||||
if (reasons.length > 0) violations.push(`${row}:${column} ${reasons.join(',')}`)
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
/** Serialize terminal cells and metadata into a stable, reviewable golden. */
|
||||
async snapshot(options: TerminalSnapshotOptions = {}): Promise<string> {
|
||||
await this.flush()
|
||||
const buffer = this.emulator.buffer.active
|
||||
const firstRow = options.includeScrollback === true ? 0 : buffer.viewportY
|
||||
const rowCount = options.includeScrollback === true ? buffer.length : this.rows
|
||||
const rows = Array.from({ length: rowCount }, (_, index) => snapshotRow(this.emulator, firstRow + index))
|
||||
const cursorBufferRow = buffer.baseY + buffer.cursorY
|
||||
const cursorViewportRow = cursorBufferRow - buffer.viewportY
|
||||
return [
|
||||
`terminal ${this.columns}x${this.rows} buffer=${buffer.type} length=${buffer.length} base=${buffer.baseY} viewport=${buffer.viewportY}`,
|
||||
`lifecycle started=${this.started} stopped=${this.stopped} progress=${this.progress ? 'active' : 'inactive'}`,
|
||||
`title ${JSON.stringify(this.title)}`,
|
||||
`cursor ${this.cursorVisible ? 'visible' : 'hidden'} column=${buffer.cursorX} viewportRow=${cursorViewportRow} bufferRow=${cursorBufferRow}`,
|
||||
options.includeScrollback === true ? 'buffer' : 'viewport',
|
||||
...renderRows(rows, firstRow),
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
await this.flush()
|
||||
for (const waiter of this.frameWaiters) {
|
||||
clearTimeout(waiter.timer)
|
||||
waiter.reject(new Error('terminal disposed before the requested frame completed'))
|
||||
}
|
||||
this.frameWaiters.clear()
|
||||
this.emulator.dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
terminal 100x40 buffer=normal length=41 base=1 viewport=1
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=37 bufferRow=38
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
8| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
9| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
10| "▌ packages/ui/tui 100% "
|
||||
style 0-0 fg=green
|
||||
11| "▌ … 4 more lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=green
|
||||
style 2-34 dim
|
||||
12| "▌ "
|
||||
style 0-0 fg=green
|
||||
13| <blank>
|
||||
14| "▌ "
|
||||
style 0-0 fg=green
|
||||
15| "▌ ✓ Edit renderer "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
16| "▌ src/view.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-12 bold
|
||||
17| "▌ - old line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=red
|
||||
18| "▌ - keep "
|
||||
style 0-0 fg=green
|
||||
style 2-7 fg=red
|
||||
19| "▌ … 5 more lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=green
|
||||
style 2-34 dim
|
||||
20| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| <blank>
|
||||
22| "▌ "
|
||||
style 0-0 fg=green
|
||||
23| "▌ ✓ Delegate renderer audit "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-26 bold
|
||||
24| "▌ The renderer has explicit lifecycle ownership. "
|
||||
style 0-0 fg=green
|
||||
25| "▌ "
|
||||
style 0-0 fg=green
|
||||
26| <blank>
|
||||
27| "▌ "
|
||||
style 0-0 fg=green
|
||||
28| "▌ ✓ Read output from background task subagent-7 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-46 bold
|
||||
29| "▌ audit complete "
|
||||
style 0-0 fg=green
|
||||
30| "▌ [status: completed] "
|
||||
style 0-0 fg=green
|
||||
31| "▌ "
|
||||
style 0-0 fg=green
|
||||
32| <blank>
|
||||
33| "▌ "
|
||||
style 0-0 fg=green
|
||||
34| "▌ ✓ Load skill dsh-code-review "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-29 bold
|
||||
35| "▌ Loaded review instructions. "
|
||||
style 0-0 fg=green
|
||||
36| "▌ "
|
||||
style 0-0 fg=green
|
||||
37| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
38| " "
|
||||
style 1-1 inverse
|
||||
39| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
40| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 67-99 dim
|
||||
@@ -0,0 +1,127 @@
|
||||
terminal 100x40 buffer=normal length=50 base=10 viewport=10
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=37 bufferRow=47
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
8| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
9| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
10| "▌ packages/ui/tui 100% "
|
||||
style 0-0 fg=green
|
||||
11| "▌ 4016 tests passed "
|
||||
style 0-0 fg=green
|
||||
12| "▌ 1 test skipped "
|
||||
style 0-0 fg=green
|
||||
13| "▌ coverage complete "
|
||||
style 0-0 fg=green
|
||||
14| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ ✓ Edit renderer "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
19| "▌ src/view.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-12 bold
|
||||
20| "▌ - old line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=red
|
||||
21| "▌ - keep "
|
||||
style 0-0 fg=green
|
||||
style 2-7 fg=red
|
||||
22| "▌ + new line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=green
|
||||
23| "▌ + keep "
|
||||
style 0-0 fg=green
|
||||
style 2-7 fg=green
|
||||
24| "▌ "
|
||||
style 0-0 fg=green
|
||||
25| "▌ tests/view.spec.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-19 bold
|
||||
26| "▌ + expect(screen).toMatchSnapshot() "
|
||||
style 0-0 fg=green
|
||||
style 2-35 fg=green
|
||||
27| "▌ "
|
||||
style 0-0 fg=green
|
||||
28| <blank>
|
||||
29| "▌ "
|
||||
style 0-0 fg=green
|
||||
30| "▌ ✓ Delegate renderer audit "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-26 bold
|
||||
31| "▌ The renderer has explicit lifecycle ownership. "
|
||||
style 0-0 fg=green
|
||||
32| "▌ "
|
||||
style 0-0 fg=green
|
||||
33| <blank>
|
||||
34| "▌ "
|
||||
style 0-0 fg=green
|
||||
35| "▌ ✓ Read output from background task subagent-7 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-46 bold
|
||||
36| "▌ audit complete "
|
||||
style 0-0 fg=green
|
||||
37| "▌ [status: completed] "
|
||||
style 0-0 fg=green
|
||||
38| "▌ "
|
||||
style 0-0 fg=green
|
||||
39| <blank>
|
||||
40| "▌ "
|
||||
style 0-0 fg=green
|
||||
41| "▌ ✓ Load skill dsh-code-review "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-29 bold
|
||||
42| "▌ Loaded review instructions. "
|
||||
style 0-0 fg=green
|
||||
43| "▌ "
|
||||
style 0-0 fg=green
|
||||
44| <blank>
|
||||
45| " Tool cards expanded. "
|
||||
style 1-20 fg=bright-black
|
||||
46| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
47| " "
|
||||
style 1-1 inverse
|
||||
48| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
49| "/workspace/project ↑0 ↓0 idle reasoning:on tools:expanded"
|
||||
style 0-24 dim
|
||||
style 66-99 dim
|
||||
@@ -0,0 +1,50 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=14 bufferRow=14
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-95 bold
|
||||
8| "▌ const second = await tools.bas "
|
||||
style 0-0 fg=green
|
||||
style 2-31 bold
|
||||
9| "▌ CODE_ONE "
|
||||
style 0-0 fg=green
|
||||
10| "▌ CODE_TWO "
|
||||
style 0-0 fg=green
|
||||
11| "▌ combined: CODE_ONE+CODE_TWO "
|
||||
style 0-0 fg=green
|
||||
12| "▌ "
|
||||
style 0-0 fg=green
|
||||
13| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
14| " "
|
||||
style 1-1 inverse
|
||||
15| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
16| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
17-35| <blank>
|
||||
52
packages/ui/tui/tests/snapshots/code-mode-pending.golden.txt
Normal file
52
packages/ui/tui/tests/snapshots/code-mode-pending.golden.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=15 bufferRow=15
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
7| "▌ ◌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-95 bold
|
||||
8| "▌ const second = await tools.bas "
|
||||
style 0-0 fg=yellow
|
||||
style 2-31 bold
|
||||
9| "▌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
style 0-0 fg=yellow
|
||||
10| "▌ const second = await tools.bash({ command: 'echo CODE_TWO' }) "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ console.log(first, second) "
|
||||
style 0-0 fg=yellow
|
||||
12| "▌ return `${first}+${second}` "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| " "
|
||||
style 1-1 inverse
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
17| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
18-35| <blank>
|
||||
@@ -0,0 +1,75 @@
|
||||
terminal 96x36 buffer=normal length=43 base=7 viewport=7
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=40
|
||||
viewport
|
||||
7| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Explain snapshot fidelity with cells. "
|
||||
style 0-0 fg=bright-blue
|
||||
style 10-26 bold
|
||||
style 33-37 fg=cyan
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " Compare the terminal state, not write fragments. "
|
||||
style 1-48 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
15| " Result "
|
||||
style 1-6 fg=bright-blue bold
|
||||
16| " "
|
||||
17| " - final viewport "
|
||||
style 1-2 fg=bright-blue
|
||||
18| " - semantic styles "
|
||||
style 1-2 fg=bright-blue
|
||||
19| " "
|
||||
20| " │ deterministic and reviewable "
|
||||
style 1-2 fg=bright-magenta
|
||||
style 3-30 fg=bright-black italic
|
||||
21| <blank>
|
||||
22| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
23| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
24| "▌ Show the live update. "
|
||||
style 0-0 fg=bright-blue
|
||||
25| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
26| <blank>
|
||||
27| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
28| " Inspecting width and styles. "
|
||||
style 1-28 fg=bright-black italic
|
||||
29| <blank>
|
||||
30| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
31| " Streaming visible state is complete. "
|
||||
style 11-23 bold
|
||||
32| <blank>
|
||||
33| " The model reached its output-token limit. "
|
||||
style 1-41 fg=yellow
|
||||
34| <blank>
|
||||
35| "Plan"
|
||||
style 0-3 fg=bright-blue bold
|
||||
36| " ✓ model the terminal"
|
||||
style 2-2 fg=green
|
||||
style 4-21 fg=bright-black
|
||||
37| " ● capture advanced states"
|
||||
style 2-2 fg=yellow
|
||||
38| " ○ verify PTY cleanup"
|
||||
style 2-2 dim
|
||||
39| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
40| " "
|
||||
style 1-1 inverse
|
||||
41| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
42| "/workspace/project ↑13k ↓760 idle reasoning:on tools:compact"
|
||||
style 0-28 dim
|
||||
style 63-95 dim
|
||||
@@ -0,0 +1,73 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=27 bufferRow=27
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Explain snapshot fidelity with cells. "
|
||||
style 0-0 fg=bright-blue
|
||||
style 10-26 bold
|
||||
style 33-37 fg=cyan
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " Compare the terminal state, not write fragments. "
|
||||
style 1-48 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
15| " Result "
|
||||
style 1-6 fg=bright-blue bold
|
||||
16| " "
|
||||
17| " - final viewport "
|
||||
style 1-2 fg=bright-blue
|
||||
18| " - semantic styles "
|
||||
style 1-2 fg=bright-blue
|
||||
19| " "
|
||||
20| " │ deterministic and reviewable "
|
||||
style 1-2 fg=bright-magenta
|
||||
style 3-30 fg=bright-black italic
|
||||
21| <blank>
|
||||
22| "Plan"
|
||||
style 0-3 fg=bright-blue bold
|
||||
23| " ✓ model the terminal"
|
||||
style 2-2 fg=green
|
||||
style 4-21 fg=bright-black
|
||||
24| " ● capture advanced states"
|
||||
style 2-2 fg=yellow
|
||||
25| " ○ verify PTY cleanup"
|
||||
style 2-2 dim
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
27| " "
|
||||
style 1-1 inverse
|
||||
28| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
29| "/workspace/project ↑13k ↓640 idle reasoning:on tools:compact"
|
||||
style 0-28 dim
|
||||
style 63-95 dim
|
||||
30-35| <blank>
|
||||
@@ -0,0 +1,75 @@
|
||||
terminal 96x36 buffer=normal length=41 base=5 viewport=5
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=38
|
||||
viewport
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Explain snapshot fidelity with cells. "
|
||||
style 0-0 fg=bright-blue
|
||||
style 10-26 bold
|
||||
style 33-37 fg=cyan
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " Compare the terminal state, not write fragments. "
|
||||
style 1-48 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
15| " Result "
|
||||
style 1-6 fg=bright-blue bold
|
||||
16| " "
|
||||
17| " - final viewport "
|
||||
style 1-2 fg=bright-blue
|
||||
18| " - semantic styles "
|
||||
style 1-2 fg=bright-blue
|
||||
19| " "
|
||||
20| " │ deterministic and reviewable "
|
||||
style 1-2 fg=bright-magenta
|
||||
style 3-30 fg=bright-black italic
|
||||
21| <blank>
|
||||
22| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
23| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
24| "▌ Show the live update. "
|
||||
style 0-0 fg=bright-blue
|
||||
25| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
26| <blank>
|
||||
27| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
28| " Inspecting width and styles. "
|
||||
style 1-28 fg=bright-black italic
|
||||
29| <blank>
|
||||
30| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
31| " Streaming visible state… "
|
||||
style 11-23 bold
|
||||
32| <blank>
|
||||
33| "Plan"
|
||||
style 0-3 fg=bright-blue bold
|
||||
34| " ✓ model the terminal"
|
||||
style 2-2 fg=green
|
||||
style 4-21 fg=bright-black
|
||||
35| " ● capture advanced states"
|
||||
style 2-2 fg=yellow
|
||||
36| " ○ verify PTY cleanup"
|
||||
style 2-2 dim
|
||||
37| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
38| " "
|
||||
style 1-1 inverse
|
||||
39| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
40| "/workspace/project ↑13k ↓640 idle reasoning:on tools:compact"
|
||||
style 0-28 dim
|
||||
style 63-95 dim
|
||||
@@ -0,0 +1,73 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=25 bufferRow=25
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ Inspect cordis runtime: tools "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-32 bold
|
||||
8| "▌ ## tools "
|
||||
style 0-0 fg=green
|
||||
9| "▌ run_code "
|
||||
style 0-0 fg=green
|
||||
10| "▌ workflow "
|
||||
style 0-0 fg=green
|
||||
11| "▌ cordis_mount "
|
||||
style 0-0 fg=green
|
||||
12| "▌ cordis_unmount "
|
||||
style 0-0 fg=green
|
||||
13| "▌ "
|
||||
style 0-0 fg=green
|
||||
14| <blank>
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
16| "▌ ✓ Mount plugin into live cordis runtime "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-40 bold
|
||||
17| "▌ mounted dyn-1 (plugin \"snapshot-marker\", state: active) "
|
||||
style 0-0 fg=green
|
||||
18| "▌ "
|
||||
style 0-0 fg=green
|
||||
19| <blank>
|
||||
20| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| "▌ ✓ Unmount dyn-1 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
22| "▌ unmounted dyn-1 (plugin \"snapshot-marker\") "
|
||||
style 0-0 fg=green
|
||||
23| "▌ "
|
||||
style 0-0 fg=green
|
||||
24| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
25| " "
|
||||
style 1-1 inverse
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
27| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
28-35| <blank>
|
||||
@@ -0,0 +1,59 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=18 bufferRow=18
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ ◌ Inspect cordis runtime: tools "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-32 bold
|
||||
7| <blank>
|
||||
8| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
9| "▌ ◌ Mount plugin into live cordis runtime "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-40 bold
|
||||
10| "▌ { "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ \"code\": \"return { name: 'snapshot-marker', apply(ctx) { ctx.provide('snapshotMarker', { "
|
||||
style 0-0 fg=yellow
|
||||
12| "▌ ready: true }) } }\" "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ } "
|
||||
style 0-0 fg=yellow
|
||||
14| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
15| <blank>
|
||||
16| "▌ ◌ Unmount dyn-1 "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-16 bold
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
18| " "
|
||||
style 1-1 inverse
|
||||
19| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
20| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
21-35| <blank>
|
||||
52
packages/ui/tui/tests/snapshots/disposed-terminal.golden.txt
Normal file
52
packages/ui/tui/tests/snapshots/disposed-terminal.golden.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=1 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor visible column=0 viewportRow=22 bufferRow=22
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Keyboard shortcuts "
|
||||
style 1-18 fg=bright-blue bold
|
||||
7| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 1-61 fg=bright-black
|
||||
8| " Esc cancel active turn • Ctrl+O expand tool cards • Ctrl+R toggle reasoning "
|
||||
style 1-75 fg=bright-black
|
||||
9| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 1-73 fg=bright-black
|
||||
10| " /help /clear /cancel /reasoning /tools /redraw /exit "
|
||||
style 1-52 fg=bright-black
|
||||
11| <blank>
|
||||
12| " Unknown command: /unknown-advanced-command "
|
||||
style 1-42 fg=yellow
|
||||
13| <blank>
|
||||
14| " provider stream failed after partial output "
|
||||
style 1-43 fg=red
|
||||
15| <blank>
|
||||
16| " The previous process ended during this turn. "
|
||||
style 1-44 fg=yellow
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
18| " "
|
||||
style 1-1 inverse
|
||||
19| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
20| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 59-91 dim
|
||||
21-31| <blank>
|
||||
@@ -0,0 +1,53 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=16 bufferRow=16
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ workflow: tui-matrix "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-23 bold
|
||||
8| "▌ workflow \"tui-matrix\" completed (2 agents). "
|
||||
style 0-0 fg=green
|
||||
9| "▌ Return value: "
|
||||
style 0-0 fg=green
|
||||
10| "▌ { "
|
||||
style 0-0 fg=green
|
||||
11| "▌ \"reports\": [\"layout ok\", \"lifecycle ok\"], "
|
||||
style 0-0 fg=green
|
||||
12| "▌ \"verdict\": \"covered\" "
|
||||
style 0-0 fg=green
|
||||
13| "▌ } "
|
||||
style 0-0 fg=green
|
||||
14| "▌ "
|
||||
style 0-0 fg=green
|
||||
15| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
16| " "
|
||||
style 1-1 inverse
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
18| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
19-35| <blank>
|
||||
@@ -0,0 +1,55 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=17 bufferRow=17
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
7| "▌ ◌ workflow: tui-matrix "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-23 bold
|
||||
8| "▌ phase('Inspect') "
|
||||
style 0-0 fg=yellow
|
||||
9| "▌ const reports = await parallel([ "
|
||||
style 0-0 fg=yellow
|
||||
10| "▌ () => agent('Audit layout', { label: 'layout', phase: 'Inspect' }), "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ () => agent('Audit lifecycle', { label: 'lifecycle', phase: 'Inspect' }), "
|
||||
style 0-0 fg=yellow
|
||||
12| "▌ ]) "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ phase('Verify') "
|
||||
style 0-0 fg=yellow
|
||||
14| "▌ return { reports, verdict: 'covered' } "
|
||||
style 0-0 fg=yellow
|
||||
15| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
17| " "
|
||||
style 1-1 inverse
|
||||
18| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
19| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 63-95 dim
|
||||
20-35| <blank>
|
||||
52
packages/ui/tui/tests/snapshots/errors-and-help.golden.txt
Normal file
52
packages/ui/tui/tests/snapshots/errors-and-help.golden.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=18 bufferRow=18
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Keyboard shortcuts "
|
||||
style 1-18 fg=bright-blue bold
|
||||
7| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 1-61 fg=bright-black
|
||||
8| " Esc cancel active turn • Ctrl+O expand tool cards • Ctrl+R toggle reasoning "
|
||||
style 1-75 fg=bright-black
|
||||
9| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 1-73 fg=bright-black
|
||||
10| " /help /clear /cancel /reasoning /tools /redraw /exit "
|
||||
style 1-52 fg=bright-black
|
||||
11| <blank>
|
||||
12| " Unknown command: /unknown-advanced-command "
|
||||
style 1-42 fg=yellow
|
||||
13| <blank>
|
||||
14| " provider stream failed after partial output "
|
||||
style 1-43 fg=red
|
||||
15| <blank>
|
||||
16| " The previous process ended during this turn. "
|
||||
style 1-44 fg=yellow
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
18| " "
|
||||
style 1-1 inverse
|
||||
19| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
20| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 59-91 dim
|
||||
21-31| <blank>
|
||||
@@ -0,0 +1,69 @@
|
||||
terminal 56x20 buffer=normal length=20 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=56 viewportRow=13 bufferRow=13
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────╮"
|
||||
style 0-55 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 55-55 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 55-55 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 55-55 fg=bright-blue
|
||||
4| "╰───╭ Coverage ────────────────────────────────────╮───╯"
|
||||
style 0-55 fg=bright-blue
|
||||
5| "────│ Which advanced TUI states belong in the │────"
|
||||
style 0-3 dim
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-50 bold
|
||||
style 51-51 fg=bright-blue bold
|
||||
style 52-55 dim
|
||||
6| " │ required matrix? │ "
|
||||
style 1-1 inverse
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-21 bold
|
||||
style 51-51 fg=bright-blue
|
||||
7| "────│ │────"
|
||||
style 0-3 dim
|
||||
style 4-4 fg=bright-blue
|
||||
style 51-51 fg=bright-blue
|
||||
style 52-55 dim
|
||||
8| "/wor│ › [ ] Code Mode — run_code programs and capt │:com"
|
||||
style 0-3 dim
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-6 fg=bright-blue inverse
|
||||
style 7-20 inverse
|
||||
style 21-49 fg=bright-black inverse
|
||||
style 51-51 fg=bright-blue
|
||||
style 52-55 dim
|
||||
9| " │ [ ] Workflows — phases and parallel agents │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 21-49 fg=bright-black
|
||||
style 51-51 fg=bright-blue
|
||||
10| " │ [ ] Cordis tools — inspect, mount, and unm │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 24-49 fg=bright-black
|
||||
style 51-51 fg=bright-blue
|
||||
11| " │ 1/4 │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-8 dim
|
||||
style 51-51 fg=bright-blue
|
||||
12| " │ ↑↓ navigate • Space toggle • Enter submit • │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-49 dim
|
||||
style 51-51 fg=bright-blue
|
||||
13| " │ Select at least one option, or press C for a │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-49 fg=red
|
||||
style 51-51 fg=bright-blue
|
||||
14| " ╰──────────────────────────────────────────────╯ "
|
||||
style 4-51 fg=bright-blue
|
||||
15-19| <blank>
|
||||
67
packages/ui/tui/tests/snapshots/question-dialog.golden.txt
Normal file
67
packages/ui/tui/tests/snapshots/question-dialog.golden.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
terminal 56x20 buffer=normal length=20 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=0 viewportRow=19 bufferRow=19
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────╮"
|
||||
style 0-55 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 55-55 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 55-55 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 55-55 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────╯"
|
||||
style 0-55 fg=bright-blue
|
||||
5| "────╭ Coverage ────────────────────────────────────╮────"
|
||||
style 0-3 dim
|
||||
style 4-51 fg=bright-blue
|
||||
style 52-55 dim
|
||||
6| " │ Which advanced TUI states belong in the │ "
|
||||
style 1-1 inverse
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-50 bold
|
||||
style 51-51 fg=bright-blue bold
|
||||
7| "────│ required matrix? │────"
|
||||
style 0-3 dim
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-21 bold
|
||||
style 51-51 fg=bright-blue
|
||||
style 52-55 dim
|
||||
8| "/wor│ │:com"
|
||||
style 0-3 dim
|
||||
style 4-4 fg=bright-blue
|
||||
style 51-51 fg=bright-blue
|
||||
style 52-55 dim
|
||||
9| " │ › [ ] Code Mode — run_code programs and capt │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-6 fg=bright-blue inverse
|
||||
style 7-20 inverse
|
||||
style 21-49 fg=bright-black inverse
|
||||
style 51-51 fg=bright-blue
|
||||
10| " │ [ ] Workflows — phases and parallel agents │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 21-49 fg=bright-black
|
||||
style 51-51 fg=bright-blue
|
||||
11| " │ [ ] Cordis tools — inspect, mount, and unm │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 24-49 fg=bright-black
|
||||
style 51-51 fg=bright-blue
|
||||
12| " │ 1/4 │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-8 dim
|
||||
style 51-51 fg=bright-blue
|
||||
13| " │ ↑↓ navigate • Space toggle • Enter submit • │ "
|
||||
style 4-4 fg=bright-blue
|
||||
style 6-49 dim
|
||||
style 51-51 fg=bright-blue
|
||||
14| " ╰──────────────────────────────────────────────╯ "
|
||||
style 4-51 fg=bright-blue
|
||||
15-19| <blank>
|
||||
@@ -0,0 +1,45 @@
|
||||
terminal 44x18 buffer=normal length=18 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=12 bufferRow=12
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────╮"
|
||||
style 0-43 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 43-43 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 43-43 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-42 dim
|
||||
style 43-43 fg=bright-blue dim
|
||||
4| "│ main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-13 dim
|
||||
style 43-43 fg=bright-blue
|
||||
5| "╰──────────────────────────────────────────╯"
|
||||
style 0-43 fg=bright-blue
|
||||
6| <blank>
|
||||
7| " Context · compact "
|
||||
style 1-17 dim
|
||||
8| " Compacted summary: the prior command "
|
||||
style 1-43 fg=bright-black
|
||||
9| " completed and its details were retired "
|
||||
style 1-43 fg=bright-black
|
||||
10| " from the active surface. "
|
||||
style 1-24 fg=bright-black
|
||||
11| "────────────────────────────────────────────"
|
||||
style 0-43 dim
|
||||
12| " "
|
||||
style 1-1 inverse
|
||||
13| "────────────────────────────────────────────"
|
||||
style 0-43 dim
|
||||
14| "/workspace/project ↑0 ↓0 idle reasoning:o"
|
||||
style 0-24 dim
|
||||
style 27-43 dim
|
||||
15-17| <blank>
|
||||
@@ -0,0 +1,37 @@
|
||||
terminal 104x30 buffer=normal length=30 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=9 bufferRow=9
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-103 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 103-103 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 103-103 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 103-103 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-103 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Context · compact "
|
||||
style 1-17 dim
|
||||
7| " Compacted summary: the prior command completed and its details were retired from the active surface. "
|
||||
style 1-100 fg=bright-black
|
||||
8| "────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-103 dim
|
||||
9| " "
|
||||
style 1-1 inverse
|
||||
10| "────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-103 dim
|
||||
11| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 71-103 dim
|
||||
12-29| <blank>
|
||||
@@ -0,0 +1,67 @@
|
||||
terminal 80x24 buffer=normal length=25 base=1 viewport=1
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=21 bufferRow=22
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-79 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 79-79 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 79-79 fg=bright-blue
|
||||
3| "│ main • deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-44 dim
|
||||
style 79-79 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-79 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Old prompt with a long line that exercises wrapping before compaction. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| "▌ "
|
||||
style 0-0 fg=green
|
||||
12| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
13| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
14| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
15| "▌ packages/ui/tui 100% "
|
||||
style 0-0 fg=green
|
||||
16| "▌ 4016 tests passed "
|
||||
style 0-0 fg=green
|
||||
17| "▌ 1 test skipped "
|
||||
style 0-0 fg=green
|
||||
18| "▌ coverage complete "
|
||||
style 0-0 fg=green
|
||||
19| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
20| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| "────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-79 dim
|
||||
22| " "
|
||||
style 1-1 inverse
|
||||
23| "────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-79 dim
|
||||
24| "/workspace/project ↑0 ↓0 idle reasoning:on tools:compact"
|
||||
style 0-24 dim
|
||||
style 47-79 dim
|
||||
472
packages/ui/tui/tests/tui.snapshot.ts
Normal file
472
packages/ui/tui/tests/tui.snapshot.ts
Normal file
@@ -0,0 +1,472 @@
|
||||
import { mkdir, readdir, writeFile } from 'node:fs/promises'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { afterAll, describe, expect, it } from 'vitest'
|
||||
import type { Context } from 'cordis'
|
||||
import { CallId, type ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||
import type { Session } from '@deepseek-ai/dsh-session'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry, { type ToolDefinition, type ToolResultView } from '@deepseek-ai/dsh-tools'
|
||||
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
|
||||
import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow'
|
||||
import {
|
||||
appendAssistant,
|
||||
appendUser,
|
||||
createTuiTestHarness,
|
||||
disposeTuiTestHarness,
|
||||
type TuiHarness,
|
||||
type TuiHarnessOptions,
|
||||
} from './harness.ts'
|
||||
import { HeadlessTerminal, type TerminalSnapshotOptions } from './headless-terminal.ts'
|
||||
|
||||
const SNAPSHOTS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'snapshots')
|
||||
const REFRESHING = process.env.DSH_SNAPSHOT === 'refresh'
|
||||
|
||||
const CHECKPOINTS = [
|
||||
'conversation-replay',
|
||||
'conversation-streaming',
|
||||
'conversation-complete',
|
||||
'code-mode-pending',
|
||||
'code-mode-complete',
|
||||
'dynamic-workflow-pending',
|
||||
'dynamic-workflow-complete',
|
||||
'cordis-tools-pending',
|
||||
'cordis-tools-complete',
|
||||
'advanced-cards-collapsed',
|
||||
'advanced-cards-expanded',
|
||||
'question-dialog',
|
||||
'question-dialog-validation',
|
||||
'surface-before-compaction',
|
||||
'surface-after-compaction-narrow',
|
||||
'surface-after-compaction-wide',
|
||||
'errors-and-help',
|
||||
'disposed-terminal',
|
||||
] as const
|
||||
|
||||
type Checkpoint = typeof CHECKPOINTS[number]
|
||||
type SnapshotHarness = TuiHarness<HeadlessTerminal, (code: number) => void>
|
||||
|
||||
const observedCheckpoints = new Set<Checkpoint>()
|
||||
|
||||
async function checkpoint(
|
||||
name: Checkpoint,
|
||||
terminal: HeadlessTerminal,
|
||||
options: TerminalSnapshotOptions = {},
|
||||
): Promise<void> {
|
||||
observedCheckpoints.add(name)
|
||||
expect(terminal.themeViolations(), `${name} must remain theme-agnostic`).toEqual([])
|
||||
const snapshot = await terminal.snapshot(options)
|
||||
const path = join(SNAPSHOTS_DIR, `${name}.golden.txt`)
|
||||
if (REFRESHING) {
|
||||
await mkdir(SNAPSHOTS_DIR, { recursive: true })
|
||||
await writeFile(path, snapshot)
|
||||
}
|
||||
await expect(snapshot).toMatchFileSnapshot(path)
|
||||
}
|
||||
|
||||
async function setupSnapshot(
|
||||
options: TuiHarnessOptions = {},
|
||||
size: { columns?: number; rows?: number } = {},
|
||||
): Promise<SnapshotHarness> {
|
||||
const terminal = new HeadlessTerminal(size.columns ?? 96, size.rows ?? 36)
|
||||
const before = terminal.frames
|
||||
const result = await createTuiTestHarness(terminal, () => {}, {
|
||||
...options,
|
||||
cwd: options.cwd === undefined ? '/workspace/project' : options.cwd,
|
||||
config: Object.assign({
|
||||
welcome: 'Snapshot agent ready.',
|
||||
color: true,
|
||||
title: 'DSH snapshot',
|
||||
}, options.config),
|
||||
})
|
||||
await terminal.waitForFrame(before)
|
||||
return result
|
||||
}
|
||||
|
||||
async function renderAfter(harness: SnapshotHarness, action: () => void): Promise<void> {
|
||||
const before = harness.terminal.frames
|
||||
action()
|
||||
await harness.terminal.waitForFrame(before)
|
||||
}
|
||||
|
||||
async function disposeSnapshot(harness: SnapshotHarness): Promise<void> {
|
||||
await disposeTuiTestHarness(harness)
|
||||
await harness.terminal.dispose()
|
||||
}
|
||||
|
||||
async function configureAdvancedTools(ctx: Context): Promise<void> {
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry, { mode: 'code' })
|
||||
ctx.provide('workflows', {} as never)
|
||||
await ctx.plugin(ToolWorkflow, { toolName: 'workflow', maxResultChars: 50_000 })
|
||||
await ctx.plugin(ToolCordis, { vmTimeoutMs: 5_000 })
|
||||
}
|
||||
|
||||
interface ToolCallFixture {
|
||||
id: string
|
||||
name: string
|
||||
arguments: unknown
|
||||
}
|
||||
|
||||
function appendToolCalls(session: Session, calls: readonly ToolCallFixture[]): void {
|
||||
appendAssistant(session, calls.map(call => ({
|
||||
type: 'tool-call',
|
||||
id: CallId(call.id),
|
||||
name: call.name,
|
||||
arguments: JSON.stringify(call.arguments),
|
||||
})))
|
||||
for (const call of calls) {
|
||||
session.append('tool/call', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
callId: CallId(call.id),
|
||||
name: call.name,
|
||||
arguments: JSON.stringify(call.arguments),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function appendToolResult(
|
||||
session: Session,
|
||||
id: string,
|
||||
content: ContentBlock[],
|
||||
options: { isError?: boolean; meta?: unknown } = {},
|
||||
): void {
|
||||
session.append('tool/result', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
callId: CallId(id),
|
||||
content,
|
||||
isError: options.isError ?? false,
|
||||
...options.meta === undefined ? {} : { meta: options.meta },
|
||||
}, { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
function visualTool(
|
||||
name: string,
|
||||
call: NonNullable<ToolDefinition['presentCall']>,
|
||||
result?: NonNullable<ToolDefinition['presentResult']>,
|
||||
): ToolDefinition {
|
||||
return {
|
||||
name,
|
||||
description: `${name} snapshot fixture`,
|
||||
parameters: {},
|
||||
execute: () => Promise.resolve([]),
|
||||
presentCall: call,
|
||||
...result === undefined ? {} : { presentResult: result },
|
||||
}
|
||||
}
|
||||
|
||||
const ADVANCED_CARD_TOOLS: Record<string, ToolDefinition> = {
|
||||
bash: visualTool(
|
||||
'bash',
|
||||
() => ({ card: 'terminal', title: 'pnpm run test:coverage', description: 'Run the coverage gate', cwd: '/workspace/project' }),
|
||||
() => ({ card: 'terminal', output: 'packages/ui/tui 100%\n4016 tests passed\n1 test skipped\ncoverage complete', exitCode: 0 }),
|
||||
),
|
||||
edit: visualTool(
|
||||
'edit',
|
||||
() => ({ card: 'diff', title: 'Edit renderer', diffs: [{ path: 'src/view.ts', oldText: 'old line', newText: 'new line' }] }),
|
||||
(): ToolResultView => ({
|
||||
card: 'diff',
|
||||
diffs: [
|
||||
{ path: 'src/view.ts', oldText: 'old line\nkeep', newText: 'new line\nkeep' },
|
||||
{ path: 'tests/view.spec.ts', oldText: null, newText: 'expect(screen).toMatchSnapshot()' },
|
||||
],
|
||||
}),
|
||||
),
|
||||
subagent: visualTool('subagent', args => ({
|
||||
card: 'generic',
|
||||
title: 'Delegate renderer audit',
|
||||
rawInput: (args as { prompt: string }).prompt,
|
||||
})),
|
||||
task_output: visualTool('task_output', args => ({
|
||||
card: 'generic',
|
||||
kind: 'read',
|
||||
title: `Read output from background task ${(args as { task_id: string }).task_id}`,
|
||||
rawInput: (args as { task_id: string }).task_id,
|
||||
})),
|
||||
skill: visualTool('skill', args => ({
|
||||
card: 'generic',
|
||||
kind: 'read',
|
||||
title: `Load skill ${(args as { name: string }).name}`,
|
||||
rawInput: (args as { name: string }).name,
|
||||
})),
|
||||
}
|
||||
|
||||
describe('TUI terminal-state snapshots', () => {
|
||||
it('pins resumed conversation, streaming, completion, plans, tokens, and Markdown', async () => {
|
||||
const harness = await setupSnapshot({
|
||||
beforeMount(session) {
|
||||
appendUser(session, 'Explain **snapshot fidelity** with `cells`.')
|
||||
appendAssistant(session, [
|
||||
{ type: 'reasoning', text: 'Compare the terminal state, not write fragments.' },
|
||||
{ type: 'text', text: '## Result\n\n- final viewport\n- semantic styles\n\n> deterministic and reviewable' },
|
||||
], { inputTokens: 12_500, outputTokens: 640 })
|
||||
session.append('todo/write', {
|
||||
todos: [
|
||||
{ content: 'model the terminal', status: 'completed' },
|
||||
{ content: 'capture advanced states', status: 'in_progress' },
|
||||
{ content: 'verify PTY cleanup', status: 'pending' },
|
||||
],
|
||||
})
|
||||
},
|
||||
})
|
||||
await checkpoint('conversation-replay', harness.terminal)
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
appendUser(harness.session, 'Show the live update.')
|
||||
harness.session.append('assistant/chunk', {
|
||||
turn: 2,
|
||||
step: 0,
|
||||
chunk: { type: 'block-start', index: 0, blockType: 'reasoning' },
|
||||
})
|
||||
harness.session.append('assistant/chunk', {
|
||||
turn: 2,
|
||||
step: 0,
|
||||
chunk: { type: 'reasoning-delta', index: 0, text: 'Inspecting width and styles.' },
|
||||
})
|
||||
harness.session.append('assistant/chunk', {
|
||||
turn: 2,
|
||||
step: 0,
|
||||
chunk: { type: 'block-start', index: 1, blockType: 'text' },
|
||||
})
|
||||
harness.session.append('assistant/chunk', {
|
||||
turn: 2,
|
||||
step: 0,
|
||||
chunk: { type: 'text-delta', index: 1, text: 'Streaming **visible state**…' },
|
||||
})
|
||||
})
|
||||
await checkpoint('conversation-streaming', harness.terminal)
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
appendAssistant(harness.session, [
|
||||
{ type: 'reasoning', text: 'Inspecting width and styles.' },
|
||||
{ type: 'text', text: 'Streaming **visible state** is complete.' },
|
||||
], { inputTokens: 800, outputTokens: 120 })
|
||||
harness.session.append('turn/end', { turn: 2, reason: { kind: 'max-tokens' } })
|
||||
})
|
||||
await checkpoint('conversation-complete', harness.terminal)
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins Code Mode run_code with its production presenter', async () => {
|
||||
const harness = await setupSnapshot({ configureContext: configureAdvancedTools })
|
||||
const call = {
|
||||
id: 'code-1',
|
||||
name: 'run_code',
|
||||
arguments: {
|
||||
code: "const first = await tools.bash({ command: 'echo CODE_ONE' })\nconst second = await tools.bash({ command: 'echo CODE_TWO' })\nconsole.log(first, second)\nreturn `${first}+${second}`",
|
||||
},
|
||||
}
|
||||
await renderAfter(harness, () => { appendToolCalls(harness.session, [call]) })
|
||||
await checkpoint('code-mode-pending', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
appendToolResult(harness.session, call.id, [{ type: 'text', text: 'CODE_ONE\n+CODE_TWO' }], {
|
||||
meta: { logs: ['CODE_ONE', 'CODE_TWO', 'combined: CODE_ONE+CODE_TWO'] },
|
||||
})
|
||||
})
|
||||
await checkpoint('code-mode-complete', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins a dynamic workflow with phases, parallel agents, and structured output', async () => {
|
||||
const harness = await setupSnapshot({ configureContext: configureAdvancedTools })
|
||||
const call = {
|
||||
id: 'workflow-1',
|
||||
name: 'workflow',
|
||||
arguments: {
|
||||
meta: {
|
||||
name: 'tui-matrix',
|
||||
description: 'Audit terminal states from independent angles',
|
||||
phases: [
|
||||
{ title: 'Inspect', detail: 'Map renderer branches' },
|
||||
{ title: 'Verify', detail: 'Challenge missing states', provider: 'deepseek', model: 'deepseek-v4-flash' },
|
||||
],
|
||||
},
|
||||
args: { packages: ['ui/tui', 'workflow/tool-workflow'] },
|
||||
script: "phase('Inspect')\nconst reports = await parallel([\n () => agent('Audit layout', { label: 'layout', phase: 'Inspect' }),\n () => agent('Audit lifecycle', { label: 'lifecycle', phase: 'Inspect' }),\n])\nphase('Verify')\nreturn { reports, verdict: 'covered' }",
|
||||
},
|
||||
}
|
||||
await renderAfter(harness, () => { appendToolCalls(harness.session, [call]) })
|
||||
await checkpoint('dynamic-workflow-pending', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
appendToolResult(harness.session, call.id, [{
|
||||
type: 'text',
|
||||
text: 'workflow "tui-matrix" completed (2 agents).\nReturn value:\n{\n "reports": ["layout ok", "lifecycle ok"],\n "verdict": "covered"\n}',
|
||||
}])
|
||||
})
|
||||
await checkpoint('dynamic-workflow-complete', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins cordis inspect, dynamic mount, and unmount cards with production presenters', async () => {
|
||||
const harness = await setupSnapshot({ configureContext: configureAdvancedTools })
|
||||
const calls = [
|
||||
{ id: 'cordis-1', name: 'cordis_inspect', arguments: { what: 'tools' } },
|
||||
{
|
||||
id: 'cordis-2',
|
||||
name: 'cordis_mount',
|
||||
arguments: { code: "return { name: 'snapshot-marker', apply(ctx) { ctx.provide('snapshotMarker', { ready: true }) } }" },
|
||||
},
|
||||
{ id: 'cordis-3', name: 'cordis_unmount', arguments: { id: 'dyn-1' } },
|
||||
]
|
||||
await renderAfter(harness, () => { appendToolCalls(harness.session, calls) })
|
||||
await checkpoint('cordis-tools-pending', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
appendToolResult(harness.session, 'cordis-1', [{ type: 'text', text: '## tools\nrun_code\nworkflow\ncordis_mount\ncordis_unmount' }])
|
||||
appendToolResult(harness.session, 'cordis-2', [{ type: 'text', text: 'mounted dyn-1 (plugin "snapshot-marker", state: active)' }])
|
||||
appendToolResult(harness.session, 'cordis-3', [{ type: 'text', text: 'unmounted dyn-1 (plugin "snapshot-marker")' }])
|
||||
})
|
||||
await checkpoint('cordis-tools-complete', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins terminal, diff, subagent, task, skill, collapsed, and expanded cards', async () => {
|
||||
const harness = await setupSnapshot({
|
||||
tools: ADVANCED_CARD_TOOLS,
|
||||
config: { maxToolOutputLines: 3 },
|
||||
}, { columns: 100, rows: 40 })
|
||||
const calls = [
|
||||
{ id: 'advanced-1', name: 'bash', arguments: { command: 'pnpm run test:coverage' } },
|
||||
{ id: 'advanced-2', name: 'edit', arguments: { file_path: 'src/view.ts' } },
|
||||
{ id: 'advanced-3', name: 'subagent', arguments: { prompt: 'Review renderer ownership and report only gaps.' } },
|
||||
{ id: 'advanced-4', name: 'task_output', arguments: { task_id: 'subagent-7', wait: true } },
|
||||
{ id: 'advanced-5', name: 'skill', arguments: { name: 'dsh-code-review' } },
|
||||
]
|
||||
await renderAfter(harness, () => {
|
||||
appendToolCalls(harness.session, calls)
|
||||
appendToolResult(harness.session, 'advanced-1', [{ type: 'text', text: 'raw process output' }])
|
||||
appendToolResult(harness.session, 'advanced-2', [{ type: 'text', text: 'edit complete' }])
|
||||
appendToolResult(harness.session, 'advanced-3', [{ type: 'text', text: 'The renderer has explicit lifecycle ownership.' }])
|
||||
appendToolResult(harness.session, 'advanced-4', [{ type: 'text', text: 'audit complete\n[status: completed]' }])
|
||||
appendToolResult(harness.session, 'advanced-5', [{ type: 'text', text: 'Loaded review instructions.' }])
|
||||
})
|
||||
await checkpoint('advanced-cards-collapsed', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => { harness.terminal.send('\x0f') })
|
||||
await checkpoint('advanced-cards-expanded', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins a constrained multi-select question and its validation state', async () => {
|
||||
const harness = await setupSnapshot({
|
||||
config: {
|
||||
maxQuestionOptions: 3,
|
||||
questionDialogWidth: 48,
|
||||
questionDialogMaxHeight: 16,
|
||||
},
|
||||
}, { columns: 56, rows: 20 })
|
||||
const controller = new AbortController()
|
||||
const beforeQuestion = harness.terminal.frames
|
||||
const answer = harness.ctx.userInteraction.ask({
|
||||
questions: [{
|
||||
id: 'coverage',
|
||||
header: 'Coverage',
|
||||
question: 'Which advanced TUI states belong in the required matrix?',
|
||||
multiSelect: true,
|
||||
options: [
|
||||
{ label: 'Code Mode', description: 'run_code programs and captured output' },
|
||||
{ label: 'Workflows', description: 'phases and parallel agents' },
|
||||
{ label: 'Cordis tools', description: 'inspect, mount, and unmount' },
|
||||
{ label: 'Compaction', description: 'surface replacement and reflow' },
|
||||
],
|
||||
}],
|
||||
signal: controller.signal,
|
||||
})
|
||||
const rejected = expect(answer).rejects.toMatchObject({ code: 'ASK_ABORTED' })
|
||||
await harness.terminal.waitForFrame(beforeQuestion)
|
||||
await checkpoint('question-dialog', harness.terminal)
|
||||
|
||||
await renderAfter(harness, () => { harness.terminal.send('\r') })
|
||||
await checkpoint('question-dialog-validation', harness.terminal)
|
||||
controller.abort()
|
||||
await rejected
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins compaction surface replacement and narrow-to-wide reflow', async () => {
|
||||
let replacementStart = 0
|
||||
let replacementEnd = 0
|
||||
let replacementSources: number[] = []
|
||||
const harness = await setupSnapshot({
|
||||
tools: ADVANCED_CARD_TOOLS,
|
||||
beforeMount(session) {
|
||||
const user = session.append('user/message', {
|
||||
content: [{ type: 'text', text: 'Old prompt with a long line that exercises wrapping before compaction.' }],
|
||||
source: { kind: 'user' },
|
||||
}, { surfaceOp: 'append' })
|
||||
const assistant = session.append('assistant/message', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
provenance: { provider: 'mock', model: 'deepseek-v4-flash' },
|
||||
content: [{ type: 'tool-call', id: CallId('old-tool'), name: 'bash', arguments: '{}' }],
|
||||
}, { surfaceOp: 'append' })
|
||||
session.append('tool/call', { turn: 1, step: 0, callId: CallId('old-tool'), name: 'bash', arguments: '{}' })
|
||||
const result = session.append('tool/result', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
callId: CallId('old-tool'),
|
||||
content: [{ type: 'text', text: 'obsolete output that must disappear' }],
|
||||
isError: false,
|
||||
}, { surfaceOp: 'append' })
|
||||
replacementStart = user.seq
|
||||
replacementEnd = result.seq
|
||||
replacementSources = [user.seq, assistant.seq, result.seq]
|
||||
},
|
||||
}, { columns: 80, rows: 24 })
|
||||
await checkpoint('surface-before-compaction', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => {
|
||||
harness.session.append('context/message', {
|
||||
content: [{ type: 'text', text: 'Compacted summary: the prior command completed and its details were retired from the active surface.' }],
|
||||
source: { kind: 'plugin', plugin: 'compact' },
|
||||
}, {
|
||||
surfaceOp: { op: 'replace', start: replacementStart, end: replacementEnd },
|
||||
sourceEventSeqs: replacementSources,
|
||||
})
|
||||
harness.terminal.resize(44, 18)
|
||||
})
|
||||
await checkpoint('surface-after-compaction-narrow', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await renderAfter(harness, () => { harness.terminal.resize(104, 30) })
|
||||
await checkpoint('surface-after-compaction-wide', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins help, unknown commands, live errors, turn failures, and terminal restoration', async () => {
|
||||
const harness = await setupSnapshot({}, { columns: 92, rows: 32 })
|
||||
await renderAfter(harness, () => {
|
||||
harness.terminal.send('/help')
|
||||
harness.terminal.send('\r')
|
||||
harness.terminal.send('/unknown-advanced-command')
|
||||
harness.terminal.send('\r')
|
||||
harness.ctx.emit('agent/error', harness.agent, 3, 1, new Error('provider stream failed after partial output'))
|
||||
harness.session.append('turn/end', {
|
||||
turn: 3,
|
||||
reason: { kind: 'error', step: 1, message: 'provider stream failed after partial output' },
|
||||
})
|
||||
harness.session.append('turn/end', {
|
||||
turn: 4,
|
||||
reason: { kind: 'interrupted' },
|
||||
})
|
||||
})
|
||||
await checkpoint('errors-and-help', harness.terminal, { includeScrollback: true })
|
||||
|
||||
await harness.controller.dispose()
|
||||
await harness.terminal.flush()
|
||||
await checkpoint('disposed-terminal', harness.terminal, { includeScrollback: true })
|
||||
await harness.ctx.fiber.dispose()
|
||||
await harness.terminal.dispose()
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
expect([...observedCheckpoints].sort()).toEqual([...CHECKPOINTS].sort())
|
||||
const files = (await readdir(SNAPSHOTS_DIR))
|
||||
.filter(file => file.endsWith('.golden.txt'))
|
||||
.sort()
|
||||
expect(files).toEqual(CHECKPOINTS.map(name => `${name}.golden.txt`).sort())
|
||||
})
|
||||
@@ -1,18 +1,23 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import type { Terminal } from '@earendil-works/pi-tui'
|
||||
import AgentRegistry, { AgentId, type Agent, type AgentStatus } from '@deepseek-ai/dsh-agent'
|
||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, { SessionId, type Session } from '@deepseek-ai/dsh-session'
|
||||
import AgentRegistry, { AgentId, type Agent } from '@deepseek-ai/dsh-agent'
|
||||
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { ToolDefinition } from '@deepseek-ai/dsh-tools'
|
||||
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
||||
import {
|
||||
createTuiChat,
|
||||
mountTui,
|
||||
resolveTuiConfig,
|
||||
type Config,
|
||||
type TuiRuntime,
|
||||
} from '../src/index.ts'
|
||||
import {
|
||||
appendAssistant,
|
||||
appendUser,
|
||||
createTuiTestHarness,
|
||||
disposeTuiTestHarness,
|
||||
type TuiHarnessOptions,
|
||||
} from './harness.ts'
|
||||
|
||||
class FakeTerminal implements Terminal {
|
||||
columns = 88
|
||||
@@ -84,97 +89,23 @@ class FakeTerminal implements Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
interface FakeAgent extends Agent {
|
||||
status: AgentStatus
|
||||
sent: ContentBlock[][]
|
||||
steered: ContentBlock[][]
|
||||
cancelled: string[]
|
||||
}
|
||||
|
||||
async function tick(): Promise<void> {
|
||||
await new Promise(resolve => setTimeout(resolve, 25))
|
||||
}
|
||||
|
||||
async function setup(options: {
|
||||
status?: AgentStatus
|
||||
config?: Config
|
||||
tools?: Record<string, ToolDefinition>
|
||||
beforeMount?: (session: Session) => void
|
||||
cwd?: string | null
|
||||
} = {}) {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(AgentRegistry)
|
||||
await ctx.plugin(UserInteractionService)
|
||||
const tools = options.tools ?? {}
|
||||
ctx.provide('tools', {
|
||||
get(name: string) {
|
||||
return tools[name]
|
||||
},
|
||||
} as never)
|
||||
const session = ctx.sessions.create(
|
||||
SessionId('main-session'),
|
||||
options.cwd === null ? undefined : { meta: { cwd: options.cwd ?? process.cwd() } },
|
||||
)
|
||||
options.beforeMount?.(session)
|
||||
const sent: ContentBlock[][] = []
|
||||
const steered: ContentBlock[][] = []
|
||||
const cancelled: string[] = []
|
||||
const agent: FakeAgent = {
|
||||
id: AgentId('main'),
|
||||
options: { model: 'deepseek-v4-flash' },
|
||||
session,
|
||||
status: options.status ?? 'idle',
|
||||
ctx,
|
||||
sent,
|
||||
steered,
|
||||
cancelled,
|
||||
send(content) {
|
||||
sent.push(content)
|
||||
},
|
||||
steer(content) {
|
||||
steered.push(content)
|
||||
},
|
||||
inject() {},
|
||||
cancel(reason) {
|
||||
cancelled.push(reason ?? '')
|
||||
},
|
||||
whenIdle() {
|
||||
return Promise.resolve()
|
||||
},
|
||||
}
|
||||
ctx.agents.register(agent)
|
||||
async function setup(options: TuiHarnessOptions = {}) {
|
||||
const terminal = new FakeTerminal()
|
||||
const exit = vi.fn()
|
||||
const controller = createTuiChat(ctx, Object.assign({
|
||||
welcome: 'Coding agent ready.',
|
||||
agent: 'main',
|
||||
color: false,
|
||||
}, options.config), { terminal, exit })
|
||||
const result = await createTuiTestHarness(terminal, exit, {
|
||||
...options,
|
||||
cwd: options.cwd === undefined ? process.cwd() : options.cwd,
|
||||
})
|
||||
await tick()
|
||||
return { ctx, session, agent, terminal, exit, controller }
|
||||
return result
|
||||
}
|
||||
|
||||
async function dispose(setupResult: Awaited<ReturnType<typeof setup>>): Promise<void> {
|
||||
await setupResult.controller.dispose()
|
||||
await setupResult.ctx.fiber.dispose()
|
||||
}
|
||||
|
||||
function appendUser(session: Session, text: string): void {
|
||||
session.append('user/message', {
|
||||
content: [{ type: 'text', text }],
|
||||
source: { kind: 'user' },
|
||||
}, { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
function appendAssistant(session: Session, content: ContentBlock[], usage?: { inputTokens: number; outputTokens: number }): void {
|
||||
session.append('assistant/message', {
|
||||
turn: 1,
|
||||
step: 0,
|
||||
provenance: { provider: 'mock', model: 'deepseek-v4-flash' },
|
||||
content,
|
||||
...usage === undefined ? {} : { usage },
|
||||
}, { surfaceOp: 'append' })
|
||||
await disposeTuiTestHarness(setupResult)
|
||||
}
|
||||
|
||||
describe('TUI config', () => {
|
||||
|
||||
Reference in New Issue
Block a user