Merge remote-tracking branch 'origin/master' into worktree/skill-invocation-controls

# Conflicts:
#	docs/cordis-catalog/services.md
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/ui/tui/README.i18n.yaml
This commit is contained in:
Yichen Jiang
2026-07-29 12:58:10 +08:00
313 changed files with 12030 additions and 1864 deletions

View File

@@ -71,6 +71,8 @@ export interface TuiHarnessOptions {
load?(id: ReturnType<typeof SessionId>): Promise<{ meta: SessionHeader; events: Session['events'] }>
}
handoffResume?: TuiRuntime['handoffResume']
/** Host-supplied exit line; absent exercises the no-message path. */
goodbyeMessage?: TuiRuntime['goodbyeMessage']
/** Set false to exercise the optional session-query degradation path. */
mountSessionQuery?: boolean
}
@@ -253,6 +255,7 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
...(options.now === undefined ? {} : { now: options.now }),
...(options.formatCwd === undefined ? {} : { formatCwd: options.formatCwd }),
...(options.handoffResume === undefined ? {} : { handoffResume: options.handoffResume }),
...(options.goodbyeMessage === undefined ? {} : { goodbyeMessage: options.goodbyeMessage }),
gitBranch: options.gitBranch ?? (() => 'tui-staging'),
})
return { ctx, session, agent, terminal, exit, controller }

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=34 bufferRow=34
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,7 +17,7 @@ buffer
6| "● Tool / bash / Run the coverage gate"
style 0-36 fg=green
7| "$ pnpm run test:coverage "
style 0-23 fg=cyan
style 0-23 dim
8| "/workspace/project "
style 0-17 dim
9| "… +4 lines (Ctrl+O to expand) "
@@ -39,11 +39,14 @@ buffer
18| "● Tool / subagent"
style 0-16 fg=green
19| "Delegate renderer audit "
style 0-99 dim
20| "The renderer has explicit lifecycle ownership. "
style 0-99 dim
21| <blank>
22| "● Tool / task_output"
style 0-19 fg=green
23| "Read output from background task subagent-7 "
style 0-99 dim
24| " "
25| "… +2 lines (Ctrl+O to expand) "
style 0-28 dim
@@ -52,18 +55,20 @@ buffer
28| "● Tool / skill"
style 0-13 fg=green
29| "Load skill dsh-code-review "
style 0-99 dim
30| "Loaded review instructions. "
style 0-99 dim
31| "Model wait 0.0s "
style 0-14 dim
32| <blank>
33| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
34| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
35-39| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=39 bufferRow=42
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,13 +17,17 @@ buffer
6| "● Tool / bash / Run the coverage gate"
style 0-36 fg=green
7| "$ pnpm run test:coverage "
style 0-23 fg=cyan
style 0-23 dim
8| "/workspace/project "
style 0-17 dim
9| "packages/ui/tui 100% "
style 0-19 dim
10| "4016 tests passed "
style 0-16 dim
11| "1 test skipped "
style 0-13 dim
12| "coverage complete "
style 0-16 dim
13| "[exit 0] "
style 0-7 dim
14| <blank>
@@ -45,35 +49,42 @@ buffer
23| "● Tool / subagent"
style 0-16 fg=green
24| "Delegate renderer audit "
style 0-99 dim
25| "The renderer has explicit lifecycle ownership. "
style 0-99 dim
26| <blank>
27| "● Tool / task_output"
style 0-19 fg=green
28| "Read output from background task subagent-7 "
style 0-99 dim
29| " "
30| "console "
style 0-6 dim
31| " started background task bash-5 "
style 2-31 fg=cyan
style 0-1 dim
style 2-31 fg=cyan dim
style 32-99 dim
32| " "
33| <blank>
34| "● Tool / skill"
style 0-13 fg=green
35| "Load skill dsh-code-review "
style 0-99 dim
36| "Loaded review instructions. "
style 0-99 dim
37| "Model wait 0.0s "
style 0-14 dim
38| <blank>
39| "Tool cards expanded. "
style 0-19 fg=bright-black
39| "Tool and context cards expanded. "
style 0-31 dim
40| <blank>
41| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
42| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse

View File

@@ -14,7 +14,7 @@ viewport
style 8-8 fg=#2498ff bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -24,13 +24,13 @@ viewport
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
8| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
9-35| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=15 bufferRow=15
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -25,13 +25,13 @@ buffer
style 0-14 dim
13| <blank>
14| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
15| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
16-35| <blank>

View File

@@ -4,19 +4,19 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=18 bufferRow=18
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "Assistant "
style 0-8 fg=bright-magenta bold underline
5| "Reasoning "
style 0-8 fg=bright-black italic
style 0-8 dim italic
6| "Inspecting width and styles. "
style 0-27 fg=bright-black italic
style 0-27 dim italic
7| "Streaming visible state… "
style 10-22 bold
8| " "
@@ -29,17 +29,16 @@ viewport
style 0-30 dim
13| <blank>
14| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
15| "Show the live update. "
16| <blank>
17| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
18| " dsh ● press enter to steer and esc to cancel "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 7-44 dim
style 1-3 fg=bright-magenta bold
style 5-44 dim
19-35| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=21 bufferRow=21
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -33,13 +33,13 @@ buffer
style 0-14 dim
19| <blank>
20| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
21| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
22-35| <blank>

View File

@@ -1,13 +1,13 @@
terminal 92x32 buffer=normal length=38 base=6 viewport=6
terminal 92x32 buffer=normal length=37 base=5 viewport=5
lifecycle started=1 stopped=1 progress=inactive
title "DSH snapshot"
cursor visible column=0 viewportRow=31 bufferRow=37
cursor visible column=0 viewportRow=31 bufferRow=36
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,62 +17,60 @@ buffer
style 0-46 dim
6| <blank>
7| "Keyboard shortcuts "
style 0-17 fg=bright-blue bold
style 0-17 fg=bright-magenta bold
8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
style 0-60 fg=bright-black
9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
style 0-74 fg=bright-black
10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
style 0-72 fg=bright-black
11| " "
12| "/clear — Clear the transcript view (session history is unchanged) "
style 0-64 fg=bright-black
13| "/exit — Exit after the active turn reaches idle "
style 0-46 fg=bright-black
14| "/help — Show keyboard shortcuts and commands "
style 0-43 fg=bright-black
15| "/model [[provider/]model] — Show or switch this session's model "
style 0-62 fg=bright-black
16| "/quit — Exit after the active turn reaches idle "
style 0-46 fg=bright-black
17| "/reasoning — Toggle reasoning blocks "
style 0-35 fg=bright-black
18| "/redraw — Invalidate components and redraw the terminal "
style 0-54 fg=bright-black
style 0-60 dim
9| "Esc cancel turn • Ctrl+O cycle cards (collapse/expand/hide) • Ctrl+R toggle reasoning • "
style 0-91 dim
10| "Ctrl+L redraw "
style 0-12 dim
11| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
style 0-72 dim
12| " "
13| "/clear — Clear the transcript view (session history is unchanged) "
style 0-64 dim
14| "/exit — Exit after the active turn reaches idle "
style 0-46 dim
15| "/help — Show keyboard shortcuts and commands "
style 0-43 dim
16| "/model [[provider/]model] — Show or switch this session's model "
style 0-62 dim
17| "/palette — Show every color and attribute role this terminal renders "
style 0-67 dim
18| "/quit — Exit after the active turn reaches idle "
style 0-46 dim
19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
style 0-87 fg=bright-black
style 0-87 dim
20| "/resume — List this workspace's resumable sessions "
style 0-49 fg=bright-black
style 0-49 dim
21| "/status — Show session diagnostics, system prompt, and registered tools "
style 0-70 fg=bright-black
22| "/tools — Expand or collapse all tool cards "
style 0-41 fg=bright-black
23| "/skill:<name> [instructions] — load a skill into the conversation "
style 0-64 fg=bright-black
24| <blank>
25| "provider stream failed after partial output "
style 0-70 dim
22| "/skill:<name> [instructions] — load a skill into the conversation "
style 0-64 dim
23| <blank>
24| "provider stream failed after partial output "
style 0-42 fg=red
26| <blank>
27| "The previous process ended during this turn. "
25| <blank>
26| "The previous process ended during this turn. "
style 0-43 fg=yellow
28| <blank>
29| "Turn stopped: the agent was disposed. "
27| <blank>
28| "Turn stopped: the agent was disposed. "
style 0-36 fg=yellow
30| <blank>
31| "Turn ended: plugin-policy. "
29| <blank>
30| "Turn ended: plugin-policy. "
style 0-25 fg=yellow
32| <blank>
33| "Unknown command: /unknown-advanced-command "
31| <blank>
32| "Unknown command: /unknown-advanced-command "
style 0-41 fg=yellow
34| <blank>
35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
36| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
33| <blank>
34| "/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
35| " dsh > "
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
37| <blank>
36| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=17 bufferRow=17
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -28,13 +28,13 @@ buffer
style 0-14 dim
15| <blank>
16| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
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 > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
18-35| <blank>

View File

@@ -1,13 +1,13 @@
terminal 92x32 buffer=normal length=37 base=5 viewport=5
terminal 92x32 buffer=normal length=36 base=4 viewport=4
lifecycle started=1 stopped=0 progress=inactive
title "DSH snapshot"
cursor hidden column=7 viewportRow=31 bufferRow=36
cursor hidden column=7 viewportRow=31 bufferRow=35
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,61 +17,59 @@ buffer
style 0-46 dim
6| <blank>
7| "Keyboard shortcuts "
style 0-17 fg=bright-blue bold
style 0-17 fg=bright-magenta bold
8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
style 0-60 fg=bright-black
9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
style 0-74 fg=bright-black
10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
style 0-72 fg=bright-black
11| " "
12| "/clear — Clear the transcript view (session history is unchanged) "
style 0-64 fg=bright-black
13| "/exit — Exit after the active turn reaches idle "
style 0-46 fg=bright-black
14| "/help — Show keyboard shortcuts and commands "
style 0-43 fg=bright-black
15| "/model [[provider/]model] — Show or switch this session's model "
style 0-62 fg=bright-black
16| "/quit — Exit after the active turn reaches idle "
style 0-46 fg=bright-black
17| "/reasoning — Toggle reasoning blocks "
style 0-35 fg=bright-black
18| "/redraw — Invalidate components and redraw the terminal "
style 0-54 fg=bright-black
style 0-60 dim
9| "Esc cancel turn • Ctrl+O cycle cards (collapse/expand/hide) • Ctrl+R toggle reasoning • "
style 0-91 dim
10| "Ctrl+L redraw "
style 0-12 dim
11| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
style 0-72 dim
12| " "
13| "/clear — Clear the transcript view (session history is unchanged) "
style 0-64 dim
14| "/exit — Exit after the active turn reaches idle "
style 0-46 dim
15| "/help — Show keyboard shortcuts and commands "
style 0-43 dim
16| "/model [[provider/]model] — Show or switch this session's model "
style 0-62 dim
17| "/palette — Show every color and attribute role this terminal renders "
style 0-67 dim
18| "/quit — Exit after the active turn reaches idle "
style 0-46 dim
19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
style 0-87 fg=bright-black
style 0-87 dim
20| "/resume — List this workspace's resumable sessions "
style 0-49 fg=bright-black
style 0-49 dim
21| "/status — Show session diagnostics, system prompt, and registered tools "
style 0-70 fg=bright-black
22| "/tools — Expand or collapse all tool cards "
style 0-41 fg=bright-black
23| "/skill:<name> [instructions] — load a skill into the conversation "
style 0-64 fg=bright-black
24| <blank>
25| "provider stream failed after partial output "
style 0-70 dim
22| "/skill:<name> [instructions] — load a skill into the conversation "
style 0-64 dim
23| <blank>
24| "provider stream failed after partial output "
style 0-42 fg=red
26| <blank>
27| "The previous process ended during this turn. "
25| <blank>
26| "The previous process ended during this turn. "
style 0-43 fg=yellow
28| <blank>
29| "Turn stopped: the agent was disposed. "
27| <blank>
28| "Turn stopped: the agent was disposed. "
style 0-36 fg=yellow
30| <blank>
31| "Turn ended: plugin-policy. "
29| <blank>
30| "Turn ended: plugin-policy. "
style 0-25 fg=yellow
32| <blank>
33| "Unknown command: /unknown-advanced-command "
31| <blank>
32| "Unknown command: /unknown-advanced-command "
style 0-41 fg=yellow
34| <blank>
35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
36| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
33| <blank>
34| "/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
35| " dsh > "
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=11 viewportRow=8 bufferRow=8
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,15 +17,15 @@ viewport
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
8| " dsh > @tsc "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 11-11 inverse
9| " → File · terminal-special-case.t src/terminal-special-case.ts "
style 7-38 fg=bright-blue
style 7-38 fg=bright-magenta
10-35| <blank>

View 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=15 viewportRow=13 bufferRow=13
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "Assistant "
style 0-8 fg=bright-magenta bold underline
5| "Model wait 0.0s "
style 0-14 dim
6| <blank>
7| "/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
8| " dsh > "
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
9-11| <blank>
12| " ╭ Select model ────────────────────────────────────────────────────────────╮ "
style 8-83 fg=bright-magenta
13| " │ > pro │ "
style 8-8 fg=bright-magenta
style 15-15 inverse
style 83-83 fg=bright-magenta
14| " │ │ "
style 8-8 fg=bright-magenta
style 83-83 fg=bright-magenta
15| " │ → deepseek/deepseek-v4-pro DeepSeek V4 Pro │ "
style 8-8 fg=bright-magenta
style 10-58 fg=bright-magenta inverse
style 83-83 fg=bright-magenta
16| " │ │ "
style 8-8 fg=bright-magenta
style 83-83 fg=bright-magenta
17| " │ type to filter • ↑/↓ move • Shift+Tab reasoning • Enter select • Esc │ "
style 8-8 fg=bright-magenta
style 10-77 dim
style 83-83 fg=bright-magenta
18| " ╰──────────────────────────────────────────────────────────────────────────╯ "
style 8-83 fg=bright-magenta
19-31| <blank>

View File

@@ -1,13 +1,13 @@
terminal 92x32 buffer=normal length=32 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH snapshot"
cursor hidden column=0 viewportRow=31 bufferRow=31
cursor hidden column=12 viewportRow=13 bufferRow=13
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,33 +17,40 @@ buffer
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
8| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
9-12| <blank>
13| " ╭ Select model ────────────────────────────────────────────────────────────╮ "
style 8-83 fg=bright-blue
14| " │ → deepseek/deepseek-v4-flash DeepSeek V4 Flash — current │ "
style 8-8 fg=bright-blue
style 10-70 fg=bright-blue inverse
style 83-83 fg=bright-blue
15| " │ deepseek/deepseek-v4-pro DeepSeek V4 Pro │ "
style 8-8 fg=bright-blue
style 36-58 fg=bright-black
style 83-83 fg=bright-blue
16| " │ │ "
style 8-8 fg=bright-blue
style 83-83 fg=bright-blue
17| " │ ↑/↓ navigate • Shift+Tab reasoning • Enter select • Esc cancel │ "
style 8-8 fg=bright-blue
style 10-71 dim
style 83-83 fg=bright-blue
18| " ╰──────────────────────────────────────────────────────────────────────────╯ "
style 8-83 fg=bright-blue
19-31| <blank>
9-11| <blank>
12| " ╭ Select model ────────────────────────────────────────────────────────────╮ "
style 8-83 fg=bright-magenta
13| " │ > │ "
style 8-8 fg=bright-magenta
style 12-12 inverse
style 83-83 fg=bright-magenta
14| " │ │ "
style 8-8 fg=bright-magenta
style 83-83 fg=bright-magenta
15| " │ → deepseek/deepseek-v4-flash DeepSeek V4 Flash — current │ "
style 8-8 fg=bright-magenta
style 10-70 fg=bright-magenta inverse
style 83-83 fg=bright-magenta
16| " │ deepseek/deepseek-v4-pro DeepSeek V4 Pro │ "
style 8-8 fg=bright-magenta
style 36-58 dim
style 83-83 fg=bright-magenta
17| " │ │ "
style 8-8 fg=bright-magenta
style 83-83 fg=bright-magenta
18| " │ type to filter • ↑/↓ move • Shift+Tab reasoning • Enter select • Esc │ "
style 8-8 fg=bright-magenta
style 10-77 dim
style 83-83 fg=bright-magenta
19| " ╰──────────────────────────────────────────────────────────────────────────╯ "
style 8-83 fg=bright-magenta
20-31| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=10 bufferRow=10
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,16 +17,16 @@ buffer
style 0-14 dim
6| <blank>
7| "Model selected: deepseek/deepseek-v4-pro. New steps will use it. "
style 0-63 fg=bright-black
style 0-63 dim
8| <blank>
9| "/workspace/project (tui-staging) deepseek-v4-pro ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-48 fg=bright-black
style 51-55 fg=bright-black
style 58-67 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-48 dim
style 51-55 dim
style 58-67 dim
10| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
11-31| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=0 viewportRow=19 bufferRow=19
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,23 +17,23 @@ viewport
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 "
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-55 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-55 dim
8| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
9-11| <blank>
12| " "
13| " Question 1/1 (1 unanswered) · Confirm "
style 2-38 fg=bright-black
style 2-38 dim
14| " Continue with this change? "
15| " "
16| " › 1. Proceed Apply the proposed change "
style 2-13 fg=bright-blue bold
style 16-40 fg=bright-black
style 2-13 fg=bright-magenta bold
style 16-40 dim
17| " Tab custom answer • Enter submit • Esc interrupt "
style 2-49 dim
18| " "

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=56 viewportRow=17 bufferRow=17
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -15,17 +15,17 @@ viewport
style 0-8 fg=bright-magenta bold underline
5| " "
6| " Question 1/3 (3 unanswered) · Coverage "
style 2-39 fg=bright-black
style 2-39 dim
7| " Which advanced TUI states belong in the required "
8| " matrix? "
9| " "
10| " › 1. [ ] Code Mode run_code programs and capture "
style 2-19 fg=bright-blue bold
style 25-53 fg=bright-black
style 2-19 fg=bright-magenta bold
style 25-53 dim
11| " 2. [ ] Workflows phases and parallel agents "
style 25-50 fg=bright-black
style 25-50 dim
12| " 3. [ ] Cordis tools inspect, mount, and unmount "
style 25-51 fg=bright-black
style 25-51 dim
13| " 1/4 "
style 2-4 dim
14| " Tab custom answer • ↑/↓ navigate • Space toggle • "

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=0 viewportRow=19 bufferRow=19
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -18,17 +18,17 @@ viewport
6| <blank>
7| " "
8| " Question 1/3 (3 unanswered) · Coverage "
style 2-39 fg=bright-black
style 2-39 dim
9| " Which advanced TUI states belong in the required "
10| " matrix? "
11| " "
12| " › 1. [ ] Code Mode run_code programs and capture "
style 2-19 fg=bright-blue bold
style 25-53 fg=bright-black
style 2-19 fg=bright-magenta bold
style 25-53 dim
13| " 2. [ ] Workflows phases and parallel agents "
style 25-50 fg=bright-black
style 25-50 dim
14| " 3. [ ] Cordis tools inspect, mount, and unmount "
style 25-51 fg=bright-black
style 25-51 dim
15| " 1/4 "
style 2-4 dim
16| " Tab custom answer • ↑/↓ navigate • Space toggle • "

View File

@@ -0,0 +1,57 @@
terminal 92x32 buffer=normal length=32 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH snapshot"
cursor hidden column=6 viewportRow=4 bufferRow=4
buffer
0| " "
1| " Resume session (1 of 3) "
style 2-24 fg=bright-magenta bold
2| " "
3| " ╭──────────────────────────────────────────────────────────────────────────────────────╮ "
style 2-89 dim
4| " │ ⌕ │ "
style 2-2 dim
style 6-6 inverse
style 89-89 dim
5| " ╰──────────────────────────────────────────────────────────────────────────────────────╯ "
style 2-89 dim
6| " "
7| " all workspaces (3) ⇥ this workspace (2) "
style 2-19 fg=bright-magenta
style 20-41 dim
8| " "
9| " ❯ Untitled session "
style 2-19 fg=bright-magenta bold
10| " 2026-07-23T08:00:00.000Z · no completed turn · route unavailable "
style 2-67 dim
11| " current · live · main-session "
style 2-32 dim
12| " workspace /workspace/project "
style 2-31 dim
13| " unavailable: current session "
style 2-31 fg=yellow
14| " Other workspace work "
15| " 2024-02-02T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
style 2-74 dim
16| " persisted · elsewhere-session "
style 2-32 dim
17| " workspace /workspace/other "
style 2-29 dim
18| " Resume selector design "
19| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
style 2-74 dim
20| " persisted · earlier-session "
style 2-30 dim
21| " workspace /workspace/project "
style 2-31 dim
22| " "
23| " "
24| " "
25| " "
26| " "
27| " "
28| " "
29| " "
30| " Type to search • ↑/↓ navigate • Tab scope • Enter resume • Esc clear/cancel "
style 2-84 dim
31| " "

View File

@@ -5,7 +5,7 @@ cursor hidden column=6 viewportRow=4 bufferRow=4
buffer
0| " "
1| " Resume session (1 of 2) "
style 2-24 fg=bright-blue bold
style 2-24 fg=bright-magenta bold
2| " "
3| " ╭──────────────────────────────────────────────────────────────────────────────────────╮ "
style 2-89 dim
@@ -16,20 +16,21 @@ buffer
5| " ╰──────────────────────────────────────────────────────────────────────────────────────╯ "
style 2-89 dim
6| " "
7| " /workspace/project "
style 2-19 fg=bright-black
7| " this workspace /workspace/project ⇥ all workspaces (3) "
style 2-34 fg=bright-magenta
style 35-56 dim
8| " "
9| " ❯ Untitled session "
style 2-19 fg=bright-blue bold
style 2-19 fg=bright-magenta bold
10| " 2026-07-23T08:00:00.000Z · no completed turn · route unavailable "
style 2-67 fg=bright-black
style 2-67 dim
11| " current · live · main-session "
style 2-32 dim
12| " unavailable: current session "
style 2-31 fg=yellow
13| " Resume selector design "
14| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
style 2-74 fg=bright-black
style 2-74 dim
15| " persisted · earlier-session "
style 2-30 dim
16| " "
@@ -46,6 +47,6 @@ buffer
27| " "
28| " "
29| " "
30| " Type to search • ↑/↓ navigate • Enter resume • Esc clear/cancel "
style 2-70 dim
30| " Type to search • ↑/↓ navigate • Tab scope • Enter resume • Esc clear/cancel "
style 2-84 dim
31| " "

View File

@@ -4,15 +4,15 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=12 bufferRow=12
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
5| "Start then cancel. "
6| <blank>
7| "Retrying model request (1/∞) in 1000ms: temporary transport failure "
@@ -22,13 +22,13 @@ buffer
style 0-14 fg=yellow
10| <blank>
11| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
12| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
13-35| <blank>

View File

@@ -4,28 +4,28 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=10 bufferRow=10
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
5| "Let the bounded policy exhaust. "
6| <blank>
7| "provider still unavailable "
style 0-25 fg=red
8| <blank>
9| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
10| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
11-35| <blank>

View File

@@ -4,28 +4,28 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=10 bufferRow=10
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
5| "Recover this request. "
6| <blank>
7| "Retrying model request (1/2) in 500ms: provider rate limit "
style 0-57 fg=yellow
8| <blank>
9| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
10| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
11-35| <blank>

View File

@@ -4,28 +4,28 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=10 bufferRow=10
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
5| "Recover this request. "
6| <blank>
7| "Retrying model request (1/2) in 500ms: provider rate limit "
style 0-57 fg=yellow
8| <blank>
9| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
10| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
11-35| <blank>

View File

@@ -4,15 +4,15 @@ title "DSH session reference"
cursor hidden column=7 viewportRow=14 bufferRow=14
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Session reference snapshot."
style 1-27 fg=bright-black
style 1-27 dim
2| " target-session"
style 1-14 dim
3| <blank>
4| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
5| "Use @Source session "
6| <blank>
7| "Referenced sessions · Source session (source-session) "
@@ -25,11 +25,11 @@ buffer
style 0-46 dim
12| <blank>
13| "/workspace/project mock ↑0 ↓0"
style 0-17 fg=bright-blue bold
style 20-23 fg=bright-black
style 26-30 fg=bright-black
style 0-17 fg=bright-magenta bold
style 20-23 dim
style 26-30 dim
14| " dsh ◍ "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
15-23| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=14 viewportRow=8 bufferRow=8
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,15 +17,15 @@ viewport
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
8| " dsh > @design "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 14-14 inverse
9| " → Session · Searchable design re opaque-source-id · /workspace/project · 1970-01-01T0 "
style 7-38 fg=bright-blue
style 7-38 fg=bright-magenta
10-35| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=38 viewportRow=13 bufferRow=13
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -17,9 +17,9 @@ viewport
style 0-14 dim
6| <blank>
7| "/workspace/project (tui-staging) deepseek-v"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-43 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-43 dim
8| " ↑ 1 more "
style 1-14 dim
9| " enough detail to wrap across multiple "

View File

@@ -4,10 +4,10 @@ title "Inspect session diagnostics — DSH snapshot"
cursor hidden column=7 viewportRow=35 bufferRow=43
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Inspect session diagnostics"
style 1-27 fg=bright-black
style 1-27 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -18,28 +18,28 @@ buffer
style 0-14 dim
7| <blank>
8| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
9| "inspect this session "
10| <blank>
11| "╭─ Session status ─────────────────────────────────────╮"
style 0-2 dim
style 3-16 fg=bright-blue bold
style 3-16 fg=bright-magenta bold
style 17-55 dim
12| "│ Session: main-session │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
13| "│ Title: Inspect session diagnostics │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
14| "│ Directory: /workspace/project │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
15| "│ Model: deepseek/deepseek-v4-pro (effort │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 40-55 dim
16| "│ default; reasoning blocks shown) │"
style 0-0 dim
@@ -50,7 +50,7 @@ buffer
style 55-55 dim
18| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
19| "│ tool call │"
style 0-0 dim
@@ -60,13 +60,13 @@ buffer
style 55-55 dim
21| "│ Tokens: 1,250 input + 340 output │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
22| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 15-15 dim
style 16-26 fg=bright-blue
style 16-26 fg=bright-magenta
style 27-32 dim
style 55-55 dim
23| "│ + 250 write) │"
@@ -74,9 +74,9 @@ buffer
style 55-55 dim
24| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 15-15 dim
style 16-20 fg=bright-blue
style 16-20 fg=bright-magenta
style 21-32 dim
style 55-55 dim
25| "│ 128,000) │"
@@ -87,17 +87,17 @@ buffer
style 55-55 dim
27| "│ Created: 2026-07-22 09:10:11 UTC │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
28| "│ Active: 2026-07-22 09:10:11 UTC │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 55-55 dim
29| "╰──────────────────────────────────────────────────────╯"
style 0-55 dim
30| <blank>
31| "System prompt "
style 0-12 fg=bright-blue bold
style 0-12 fg=bright-magenta bold
32| "You are an AI agent powered by the DeepSeek Harness SDK."
33| " "
34| "Paths prefixed with @ are files explicitly referenced by"
@@ -106,15 +106,15 @@ buffer
37| "reading it. "
38| <blank>
39| "Registered tools "
style 0-15 fg=bright-blue bold
style 0-15 fg=bright-magenta bold
40| "read, write "
41| <blank>
42| "/workspace/project (tui-staging) deepseek-v4-pro ↑1.3k"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-48 fg=bright-black
style 51-55 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-48 dim
style 51-55 dim
43| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse

View File

@@ -4,10 +4,10 @@ title "Inspect session diagnostics — DSH snapshot"
cursor hidden column=7 viewportRow=31 bufferRow=37
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Inspect session diagnostics"
style 1-27 fg=bright-black
style 1-27 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -18,28 +18,28 @@ buffer
style 0-14 dim
7| <blank>
8| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
9| "inspect this session "
10| <blank>
11| "╭─ Session status ───────────────────────────────────────────────────────────────╮"
style 0-2 dim
style 3-16 fg=bright-blue bold
style 3-16 fg=bright-magenta bold
style 17-81 dim
12| "│ Session: main-session │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
13| "│ Title: Inspect session diagnostics │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
14| "│ Directory: /workspace/project │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
15| "│ Model: deepseek/deepseek-v4-pro (effort default; reasoning blocks shown) │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 40-79 dim
style 81-81 dim
16| "│ │"
@@ -47,27 +47,27 @@ buffer
style 81-81 dim
17| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 tool call │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
18| "│ │"
style 0-0 dim
style 81-81 dim
19| "│ Tokens: 1,250 input + 340 output │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
20| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read + 250 write) │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 15-15 dim
style 16-26 fg=bright-blue
style 16-26 fg=bright-magenta
style 27-32 dim
style 81-81 dim
21| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / 128,000) │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 15-15 dim
style 16-20 fg=bright-blue
style 16-20 fg=bright-magenta
style 21-32 dim
style 81-81 dim
22| "│ │"
@@ -75,33 +75,33 @@ buffer
style 81-81 dim
23| "│ Created: 2026-07-22 09:10:11 UTC │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
24| "│ Active: 2026-07-22 09:10:11 UTC │"
style 0-0 dim
style 3-12 fg=bright-black
style 3-12 dim
style 81-81 dim
25| "╰────────────────────────────────────────────────────────────────────────────────╯"
style 0-81 dim
26| <blank>
27| "System prompt "
style 0-12 fg=bright-blue bold
style 0-12 fg=bright-magenta bold
28| "You are an AI agent powered by the DeepSeek Harness SDK. "
29| " "
30| "Paths prefixed with @ are files explicitly referenced by the user. Use the read tool when "
31| "their contents are needed; do not claim to have inspected a file before reading it. "
32| <blank>
33| "Registered tools "
style 0-15 fg=bright-blue bold
style 0-15 fg=bright-magenta bold
34| "read, write "
35| <blank>
36| "/workspace/project (tui-staging) deepseek-v4-pro ↑1.3k ↓340 cache 67% 33% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-48 fg=bright-black
style 51-71 fg=bright-black
style 74-84 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-48 dim
style 51-71 dim
style 74-84 dim
37| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse

View File

@@ -4,31 +4,31 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=11 bufferRow=11
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
4| "Assistant "
style 0-8 fg=bright-magenta bold underline
5| "Reasoning "
style 0-8 fg=bright-black italic
style 0-8 dim italic
6| "Checking the result. "
style 0-19 fg=bright-black italic
style 0-19 dim italic
7| "The result is ready. "
8| "Model wait 1.0s · Thinking 2.0s · Response 3.0s · Completed 2026-07-21 14:32:12 "
style 0-78 dim
9| <blank>
10| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
11| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
12-35| <blank>

View File

@@ -1,13 +1,13 @@
terminal 44x18 buffer=normal length=18 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH snapshot"
cursor hidden column=7 viewportRow=15 bufferRow=15
cursor hidden column=7 viewportRow=14 bufferRow=14
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -16,21 +16,22 @@ buffer
5| "Model wait 0.0s "
style 0-14 dim
6| <blank>
7| "Context · workspace-context "
7| "Context · workspace-context"
style 0-26 dim
8| "system-reminder "
style 0-14 fg=bright-black
9| " Additional instructions from: "
10| "nested/AGENTS.md "
11| " "
12| " Render workspace context XML clearly. "
13| <blank>
14| "/workspace/project (tui-staging) deepseek-v"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-43 fg=bright-black
15| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
8| "Additional instructions from: "
style 0-43 dim
9| "nested/AGENTS.md "
style 0-15 dim
10| " "
11| "Render workspace context XML clearly. "
style 0-36 dim
12| <blank>
13| "/workspace/project (tui-staging) deepseek-v"
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-43 dim
14| " dsh > "
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
16-17| <blank>
15-17| <blank>

View File

@@ -1,13 +1,13 @@
terminal 104x30 buffer=normal length=30 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH snapshot"
cursor hidden column=7 viewportRow=14 bufferRow=14
cursor hidden column=7 viewportRow=13 bufferRow=13
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -16,22 +16,22 @@ buffer
5| "Model wait 0.0s "
style 0-14 dim
6| <blank>
7| "Context · workspace-context "
7| "Context · workspace-context"
style 0-26 dim
8| "system-reminder "
style 0-14 fg=bright-black
9| " Additional instructions from: nested/AGENTS.md "
10| " "
11| " Render workspace context XML clearly. "
12| <blank>
13| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
14| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
8| "Additional instructions from: nested/AGENTS.md "
style 0-45 dim
9| " "
10| "Render workspace context XML clearly. "
style 0-36 dim
11| <blank>
12| "/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
13| " dsh > "
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
15-29| <blank>
14-29| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=20 bufferRow=20
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -15,33 +15,36 @@ buffer
style 0-8 fg=bright-magenta bold underline
5| <blank>
6| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
7| "Old prompt with a long line that exercises wrapping before compaction. "
8| <blank>
9| "● Tool / bash / Run the coverage gate"
style 0-36 fg=green
10| "$ pnpm run test:coverage "
style 0-23 fg=cyan
style 0-23 dim
11| "/workspace/project "
style 0-17 dim
12| "packages/ui/tui 100% "
style 0-19 dim
13| "… +1 lines (Ctrl+O to expand) "
style 0-28 dim
14| "1 test skipped "
style 0-13 dim
15| "coverage complete "
style 0-16 dim
16| "[exit 0] "
style 0-7 dim
17| "Model wait 0.0s "
style 0-14 dim
18| <blank>
19| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
20| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
21-23| <blank>

View File

@@ -4,10 +4,10 @@ title "DSH snapshot"
cursor hidden column=7 viewportRow=15 bufferRow=15
viewport
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Snapshot agent ready."
style 1-21 fg=bright-black
style 1-21 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -18,21 +18,21 @@ viewport
style 0-46 dim
7| <blank>
8| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
9| "Plan the work. "
10| <blank>
11| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
12| "Next question. "
13| <blank>
14| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
15| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
16-35| <blank>

View File

@@ -4,10 +4,10 @@ title "Unsafe terminal title \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
cursor hidden column=0 viewportRow=33 bufferRow=33
buffer
0| " DEEPSEEK HARNESS"
style 1-8 fg=bright-blue bold
style 1-8 fg=bright-magenta bold
style 10-16 bold
1| " Unsafe welcome \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
style 1-60 fg=bright-black
style 1-60 dim
2| " main-session"
style 1-12 dim
3| <blank>
@@ -15,51 +15,52 @@ buffer
style 0-8 fg=bright-magenta bold underline
5| <blank>
6| "You "
style 0-2 fg=bright-blue bold underline
style 0-2 fg=bright-magenta bold underline
7| "Unsafe user \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
8| <blank>
9| "● Tool / unsafe / Unsafe description \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
style 0-81 fg=green
10| "$ Unsafe title \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 0-59 fg=cyan
style 0-59 dim
11| "/unsafe/\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 0-52 dim
12| "Unsafe output \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 0-58 dim
13| "[signal SIG\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m] "
style 0-56 fg=red
14| "Model wait 0.0s · Completed 2026-07-21 15:00:00 "
style 0-46 dim
15| <blank>
16| "Context · unsafe-\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
16| "Context · unsafe-\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
style 0-61 dim
17| "Unsafe context \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 0-59 fg=bright-black
style 0-59 dim
18| <blank>
19| "Unsafe turn error \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 0-62 fg=red
20-21| <blank>
22| "Plan"
style 0-3 fg=bright-blue bold
style 0-3 fg=bright-magenta bold
23| " ● Unsafe todo \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
style 2-2 fg=yellow
24| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
style 0-17 fg=bright-blue bold
style 18-31 fg=bright-black
style 34-50 fg=bright-black
style 53-57 fg=bright-black
style 60-69 fg=bright-black
style 0-17 fg=bright-magenta bold
style 18-31 dim
style 34-50 dim
style 53-57 dim
style 60-69 dim
25| " dsh > "
style 1-3 fg=bright-blue bold
style 5-6 fg=bright-black
style 1-3 fg=bright-magenta bold
style 5-6 dim
style 7-7 inverse
26| " "
27| " Question 1/1 (1 unanswered) · Unsafe header \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
style 2-90 fg=bright-black
style 2-90 dim
28| " Unsafe question \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
29| " "
30| " › 1. Unsafe option \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m Unsafe detail \\x1b]2;snapshot-c "
style 2-65 fg=bright-blue bold
style 67-97 fg=bright-black
style 2-65 fg=bright-magenta bold
style 67-97 dim
31| " Tab custom answer • Enter submit • Esc interrupt "
style 2-49 dim
32| " "

View File

@@ -7,7 +7,7 @@ import type { Context } from 'cordis'
import { agentEvents } from '@deepseek-ai/dsh-agent'
import { createUserMessage, CallId, type ContentBlock , createMessage, createToolResultMessage } from '@deepseek-ai/dsh-llm'
import type {} from '@deepseek-ai/dsh-llm-retry'
import { SessionId, type JsonValue, type Session } from '@deepseek-ai/dsh-session'
import { SessionId, type JsonValue, type Session, type SessionEvent } from '@deepseek-ai/dsh-session'
import SessionReferenceService from '@deepseek-ai/dsh-session-reference'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry, { type ToolDefinition, type ToolResultView } from '@deepseek-ai/dsh-tools'
@@ -51,10 +51,12 @@ const CHECKPOINTS = [
'surface-after-compaction-narrow',
'surface-after-compaction-wide',
'model-selector',
'model-selector-filtered',
'model-switching',
'errors-and-help',
'disposed-terminal',
'resume-sessions',
'resume-sessions-all-workspaces',
'status-diagnostics',
'status-diagnostics-narrow',
'todo-plan-cleared',
@@ -801,6 +803,10 @@ describe('TUI terminal-state snapshots', () => {
harness.terminal.send('\r')
})
await checkpoint('model-selector', harness.terminal, { includeScrollback: true })
await renderAfter(harness, () => {
harness.terminal.send('pro')
})
await checkpoint('model-selector-filtered', harness.terminal, { includeScrollback: true })
await renderAfter(harness, () => {
harness.terminal.send('\x1b[B')
harness.terminal.send('\r')
@@ -812,35 +818,33 @@ describe('TUI terminal-state snapshots', () => {
it('opens the searchable resume selector with log-backed session summaries', async () => {
const dateNow = vi.spyOn(Date, 'now').mockReturnValue(Date.parse('2026-07-23T08:00:00.000Z'))
const earlier = { version: 0, id: SessionId('earlier-session'), createdAt: Date.parse('2024-01-01T00:00:00Z'), cwd: '/workspace/project' }
const elsewhere = { version: 0, id: SessionId('elsewhere-session'), createdAt: Date.parse('2024-02-02T00:00:00Z'), cwd: '/workspace/other' }
const log = (meta: typeof earlier, title: string, day: string): { meta: typeof earlier; events: SessionEvent[] } => ({
meta,
events: [
{ type: 'turn/start', seq: 0, time: Date.parse(`${day}T00:00:01Z`), data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } },
{ type: 'user/message', seq: 1, time: Date.parse(`${day}T00:00:02Z`), data: createUserMessage({ content: [{ type: 'text', text: 'restore the selector' }], source: { kind: 'user' } }), surfaceOp: 'append' },
{ type: 'step/start', seq: 2, time: Date.parse(`${day}T00:00:03Z`), data: { turn: 1, step: 1 } },
{ type: 'request/header', seq: 3, time: Date.parse(`${day}T00:00:04Z`), data: { header: { config: { provider: 'deepseek', model: 'deepseek-v4-pro' } }, reason: 'initial' } },
{ type: 'assistant/message', seq: 4, time: Date.parse(`${day}T00:00:05Z`), data: {
turn: 1, step: 1,
message: createMessage({
role: 'assistant',
content: [{ type: 'text', text: 'ready' }],
source: { kind: 'model', provider: 'deepseek', model: 'deepseek-v4-pro' },
}),
}, surfaceOp: 'append' },
{ type: 'step/end', seq: 5, time: Date.parse(`${day}T00:00:06Z`), data: { turn: 1, step: 1 } },
{ type: 'turn/end', seq: 6, time: Date.parse(`${day}T00:00:07Z`), data: { turn: 1, reason: { kind: 'completed' } } },
{ type: 'session/title', seq: 7, time: Date.parse(`${day}T00:00:08Z`), data: { title, messageSeqs: [1], source: { kind: 'fallback' } } },
],
})
const harness = await setupSnapshot({
config: { resumeCommand: 'dsh --resume {session}' },
sessionPersistence: {
list: async () => [earlier],
load: async () => ({
meta: earlier,
events: [
{ type: 'turn/start', seq: 0, time: Date.parse('2024-01-01T00:00:01Z'), data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } },
{ type: 'user/message', seq: 1, time: Date.parse('2024-01-01T00:00:02Z'), data: createUserMessage({
content: [{ type: 'text', text: 'restore the selector' }], source: { kind: 'user' },
}), surfaceOp: 'append' },
{ type: 'step/start', seq: 2, time: Date.parse('2024-01-01T00:00:03Z'), data: { turn: 1, step: 1 } },
{ type: 'request/header', seq: 3, time: Date.parse('2024-01-01T00:00:04Z'), data: { header: { config: { provider: 'deepseek', model: 'deepseek-v4-pro' } }, reason: 'initial' } },
{ type: 'assistant/message', seq: 4, time: Date.parse('2024-01-01T00:00:05Z'), data: {
turn: 1, step: 1,
message: createMessage({
role: 'assistant',
content: [{ type: 'text', text: 'ready' }],
source: {
kind: 'model',
...{ provider: 'deepseek', model: 'deepseek-v4-pro' },
},
}),
}, surfaceOp: 'append' },
{ type: 'step/end', seq: 5, time: Date.parse('2024-01-01T00:00:06Z'), data: { turn: 1, step: 1 } },
{ type: 'turn/end', seq: 6, time: Date.parse('2024-01-01T00:00:07Z'), data: { turn: 1, reason: { kind: 'completed' } } },
{ type: 'session/title', seq: 7, time: Date.parse('2024-01-01T00:00:08Z'), data: { title: 'Resume selector design', messageSeqs: [1], source: { kind: 'fallback' } } },
],
}),
list: async () => [earlier, elsewhere],
load: async id => id === elsewhere.id
? log(elsewhere, 'Other workspace work', '2024-02-02')
: log(earlier, 'Resume selector design', '2024-01-01'),
},
}, { columns: 92, rows: 32 })
harness.terminal.send('/resume')
@@ -850,6 +854,12 @@ describe('TUI terminal-state snapshots', () => {
await new Promise(resolve => setTimeout(resolve, 60))
await harness.terminal.flush()
await checkpoint('resume-sessions', harness.terminal, { includeScrollback: true })
// Tab switches to the all-workspaces scope, which adds the other workspace's
// session and labels every row with the directory it belongs to.
harness.terminal.send('\t')
await new Promise(resolve => setTimeout(resolve, 60))
await harness.terminal.flush()
await checkpoint('resume-sessions-all-workspaces', harness.terminal, { includeScrollback: true })
await disposeSnapshot(harness)
dateNow.mockRestore()
})

View File

@@ -36,6 +36,7 @@ import {
type TuiRuntime,
} from '../src/index.ts'
import { WorkspaceFileSearch } from '../src/chat/file-autocomplete.ts'
import { ATTRIBUTE_ROLES, COLOR_ROLES, paletteSpec } from '../src/components/theme.ts'
import {
appendAssistant,
appendUser,
@@ -180,7 +181,7 @@ describe('TUI config', () => {
color: true,
truecolor: false,
leftPrompt: '${cwd}${git/worktree}${model}${token_meter/cache_hit_rate}${context}',
rightPrompt: '${timing}',
rightPrompt: '${queued}',
inputPrompt: '${symbol} ${indicator}',
inputPlaceholder: 'press enter to steer and esc to cancel',
},
@@ -220,7 +221,7 @@ describe('TUI config', () => {
color: false,
truecolor: true,
leftPrompt: '${cwd}${git/worktree}${model}${token_meter/cache_hit_rate}${context}',
rightPrompt: '${timing}',
rightPrompt: '${queued}',
inputPrompt: '${symbol} ${indicator}',
inputPlaceholder: 'press enter to steer and esc to cancel',
},
@@ -229,8 +230,7 @@ describe('TUI config', () => {
})
})
describe('resume command and /resume', () => {
const RESUME = 'dsh --resume {session}'
describe('goodbye message and /resume', () => {
const header = (id: string, createdAt: number, cwd: string): SessionHeader =>
({ version: 0, id: SessionId(id), createdAt, cwd })
const resumeEvents = (
@@ -261,11 +261,10 @@ describe('resume command and /resume', () => {
{ type: 'session/title', seq: 7, time: time + 7, data: { title, messageSeqs: [1], source: { kind: 'fallback' } } },
]
it('prints the resume command on exit once the session is persisted', async () => {
it('prints the host goodbye message on exit', async () => {
const result = await setup({
cwd: '/workspace',
config: { resumeCommand: RESUME },
sessionPersistence: { list: async () => [header('main-session', 1000, '/workspace')] },
goodbyeMessage: 'To resume this session: dsh --resume main-session',
})
result.terminal.send('/exit')
result.terminal.send('\r')
@@ -275,8 +274,8 @@ describe('resume command and /resume', () => {
await dispose(result)
})
it('omits the exit hint when the session is not yet persisted', async () => {
const result = await setup({ cwd: '/workspace', config: { resumeCommand: RESUME } })
it('prints nothing on exit when the host supplies no goodbye message', async () => {
const result = await setup({ cwd: '/workspace' })
result.terminal.send('/exit')
result.terminal.send('\r')
await tick()
@@ -285,17 +284,16 @@ describe('resume command and /resume', () => {
await dispose(result)
})
it('omits the exit hint when the session listing fails', async () => {
it('escapes terminal controls in the host goodbye message', async () => {
const result = await setup({
cwd: '/workspace',
config: { resumeCommand: RESUME },
sessionPersistence: { list: () => Promise.reject(new Error('disk gone')) },
goodbyeMessage: 'resume \u001b]2;hijacked\u0007now',
})
result.terminal.send('/exit')
result.terminal.send('\r')
await tick()
expect(result.terminal.output).not.toContain('To resume this session')
expect(result.exit).toHaveBeenCalledWith(0)
expect(result.terminal.output).toContain('resume \\x1b]2;hijacked\\x07now')
expect(result.terminal.output).not.toContain('\u001b]2;hijacked')
await dispose(result)
})
@@ -305,7 +303,6 @@ describe('resume command and /resume', () => {
const handoff = vi.fn<NonNullable<TuiRuntime['handoffResume']>>()
const result = await setup({
cwd: '/workspace',
config: { resumeCommand: RESUME },
handoffResume: handoff,
sessionPersistence: {
list: async () => [older, newer, header('foreign-session', 3000, '/elsewhere')],
@@ -323,7 +320,10 @@ describe('resume command and /resume', () => {
expect(output).toContain('Older investigation')
expect(output).toContain('current · live')
expect(output.indexOf('Newer product work')).toBeLessThan(output.indexOf('Older investigation'))
// Default scope is the current workspace; one of the four records (three
// listed plus the live current session) belongs to another.
expect(output).not.toContain('foreign-session')
expect(output).toContain('all workspaces (4)')
result.terminal.send('Older')
await tick()
expect(result.terminal.output).toContain('⌕ Older')
@@ -351,7 +351,9 @@ describe('resume command and /resume', () => {
await tick(); await tick()
result.terminal.send('\x1b[B')
result.terminal.send('\x1b[A')
result.terminal.send('\t')
// A key the search editor swallows without changing its value (backspace on
// an empty box) keeps the selection and error untouched.
result.terminal.send('\x7f')
result.terminal.send('zz')
result.terminal.send('\r')
await tick()
@@ -602,7 +604,6 @@ describe('resume command and /resume', () => {
const corrupt = header('corrupt', 30, '/workspace')
const result = await setup({
cwd: '/workspace',
config: { resumeCommand: RESUME },
sessionPersistence: {
list: async () => [missing, corrupt],
load: async (id) => {
@@ -683,7 +684,7 @@ describe('resume command and /resume', () => {
await dispose(result)
})
it('flushes, releases the terminal, and invokes one host handoff for the same SessionId', async () => {
it('flushes, releases the terminal, and invokes one host handoff for the same SessionId and workspace', async () => {
const target = header('target-session', 10, '/workspace')
const handoff = vi.fn<NonNullable<TuiRuntime['handoffResume']>>(() => Promise.reject(new Error('test host retained process')))
const result = await setup({
@@ -701,7 +702,7 @@ describe('resume command and /resume', () => {
result.terminal.send('\r')
await tick(); await tick()
expect(handoff).toHaveBeenCalledTimes(1)
expect(handoff).toHaveBeenCalledWith(target.id)
expect(handoff).toHaveBeenCalledWith(target.id, '/workspace')
expect(result.terminal.stopped).toBeGreaterThan(0)
expect(result.terminal.output).toContain('Resume handoff failed: test host retained process')
await dispose(result)
@@ -817,7 +818,7 @@ describe('resume command and /resume', () => {
result.terminal.send('Query without persistence')
result.terminal.send('\r')
await tick(); await tick()
expect(handoff).toHaveBeenCalledWith(target.id)
expect(handoff).toHaveBeenCalledWith(target.id, '/workspace')
expect(result.terminal.output).toContain('Resume handoff failed: test host retained process')
await dispose(result)
})
@@ -902,16 +903,23 @@ describe('resume command and /resume', () => {
expect(result.terminal.output).not.toContain('host rejected after disposal')
})
it('rejects a candidate whose cwd changes between listing and preflight', async () => {
// A cwd that changes between listing and preflight is no longer a rejection:
// resume targets whatever workspace the record names at preflight, so the
// handoff must carry the RE-READ cwd rather than the one the row displayed.
it('hands off with the cwd re-read at preflight, not the one listed', async () => {
const target = header('moving-workspace', 10, '/workspace')
const moved = header('moving-workspace', 10, '/elsewhere')
const handoff = vi.fn<NonNullable<TuiRuntime['handoffResume']>>(
() => Promise.reject(new Error('test host retained process')),
)
let listings = 0
const result = await setup({
cwd: '/workspace',
handoffResume: vi.fn(),
handoffResume: handoff,
sessionPersistence: {
list: async () => [++listings <= 2 ? target : header('moving-workspace', 10, '/elsewhere')],
list: async () => [++listings <= 2 ? target : moved],
load: async () => ({
meta: listings <= 2 ? target : header('moving-workspace', 10, '/elsewhere'),
meta: listings <= 2 ? target : moved,
events: resumeEvents('Moving workspace'),
}),
},
@@ -922,7 +930,101 @@ describe('resume command and /resume', () => {
result.terminal.send('Moving workspace')
result.terminal.send('\r')
await tick(); await tick()
expect(result.terminal.output).toContain('different workspace')
expect(handoff).toHaveBeenCalledWith(target.id, '/elsewhere')
await dispose(result)
})
it('keeps a session with no recorded workspace visible but disabled', async () => {
// The key is omitted, not set to undefined: an explicit undefined is not
// losslessly JSON-serializable and the header validator rejects it.
const { cwd: _cwd, ...rootless } = header('no-workspace', 10, '/workspace')
const handoff = vi.fn<NonNullable<TuiRuntime['handoffResume']>>()
const result = await setup({
cwd: '/workspace',
handoffResume: handoff,
sessionPersistence: {
list: async () => [rootless],
load: async () => ({ meta: rootless, events: resumeEvents('Rootless session') }),
},
})
result.terminal.send('/resume')
result.terminal.send('\r')
await tick(); await tick()
// A cwd-less session lists under all workspaces, never the current one.
result.terminal.send('\t')
await tick()
result.terminal.send('Rootless session')
result.terminal.send('\r')
await tick()
expect(result.terminal.output).toContain('session has no recorded workspace')
expect(handoff).not.toHaveBeenCalled()
await dispose(result)
})
it('lists other workspaces only in the all-workspaces scope and resumes into their cwd', async () => {
const local = header('local-session', 2000, '/workspace')
const foreign = header('foreign-session', 3000, '/elsewhere')
const handoff = vi.fn<NonNullable<TuiRuntime['handoffResume']>>(
() => Promise.reject(new Error('test host retained process')),
)
const result = await setup({
cwd: '/workspace',
handoffResume: handoff,
sessionPersistence: {
list: async () => [local, foreign],
load: async id => id === local.id
? { meta: local, events: resumeEvents('Local product work') }
: { meta: foreign, events: resumeEvents('Foreign investigation') },
},
})
result.terminal.send('/resume')
result.terminal.send('\r')
await tick(); await tick()
// Three records: the two listed plus the live current session.
expect(result.terminal.output).toContain('Local product work')
expect(result.terminal.output).not.toContain('Foreign investigation')
expect(result.terminal.output).toContain('all workspaces (3)')
result.terminal.send('\t')
await tick()
const scoped = result.terminal.output.slice(result.terminal.output.lastIndexOf('Resume session'))
expect(scoped).toContain('Foreign investigation')
expect(scoped).toContain('workspace /elsewhere')
expect(scoped).toContain('this workspace (2)')
// Searching the workspace label reaches a row the title would not match.
result.terminal.send('elsewhere')
result.terminal.send('\r')
await tick(); await tick()
expect(handoff).toHaveBeenCalledWith(foreign.id, '/elsewhere')
await dispose(result)
})
it('returns to the current workspace when Tab toggles back and clears the search', async () => {
const local = header('scope-local', 2000, '/workspace')
const foreign = header('scope-foreign', 3000, '/elsewhere')
const result = await setup({
cwd: '/workspace',
handoffResume: vi.fn(),
sessionPersistence: {
list: async () => [local, foreign],
load: async id => id === local.id
? { meta: local, events: resumeEvents('Scope local') }
: { meta: foreign, events: resumeEvents('Scope foreign') },
},
})
result.terminal.send('/resume')
result.terminal.send('\r')
await tick(); await tick()
result.terminal.send('\t')
await tick()
result.terminal.send('Scope foreign')
await tick()
expect(result.terminal.output).toContain('⌕ Scope foreign')
result.terminal.send('\t')
await tick()
const back = result.terminal.output.slice(result.terminal.output.lastIndexOf('Resume session'))
expect(back).not.toContain('⌕ Scope foreign')
expect(back).toContain('Scope local')
expect(back).not.toContain('Scope foreign')
await dispose(result)
})
@@ -1018,30 +1120,7 @@ describe('resume command and /resume', () => {
await dispose(result)
})
it('keeps resumeCommand as a displayed fallback when the host cannot hand off', async () => {
const target = header('fallback-session', 10, '/workspace')
const result = await setup({
cwd: '/workspace',
config: { resumeCommand: RESUME },
sessionPersistence: {
list: async () => [target],
load: async () => ({ meta: target, events: resumeEvents('Fallback target') }),
},
})
result.terminal.send('/resume')
result.terminal.send('\r')
await tick(); await tick()
result.terminal.send('Fallback target')
result.terminal.send('\r')
await vi.waitFor(() => {
expect(result.terminal.output).toContain('This host cannot hand off in place. Exit and run:')
})
expect(result.terminal.output).toContain('dsh --resume fallback-session')
expect(result.terminal.stopped).toBe(0)
await dispose(result)
})
it('keeps the selector independent from an absent command fallback', async () => {
it('warns without releasing the terminal when the host cannot hand off', async () => {
const target = header('no-fallback-session', 10, '/workspace')
const result = await setup({
cwd: '/workspace',
@@ -1058,6 +1137,7 @@ describe('resume command and /resume', () => {
await vi.waitFor(() => {
expect(result.terminal.output).toContain('Session is resumable, but this host cannot hand it off in place')
})
expect(result.terminal.stopped).toBe(0)
await dispose(result)
})
@@ -1330,10 +1410,16 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.output).toContain('Steering')
expect(result.terminal.output).toContain('user context')
expect(result.terminal.output).toContain('Context · workspace-context')
expect(result.terminal.output).toContain('system-reminder')
// The redundant `system-reminder` frame element is dropped: the source label
// already names the context, so the card body starts at the instruction text.
expect(result.terminal.output).toContain('Additional instructions from: nested/AGENTS.md')
expect(result.terminal.output).not.toContain('<system-reminder>')
expect(result.terminal.output).toContain('\\x9b')
expect(result.terminal.output).toContain('Render XML context clearly.')
// A one-line frame has no open/close line pair to strip, so its text renders as
// the prose it is. The card no longer parses context, so a character reference
// stays literal instead of expanding to the control character it names — which
// is why the expanded-C1 escaping the parser needed is no longer reachable here.
expect(result.terminal.output).toContain('&#155;')
expect(result.terminal.output).not.toContain('\u009b')
expect(result.terminal.output).toContain('Context · goal') // goal-sourced injected context labels by kind
expect(result.terminal.output).toContain('Turn cancelled')
expect(result.terminal.progress).toContain(true)
@@ -1361,6 +1447,104 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.drainInput).toHaveBeenCalledWith(100, 20)
})
it('folds an injected-context card by default and expands it with Ctrl+O', async () => {
const result = await setup()
// A reminder body past the default 6-line budget so the collapsed card shows
// the expand marker and hides a middle line until Ctrl+O.
const instructions = Array.from({ length: 10 }, (_, index) => `instruction line ${index}`).join('\n')
result.session.append('user/message', createUserMessage({
content: [{ type: 'text', text: `<system-reminder>\n${instructions}\n</system-reminder>` }],
source: { kind: 'plugin', plugin: 'workspace-context' },
}), { surfaceOp: 'append' })
await tick()
// The redundant `system-reminder` frame element is dropped; the card is
// collapsed by default with the shared Ctrl+O expand marker.
expect(result.terminal.output).toContain('Context · workspace-context')
expect(result.terminal.output).not.toContain('system-reminder')
expect(result.terminal.output).toContain('lines (Ctrl+O to expand)')
expect(result.terminal.output).toContain('instruction line 0')
expect(result.terminal.output).not.toContain('instruction line 5')
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('Tool and context cards expanded.')
expect(result.terminal.output).toContain('instruction line 5')
// Third state: tool cards hide; a context card is injected instructions,
// not tool traffic, so it stays visible at its collapsed preview.
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('Tool cards hidden.')
// A repaint proves the context card SURVIVES the hidden phase: injected
// instructions are not tool traffic, so they stay at the collapsed preview.
result.terminal.send('\x0c')
await tick()
const hidden = result.terminal.output.slice(result.terminal.output.lastIndexOf('\x1b[2J'))
expect(hidden).toContain('Context · workspace-context')
// Fourth press returns to the collapsed default, closing the cycle.
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('Tool and context cards collapsed.')
// Context with no frame renders as muted prose under the header; a frame
// wrapping nothing renders header-only.
result.session.append('user/message', createUserMessage({
content: [{ type: 'text', text: 'plain reminder text, no tags' }],
source: { kind: 'plugin', plugin: 'plain-context' },
}), { surfaceOp: 'append' })
result.session.append('user/message', createUserMessage({
content: [{ type: 'text', text: '<system-reminder>\n</system-reminder>' }],
source: { kind: 'plugin', plugin: 'empty-context' },
}), { surfaceOp: 'append' })
// Only a matched open/close pair is a frame: an unpaired tag line is prose and
// survives, so a body is never silently truncated by a tag-like first line.
result.session.append('user/message', createUserMessage({
content: [{ type: 'text', text: '<available_skills>\nkept prose line\n</other-tag>' }],
source: { kind: 'plugin', plugin: 'unpaired-context' },
}), { surfaceOp: 'append' })
await tick()
expect(result.terminal.output).toContain('Context · plain-context')
expect(result.terminal.output).toContain('plain reminder text, no tags')
expect(result.terminal.output).toContain('Context · empty-context')
expect(result.terminal.output).toContain('<available_skills>')
expect(result.terminal.output).toContain('kept prose line')
// Ctrl+L invalidates the mounted tree, exercising the card's invalidate hook.
result.terminal.send('\x0c')
await tick()
await dispose(result)
})
it('renders XML-hostile instruction prose verbatim, framed and folded', async () => {
const result = await setup()
// Real AGENTS.md prose carries a raw `&` (a badge URL's `&logo=`) and
// angle-bracket placeholders that name nothing (`packages/<group>/<pkg>/`).
// Both are prose the model must read literally, and neither may affect whether
// the frame is stripped or the body folds.
const lines = Array.from({ length: 10 }, (_, index) => `prose line ${index}`).join('\n')
result.session.append('user/message', createUserMessage({
content: [{
type: 'text',
text: `<system-reminder>\nbadge: https://img.shields.io/badge/x?style=flat&logo=deepseek\npath: packages/<group>/<pkg>/\n${lines}\n</system-reminder>`,
}],
source: { kind: 'plugin', plugin: 'prose-context' },
}), { surfaceOp: 'append' })
await tick()
expect(result.terminal.output).toContain('Context · prose-context')
expect(result.terminal.output).not.toContain('<system-reminder>')
expect(result.terminal.output).toContain('lines (Ctrl+O to expand)')
expect(result.terminal.output).not.toContain('prose line 5')
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('prose line 5')
// Characters that break a strict XML parse survive unescaped and unexpanded.
expect(result.terminal.output).toContain('&logo=deepseek')
expect(result.terminal.output).toContain('packages/<group>/<pkg>/')
await dispose(result)
})
it('counts failed and recovered request usage once per step', async () => {
const result = await setup()
result.session.append('assistant/chunk', {
@@ -1445,10 +1629,10 @@ describe('pi-tui chat lifecycle and transcript', () => {
await dispose(result)
})
it('badges queued steering on the prompt context timing and clears it as each drains', async () => {
it('badges queued steering on the prompt context and clears it as each drains', async () => {
// Pin a cwd free of the substring under test; the prompt context renders the path.
const result = await setup({ status: 'running', cwd: '/workspace' })
// Running with nothing queued: timing appears once in the prompt context and the editor keeps its hint.
// Running with nothing queued: the badge is absent and the editor keeps its hint.
expect(result.terminal.output).toContain('Assistant')
expect(result.terminal.output).toContain('Model wait 0.0s')
expect(result.terminal.output).toContain('press enter to steer and esc to cancel')
@@ -1854,13 +2038,13 @@ describe('pi-tui chat lifecycle and transcript', () => {
}
// Without truecolor there is no per-frame gray: below the fade midpoint the
// glyph slot is blank; past it the glyph shows in the palette muted role
// (ANSI 90), never the accent (SGR 94).
// glyph slot is blank; past it the glyph shows in the palette dim role,
// never the accent (ANSI 95).
const early = await frameAt(60)
expect(early).not.toMatch(/dsh(?:\x1b\[[0-9;]*m| )*●/u)
const shown = await frameAt(300)
expect(shown).toMatch(/\x1b\[90m●/u)
expect(shown).not.toMatch(/\x1b\[94m●/u)
expect(shown).toMatch(/\x1b\[2;39m●/u)
expect(shown).not.toMatch(/\x1b\[95m●/u)
await dispose(result)
})
@@ -2065,8 +2249,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
})
expect(result.terminal.output).not.toContain('stale partial response')
result.terminal.send('/reasoning')
result.terminal.send('\r')
result.terminal.send('\x12')
result.terminal.send('\x1b[A')
result.terminal.send('\x1b[A')
result.terminal.send('\x1b[A')
@@ -2231,8 +2414,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.output).not.toContain('\u001B]2;unsafe\u0007')
result.terminal.resize(56)
result.terminal.send('/redraw')
result.terminal.send('\r')
result.terminal.send('\x0c')
await tick()
await dispose(result)
@@ -2304,7 +2486,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.agent.cancelled).toContainEqual({ kind: 'user' })
result.agent.status = 'idle'
for (const command of ['/help', '/reasoning', '/tools', '/redraw', '/reload']) {
for (const command of ['/help', '/palette', '/reload']) {
result.terminal.send(command)
result.terminal.send('\r')
await tick()
@@ -2321,7 +2503,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
expect(result.terminal.output).toContain('Keyboard shortcuts')
expect(result.terminal.output).toContain('Reasoning blocks')
expect(result.terminal.output).toContain('Tool cards')
expect(result.terminal.output).toContain('Tool and context cards')
expect(result.terminal.output).toContain('Unknown command')
// /reload without a Loader in the context degrades to a warning.
expect(result.terminal.output).toContain('/reload needs the cordis Loader')
@@ -3133,8 +3315,25 @@ describe('pi-tui chat lifecycle and transcript', () => {
await vi.waitFor(() => {
expect(result.terminal.output.slice(firstSelectorOutput)).toContain('Select model')
})
const filterOpenOutput = result.terminal.output.length
result.terminal.send('beta')
await tick()
expect(result.terminal.output.slice(filterOpenOutput)).toContain('> beta')
expect(result.terminal.output.slice(filterOpenOutput)).toContain('beta/b1')
expect(result.terminal.output.slice(filterOpenOutput)).not.toContain('alpha/a1')
const noMatchOutput = result.terminal.output.length
result.terminal.send('zzz')
await tick()
expect(result.terminal.output.slice(noMatchOutput)).toContain('No models match the filter')
result.terminal.send('\x1b[D')
await tick()
expect(result.terminal.output.slice(noMatchOutput)).toContain('No models match the filter')
result.terminal.send('\x1b')
await tick()
const filterClearedOutput = result.terminal.output.length
result.terminal.send('\x1b')
await tick()
expect(result.terminal.output.slice(filterClearedOutput)).not.toContain('Select model')
const providerDefaultOutput = result.terminal.output.length
result.terminal.send('/model alpha/shared')
@@ -3705,6 +3904,23 @@ describe('skill slash command', () => {
await dispose(result)
})
it('auto-invokes a launcher-seeded initial skill as the first turn', async () => {
const result = await setup({ config: { initialSkill: 'demo-skill' }, configureContext: withSkills })
// The seed rides the same path as a typed `/skill:demo-skill`, delivered
// once the chat is live; no user input is required.
await tick()
expect(result.agent.sent).toEqual([[{ type: 'text', text: '<skill name="demo-skill">\nDemo instructions body.\n</skill>' }]])
await dispose(result)
})
it('reports an unknown initial skill as a notice without sending', async () => {
const result = await setup({ config: { initialSkill: 'nope' }, configureContext: withSkills })
await tick()
expect(result.terminal.output).toContain('Unknown skill: nope')
expect(result.agent.sent).toEqual([])
await dispose(result)
})
it('reports an unknown skill and an empty skill name without sending', async () => {
const result = await setup({ configureContext: withSkills })
result.terminal.send('/skill:does-not-exist')
@@ -3931,8 +4147,7 @@ describe('tool cards and surface replay', () => {
}
await tick()
expect(result.terminal.output).toContain('$ raw command')
result.terminal.send('/reasoning')
result.terminal.send('\r')
result.terminal.send('\x12')
await tick()
expect(result.terminal.output).toContain('call presenter boom')
expect(result.terminal.output).toContain('Symbol(input)')
@@ -4066,8 +4281,7 @@ describe('tool cards and surface replay', () => {
expect(output).toContain('line (number="1"): hello')
expect(output).not.toContain('<result>')
result.terminal.send('/redraw')
result.terminal.send('\r')
result.terminal.send('\x0c')
await tick()
const collapsed = result.terminal.output.slice(result.terminal.output.lastIndexOf('\x1b[2J'))
expect(collapsed).toContain('Run command')
@@ -4077,7 +4291,7 @@ describe('tool cards and surface replay', () => {
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('world')
expect(result.terminal.output).toContain('Tool cards expanded.')
expect(result.terminal.output).toContain('Tool and context cards expanded.')
expect(result.terminal.output).not.toContain('tools:expanded')
expect(result.terminal.output).toContain('+ created')
expect(result.terminal.output).toContain('console')
@@ -4085,6 +4299,42 @@ describe('tool cards and surface replay', () => {
// expanded (`+ after` is b.txt's new text; the footer counts both files).
expect(result.terminal.output).toContain('+ after')
expect(result.terminal.output).toContain('· 2 files')
// Third Ctrl+O phase hides every tool card: after a redraw the repainted
// frame carries no tool header at all, only the conversation.
result.terminal.send('\x0f')
await tick()
expect(result.terminal.output).toContain('Tool cards hidden.')
// A result for an untracked call mints a fallback card mid-hidden: it must
// adopt the current visibility instead of rendering collapsed.
result.session.append('tool/result', {
turn: 1, step: 1,
message: createToolResultMessage({
callId: 'untracked' as never,
content: [{ type: 'text', text: 'fallback result body' }],
isError: false,
}),
}, { surfaceOp: 'append' })
await tick()
result.terminal.send('\x0c')
await tick()
const hiddenFrame = result.terminal.output.slice(result.terminal.output.lastIndexOf('\x1b[2J'))
expect(hiddenFrame).not.toContain('Tool / bash')
expect(hiddenFrame).not.toContain('Run command')
expect(hiddenFrame).not.toContain('fallback result body')
// The dozen hidden cards leave no per-card blank rows behind: each card owns
// its leading gap, so the trimmed frame has no long blank run where the
// cards used to be.
const frameRows = hiddenFrame.split('\n').map(row => row.replaceAll(/\x1b\[[0-9;]*[A-Za-z]/g, '').trim())
const first = frameRows.findIndex(row => row.includes('Calling tools'))
expect(first).toBeGreaterThan(-1)
let blankRun = 0
let longestRun = 0
for (const row of frameRows.slice(first)) {
blankRun = row === '' ? blankRun + 1 : 0
longestRun = Math.max(longestRun, blankRun)
}
expect(longestRun).toBeLessThanOrEqual(2)
await dispose(result)
})
@@ -4111,6 +4361,46 @@ describe('tool cards and surface replay', () => {
await dispose(result)
})
it('drops blank rows from a terminal card result that the dim styling wraps', async () => {
const blankRowTools: Record<string, ToolDefinition> = {
trailing: {
name: 'trailing', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [],
presentCall: () => ({ card: 'terminal', title: 'printf out', description: 'Run it', cwd: '/tmp' }),
// Real command output ends in a newline, so the split yields a trailing blank row.
presentResult: () => ({ card: 'terminal', output: 'first\n\nlast\n', exitCode: 0 }),
},
}
// Color on: the dim wrapper is what makes a blank row non-empty, so the
// guard against wrapping one is only observable with ANSI enabled.
const result = await setup({ tools: blankRowTools, config: { theme: { color: true } } })
appendUser(result.session, 'run it')
appendAssistant(result.session, [
{ type: 'tool-call', id: 'blank' as never, name: 'trailing', arguments: '{}' },
])
result.session.append('tool/call', {
turn: 1, step: 1, callId: 'blank' as never, name: 'trailing', arguments: '{}',
})
result.session.append('tool/result', {
turn: 1, step: 1,
message: createToolResultMessage({
callId: 'blank' as never, content: [{ type: 'text', text: 'ignored' }], isError: false,
}),
}, { surfaceOp: 'append' })
await tick()
// Each output row is dim-wrapped, and the result's blank rows are dropped
// rather than kept as dim-wrapped empty strings: `last` is the row right
// after `first`, and no empty dim pair reaches the terminal.
expect(result.terminal.output).toContain('\x1b[2;39mfirst\x1b[22;39m')
expect(result.terminal.output).toContain('\x1b[2;39mlast\x1b[22;39m')
expect(result.terminal.output).not.toContain('\x1b[2;39m\x1b[22;39m')
const rows = result.terminal.output.split('\n')
const firstRow = rows.findIndex(row => row.includes('first'))
expect(firstRow).toBeGreaterThan(-1)
expect(rows[firstRow + 1]).toContain('last')
expect(rows[firstRow + 2]).toContain('[exit 0]')
await dispose(result)
})
it('rebuilds after a surface replacement and hides shadowed tool calls', async () => {
const result = await setup({ tools })
appendUser(result.session, 'old prompt')
@@ -4347,7 +4637,6 @@ describe('TUI extension service', () => {
host.theme.accent(`${label} plugin overlay`),
[
host.theme.text('text'),
host.theme.muted('muted'),
host.theme.dim('dim'),
host.theme.success('success'),
host.theme.warning('warning'),
@@ -4641,10 +4930,42 @@ describe('terminal mounting', () => {
await ctx.fiber.dispose()
})
it('detects a light terminal color scheme and switches from dark- to light-optimised ANSI codes', async () => {
it('prints every palette role through /palette, each painted by the code it reports', async () => {
const result = await setup({ config: { theme: { color: true } } })
// Initial render uses dark-optimised palette: SGR 2 (dim) for dim text.
expect(result.terminal.output).toContain('\x1b[90mdeepseek-v4-flash')
const before = result.terminal.output.length
result.terminal.send('/palette')
result.terminal.send('\r')
await tick()
const printed = result.terminal.output.slice(before)
// Every declared role appears with its purpose, so a role added to the spec
// without a listing entry (or the reverse) fails here rather than silently
// going unlisted.
const spec = paletteSpec('dark')
for (const name of COLOR_ROLES) {
expect(printed).toContain(name)
expect(printed).toContain(spec.colors[name].purpose)
}
for (const name of ATTRIBUTE_ROLES) {
expect(printed).toContain(name)
expect(printed).toContain(spec.attributes[name].purpose)
}
// Each row is painted by the role it names, so the listing cannot report one
// code while rendering another: the sample carries the spec's own open code.
expect(printed).toContain(`\x1b[${spec.colors.accent.open}m`)
expect(printed).toContain(`\x1b[${spec.colors.dim.open}m`)
expect(printed).toContain(`\x1b[${spec.attributes.selected.open}m`)
// `text` is the terminal default, emitted as no escape at all.
expect(printed).toContain('no escape')
await dispose(result)
})
it('detects a light terminal color scheme and switches the scheme-dependent code role', async () => {
const result = await setup({ config: { theme: { color: true } } })
// `dim` is scheme-independent (SGR 2 over the default foreground), so the
// startup render carries it on both schemes; `code` is the role that varies.
expect(result.terminal.output).toContain('\x1b[2;39mdeepseek-v4-flash')
// A report matching the current scheme is a no-op: no palette rebuild or
// re-render (ESC [?997;1n = dark, the startup default).
@@ -4658,20 +4979,14 @@ describe('terminal mounting', () => {
result.terminal.send('\x1b[?997;2n')
await tick()
await tick()
// The rebuild re-renders under the light palette, where `code` is ANSI 34
// (blue) rather than the dark scheme's ANSI 36 (cyan); `dim` is unchanged.
expect(result.terminal.output).toContain('\x1b[2;39mdeepseek-v4-flash')
// After switching to light-optimised palette: palette.dim uses ANSI 90
// (gray) instead of SGR 2. The header now uses \x1b[90m for the detail
// line. The cumulative output still contains the initial SGR 2 render,
// so we assert that a LATER write (appended after the scheme switch)
// uses ANSI 90 for the same header text.
expect(result.terminal.output).toContain('\x1b[90mdeepseek-v4-flash')
// Switch back to dark scheme.
result.terminal.send('\x1b[?997;1n')
await tick()
await tick()
// After switching back, a new write uses SGR 2 for the header detail.
expect(result.terminal.output).toContain('\x1b[90mdeepseek-v4-flash')
expect(result.terminal.output).toContain('\x1b[2;39mdeepseek-v4-flash')
await dispose(result)
})
@@ -4692,8 +5007,8 @@ describe('terminal mounting', () => {
cwd: join(homedir(), 'projects', 'dsh-tui'),
})
await tick()
expect(terminal.output).toContain('\x1b[94m~/')
expect(terminal.output).toContain('\x1b[90m (tui-staging)')
expect(terminal.output).toContain('\x1b[95m~/')
expect(terminal.output).toContain('\x1b[2;39m (tui-staging)')
await disposeTuiTestHarness(result)
})
it('runs /reload against every file-backed loader subtree, reports completion, and rejects re-entry while in flight', async () => {

View File

@@ -8,6 +8,7 @@ const render = (source: string, limit = 4, expanded = false): string[] | undefin
text => text.replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/gu, control =>
`\\x${control.charCodeAt(0).toString(16).padStart(2, '0')}`),
text => `[label]${text}[/label]`,
text => `[body]${text}[/body]`,
count => ` … +${count} lines`,
)
@@ -22,30 +23,38 @@ describe('unknown-tool XML rendering', () => {
</content>
</result>`)).toEqual([
'[label]result[/label]',
' [label]path:[/label] /tmp/a.txt',
' [label]type:[/label] file',
' [label]path:[/label] [body]/tmp/a.txt[/body]',
' [label]type:[/label] [body]file[/body]',
' [label]content[/label]',
' [label]line (number="1"):[/label] hello',
' [label]line (number="2"):[/label] world',
' [label]line (number="1"):[/label] [body]hello[/body]',
' [label]line (number="2"):[/label] [body]world[/body]',
])
})
it('renders root text, CDATA, empty elements, and multiline nested text', () => {
expect(render(' <result>\nfirst\nsecond\n</result> ')).toEqual([
'[label]result[/label]',
' first',
' second',
' [body]first[/body]',
' [body]second[/body]',
])
expect(render('<result>\nfirst\nsecond\n</result>', 1, true)).toEqual([
'[label]result[/label]',
' first',
' second',
' [body]first[/body]',
' [body]second[/body]',
])
expect(render('<result><value><![CDATA[literal <xml>]]></value><empty /></result>')).toEqual([
'[label]result[/label]',
' [label]value:[/label] literal <xml>',
' [label]value:[/label] [body]literal <xml>[/body]',
' [label]empty[/label]',
])
// An interior blank line stays the empty string: styling it would emit an
// escape-only row, which reads as a stray indented blank rather than a gap.
expect(render('<result>\nfirst\n\nsecond\n</result>', 4, true)).toEqual([
'[label]result[/label]',
' [body]first[/body]',
'',
' [body]second[/body]',
])
})
it('previews each top-level child independently and expands all rows', () => {
@@ -53,13 +62,13 @@ describe('unknown-tool XML rendering', () => {
expect(render(xml, 3)).toEqual([
'[label]result[/label]',
' [label]first[/label]',
' a',
' [body]a[/body]',
' … +4 lines',
' f',
' [body]f[/body]',
' [label]second[/label]',
' g',
' [body]g[/body]',
' … +4 lines',
' l',
' [body]l[/body]',
])
expect(render(xml, 3, true)).toHaveLength(15)
})
@@ -68,10 +77,10 @@ describe('unknown-tool XML rendering', () => {
const xml = `<result>${Array.from({ length: 8 }, (_, index) => `<item>${index}</item>`).join('')}</result>`
expect(render(xml, 3)).toEqual([
'[label]result[/label]',
' [label]item:[/label] 0',
' [label]item:[/label] 1',
' [label]item:[/label] [body]0[/body]',
' [label]item:[/label] [body]1[/body]',
' … +5 lines',
' [label]item:[/label] 7',
' [label]item:[/label] [body]7[/body]',
])
expect(render(xml, 3, true)).toHaveLength(9)
})
@@ -79,11 +88,11 @@ describe('unknown-tool XML rendering', () => {
it('escapes control characters expanded from character references', () => {
expect(render('<result attr="a&#155;b">tab&#9;csi&#155;</result>')).toEqual([
'[label]result (attr="a\\\\x9bb")[/label]',
' tab\\x09csi\\x9b',
' [body]tab\\x09csi\\x9b[/body]',
])
expect(render('<result><value><![CDATA[del\u007f]]></value></result>')).toEqual([
'[label]result[/label]',
' [label]value:[/label] del\\x7f',
' [label]value:[/label] [body]del\\x7f[/body]',
])
})