Merge refreshed schema DSL into canonical tool output
# Conflicts: # docs/config-catalog.md # examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl # packages/context/workspace-context/tests/workspace-context.spec.ts # packages/core/tools/tests/tools.spec.ts # packages/ui/tui/src/index.ts # packages/ui/tui/tests/tui.snapshot.ts
This commit is contained in:
@@ -8,7 +8,7 @@ import AgentRegistry, {
|
||||
} from '@deepseek-ai/dsh-agent'
|
||||
import type { ContentBlock, LlmModelContext, LlmModelInfo, LlmProviderInfo } from '@deepseek-ai/dsh-llm'
|
||||
import CommandService from '@deepseek-ai/dsh-commands'
|
||||
import SessionStore, { SessionId, type Session } from '@deepseek-ai/dsh-session'
|
||||
import SessionStore, { SessionId, type Session, type SessionHeader } from '@deepseek-ai/dsh-session'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import type { ToolDefinition } from '@deepseek-ai/dsh-tools'
|
||||
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
||||
@@ -24,11 +24,16 @@ interface FakeAgent extends Agent {
|
||||
export interface TuiHarnessOptions {
|
||||
status?: AgentStatus
|
||||
config?: Config
|
||||
/** Leave the session event log empty instead of seeding one turn and step. */
|
||||
omitInitialLifecycle?: boolean
|
||||
/** Omit the harness's default `welcome`, exercising the banner sweep-reveal path. */
|
||||
omitWelcome?: boolean
|
||||
tools?: Record<string, ToolDefinition>
|
||||
configureContext?: (ctx: Context) => Promise<void>
|
||||
beforeMount?: (session: Session) => void
|
||||
cwd?: string | null
|
||||
formatCwd?: TuiRuntime['formatCwd']
|
||||
/** Fake-agent creation options (`provider`/`model` seed the model selector's initial target). */
|
||||
agentOptions?: AgentOptions
|
||||
contextWindow?: number
|
||||
contextTokens?: number
|
||||
@@ -39,6 +44,8 @@ export interface TuiHarnessOptions {
|
||||
listModels?: (provider: string) => Promise<LlmModelInfo[]>
|
||||
resolveModelContext?: (provider: string, model: string) => Promise<LlmModelContext | undefined>
|
||||
}
|
||||
/** Provide a fake `sessionPersistence` service so resume surfaces can list sessions. */
|
||||
sessionPersistence?: { list(): Promise<SessionHeader[]> }
|
||||
}
|
||||
|
||||
export interface TuiHarness<TerminalType extends Terminal, Exit extends (code: number) => void> {
|
||||
@@ -74,19 +81,6 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
{ provider: 'deepseek', id: 'deepseek-v4-pro', name: 'DeepSeek V4 Pro' },
|
||||
],
|
||||
}
|
||||
ctx.provide('llm', {
|
||||
listProviders() {
|
||||
return catalog.providers.map(provider => ({ ...provider }))
|
||||
},
|
||||
listModels(provider: string) {
|
||||
return catalog.listModels?.(provider)
|
||||
?? Promise.resolve(catalog.models.filter(model => model.provider === provider).map(model => ({ ...model })))
|
||||
},
|
||||
resolveModelContext(provider: string, model: string) {
|
||||
return catalog.resolveModelContext?.(provider, model)
|
||||
?? Promise.resolve({ contextWindow: options.contextWindow ?? 128_000 })
|
||||
},
|
||||
} as never)
|
||||
ctx.provide('tokenMeter', {
|
||||
measure() {
|
||||
return { totalTokens: options.contextTokens ?? 0 }
|
||||
@@ -102,17 +96,39 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
} else {
|
||||
await options.configureContext(ctx)
|
||||
}
|
||||
// A configureContext may mount the real LlmService; only fill the
|
||||
// advisory-catalog stub when none was provided.
|
||||
if (ctx.get('llm') === undefined) {
|
||||
ctx.provide('llm', {
|
||||
listProviders() {
|
||||
return catalog.providers.map(provider => ({ ...provider }))
|
||||
},
|
||||
listModels(provider: string) {
|
||||
return catalog.listModels?.(provider)
|
||||
?? Promise.resolve(catalog.models.filter(model => model.provider === provider).map(model => ({ ...model })))
|
||||
},
|
||||
resolveModelContext(provider: string, model: string) {
|
||||
return catalog.resolveModelContext?.(provider, model)
|
||||
?? Promise.resolve({ contextWindow: options.contextWindow ?? 128_000 })
|
||||
},
|
||||
} as never)
|
||||
}
|
||||
if (ctx.get('systemPrompt') === undefined) await ctx.plugin(SystemPrompt)
|
||||
if (options.sessionPersistence !== undefined) {
|
||||
ctx.provide('sessionPersistence', options.sessionPersistence as never)
|
||||
}
|
||||
const sessionId = SessionId('main-session')
|
||||
const session = ctx.sessions.create(
|
||||
sessionId,
|
||||
options.cwd === null ? undefined : { meta: { cwd: options.cwd ?? '/workspace' } },
|
||||
)
|
||||
session.append('turn/start', {
|
||||
turn: 1,
|
||||
trigger: { kind: 'message', source: { kind: 'user' } },
|
||||
})
|
||||
session.append('step/start', { turn: 1, step: 1 })
|
||||
if (options.omitInitialLifecycle !== true) {
|
||||
session.append('turn/start', {
|
||||
turn: 1,
|
||||
trigger: { kind: 'message', source: { kind: 'user' } },
|
||||
})
|
||||
session.append('step/start', { turn: 1, step: 1 })
|
||||
}
|
||||
options.beforeMount?.(session)
|
||||
const sent: ContentBlock[][] = []
|
||||
const steered: ContentBlock[][] = []
|
||||
@@ -142,13 +158,16 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
}
|
||||
ctx.agents.register(agent)
|
||||
const controller = createTuiChat(ctx, Object.assign({
|
||||
welcome: 'Coding agent ready.',
|
||||
...options.omitWelcome === true ? {} : { welcome: 'Coding agent ready.' },
|
||||
sessionId,
|
||||
color: false,
|
||||
}, options.config), {
|
||||
terminal,
|
||||
exit,
|
||||
now: options.now ?? (() => 0),
|
||||
// Default to the real clock (runtime.now falls back to Date.now) so the
|
||||
// elapsed-status suites can drive time via timers or Date.now spies; a
|
||||
// test pins the clock only by passing `now` explicitly.
|
||||
...(options.now === undefined ? {} : { now: options.now }),
|
||||
...(options.formatCwd === undefined ? {} : { formatCwd: options.formatCwd }),
|
||||
})
|
||||
return { ctx, session, agent, terminal, exit, controller }
|
||||
@@ -174,7 +193,7 @@ export function appendUser(session: Session, text: string): void {
|
||||
export function appendAssistant(
|
||||
session: Session,
|
||||
content: ContentBlock[],
|
||||
usage?: { inputTokens: number; outputTokens: number },
|
||||
usage?: { inputTokens: number; outputTokens: number; cacheReadTokens?: number; cacheWriteTokens?: number },
|
||||
position: { turn: number; step: number } = { turn: 1, step: 1 },
|
||||
): void {
|
||||
session.append('assistant/message', {
|
||||
|
||||
@@ -1,108 +1,99 @@
|
||||
terminal 100x40 buffer=normal length=41 base=1 viewport=1
|
||||
terminal 100x40 buffer=normal length=40 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=37 bufferRow=38
|
||||
cursor hidden column=1 viewportRow=36 bufferRow=36
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ pnpm run test:coverage "
|
||||
5| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
8| "▌ Run the coverage gate "
|
||||
6| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
9| "▌ /workspace/project "
|
||||
7| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
10| "▌ … +4 lines (Ctrl+O to expand) "
|
||||
8| "▌ … +4 lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=green
|
||||
style 2-30 dim
|
||||
11| "▌ [exit 0] "
|
||||
9| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
10| "▌ "
|
||||
style 0-0 fg=green
|
||||
11| <blank>
|
||||
12| "▌ "
|
||||
style 0-0 fg=green
|
||||
13| <blank>
|
||||
14| "▌ "
|
||||
style 0-0 fg=green
|
||||
15| "▌ ✓ Edit renderer "
|
||||
13| "▌ ✓ Edit renderer "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
16| "▌ src/view.ts "
|
||||
14| "▌ src/view.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-12 bold
|
||||
17| "▌ - old line "
|
||||
15| "▌ - old line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=red
|
||||
18| "▌ … +5 lines (Ctrl+O to expand) "
|
||||
16| "▌ … +5 lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=green
|
||||
style 2-30 dim
|
||||
19| "▌ + expect(screen).toMatchSnapshot() "
|
||||
17| "▌ + expect(screen).toMatchSnapshot() "
|
||||
style 0-0 fg=green
|
||||
style 2-35 fg=green
|
||||
18| "▌ "
|
||||
style 0-0 fg=green
|
||||
19| <blank>
|
||||
20| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| <blank>
|
||||
22| "▌ "
|
||||
style 0-0 fg=green
|
||||
23| "▌ ✓ Delegate renderer audit "
|
||||
21| "▌ ✓ Delegate renderer audit "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-26 bold
|
||||
24| "▌ The renderer has explicit lifecycle ownership. "
|
||||
22| "▌ The renderer has explicit lifecycle ownership. "
|
||||
style 0-0 fg=green
|
||||
23| "▌ "
|
||||
style 0-0 fg=green
|
||||
24| <blank>
|
||||
25| "▌ "
|
||||
style 0-0 fg=green
|
||||
26| <blank>
|
||||
27| "▌ "
|
||||
style 0-0 fg=green
|
||||
28| "▌ ✓ Read output from background task subagent-7 "
|
||||
26| "▌ ✓ Read output from background task subagent-7 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-46 bold
|
||||
29| "▌ audit complete "
|
||||
27| "▌ audit complete "
|
||||
style 0-0 fg=green
|
||||
30| "▌ [status: completed] "
|
||||
28| "▌ [status: completed] "
|
||||
style 0-0 fg=green
|
||||
29| "▌ "
|
||||
style 0-0 fg=green
|
||||
30| <blank>
|
||||
31| "▌ "
|
||||
style 0-0 fg=green
|
||||
32| <blank>
|
||||
33| "▌ "
|
||||
style 0-0 fg=green
|
||||
34| "▌ ✓ Load skill dsh-code-review "
|
||||
32| "▌ ✓ Load skill dsh-code-review "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-29 bold
|
||||
35| "▌ Loaded review instructions. "
|
||||
33| "▌ Loaded review instructions. "
|
||||
style 0-0 fg=green
|
||||
36| "▌ "
|
||||
34| "▌ "
|
||||
style 0-0 fg=green
|
||||
35| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
36| " "
|
||||
style 1-1 inverse
|
||||
37| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
38| " "
|
||||
style 1-1 inverse
|
||||
39| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
40| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 42-99 dim
|
||||
38| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 73-99 dim
|
||||
39| <blank>
|
||||
|
||||
@@ -1,127 +1,117 @@
|
||||
terminal 100x40 buffer=normal length=50 base=10 viewport=10
|
||||
terminal 100x40 buffer=normal length=48 base=8 viewport=8
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=37 bufferRow=47
|
||||
cursor hidden column=1 viewportRow=37 bufferRow=45
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=green
|
||||
7| "▌ ✓ pnpm run test:coverage "
|
||||
5| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
8| "▌ Run the coverage gate "
|
||||
6| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
9| "▌ /workspace/project "
|
||||
7| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
10| "▌ packages/ui/tui 100% "
|
||||
8| "▌ packages/ui/tui 100% "
|
||||
style 0-0 fg=green
|
||||
11| "▌ 4016 tests passed "
|
||||
9| "▌ 4016 tests passed "
|
||||
style 0-0 fg=green
|
||||
12| "▌ 1 test skipped "
|
||||
10| "▌ 1 test skipped "
|
||||
style 0-0 fg=green
|
||||
13| "▌ coverage complete "
|
||||
11| "▌ coverage complete "
|
||||
style 0-0 fg=green
|
||||
14| "▌ [exit 0] "
|
||||
12| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
13| "▌ "
|
||||
style 0-0 fg=green
|
||||
14| <blank>
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ ✓ Edit renderer "
|
||||
16| "▌ ✓ Edit renderer "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
19| "▌ src/view.ts "
|
||||
17| "▌ src/view.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-12 bold
|
||||
20| "▌ - old line "
|
||||
18| "▌ - old line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=red
|
||||
21| "▌ - keep "
|
||||
19| "▌ - keep "
|
||||
style 0-0 fg=green
|
||||
style 2-7 fg=red
|
||||
22| "▌ + new line "
|
||||
20| "▌ + new line "
|
||||
style 0-0 fg=green
|
||||
style 2-11 fg=green
|
||||
23| "▌ + keep "
|
||||
21| "▌ + keep "
|
||||
style 0-0 fg=green
|
||||
style 2-7 fg=green
|
||||
24| "▌ "
|
||||
22| "▌ "
|
||||
style 0-0 fg=green
|
||||
25| "▌ tests/view.spec.ts "
|
||||
23| "▌ tests/view.spec.ts "
|
||||
style 0-0 fg=green
|
||||
style 2-19 bold
|
||||
26| "▌ + expect(screen).toMatchSnapshot() "
|
||||
24| "▌ + expect(screen).toMatchSnapshot() "
|
||||
style 0-0 fg=green
|
||||
style 2-35 fg=green
|
||||
25| "▌ "
|
||||
style 0-0 fg=green
|
||||
26| <blank>
|
||||
27| "▌ "
|
||||
style 0-0 fg=green
|
||||
28| <blank>
|
||||
29| "▌ "
|
||||
style 0-0 fg=green
|
||||
30| "▌ ✓ Delegate renderer audit "
|
||||
28| "▌ ✓ Delegate renderer audit "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-26 bold
|
||||
31| "▌ The renderer has explicit lifecycle ownership. "
|
||||
29| "▌ The renderer has explicit lifecycle ownership. "
|
||||
style 0-0 fg=green
|
||||
30| "▌ "
|
||||
style 0-0 fg=green
|
||||
31| <blank>
|
||||
32| "▌ "
|
||||
style 0-0 fg=green
|
||||
33| <blank>
|
||||
34| "▌ "
|
||||
style 0-0 fg=green
|
||||
35| "▌ ✓ Read output from background task subagent-7 "
|
||||
33| "▌ ✓ Read output from background task subagent-7 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-46 bold
|
||||
36| "▌ audit complete "
|
||||
34| "▌ audit complete "
|
||||
style 0-0 fg=green
|
||||
37| "▌ [status: completed] "
|
||||
35| "▌ [status: completed] "
|
||||
style 0-0 fg=green
|
||||
36| "▌ "
|
||||
style 0-0 fg=green
|
||||
37| <blank>
|
||||
38| "▌ "
|
||||
style 0-0 fg=green
|
||||
39| <blank>
|
||||
40| "▌ "
|
||||
style 0-0 fg=green
|
||||
41| "▌ ✓ Load skill dsh-code-review "
|
||||
39| "▌ ✓ Load skill dsh-code-review "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-29 bold
|
||||
42| "▌ Loaded review instructions. "
|
||||
40| "▌ Loaded review instructions. "
|
||||
style 0-0 fg=green
|
||||
43| "▌ "
|
||||
41| "▌ "
|
||||
style 0-0 fg=green
|
||||
44| <blank>
|
||||
45| " Tool cards expanded. "
|
||||
42| <blank>
|
||||
43| " Tool cards expanded. "
|
||||
style 1-20 fg=bright-black
|
||||
44| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
45| " "
|
||||
style 1-1 inverse
|
||||
46| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
47| " "
|
||||
style 1-1 inverse
|
||||
48| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
49| "/workspace/project ↑0 ↓0 0% context tools:expanded deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 41-99 dim
|
||||
47| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:expanded"
|
||||
style 0-43 dim
|
||||
style 74-99 dim
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=4 bufferRow=4
|
||||
viewport
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-1 fg=#4d6bfe bold
|
||||
style 2-2 fg=#4772fe bold
|
||||
style 3-3 fg=#4278ff bold
|
||||
style 4-4 fg=#3c7fff bold
|
||||
style 5-5 fg=#3685ff bold
|
||||
style 6-6 fg=#308bff bold
|
||||
style 7-7 fg=#2a92ff bold
|
||||
style 8-8 fg=#2498ff bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
4| " "
|
||||
style 1-1 inverse
|
||||
5| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
6| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
7-35| <blank>
|
||||
@@ -1,52 +1,42 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=15 bufferRow=15
|
||||
cursor hidden column=1 viewportRow=13 bufferRow=13
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
7| "▌ ◌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
5| "▌ ◌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-95 bold
|
||||
8| "▌ const second = await tools.bas "
|
||||
6| "▌ const second = await tools.bas "
|
||||
style 0-0 fg=yellow
|
||||
style 2-31 bold
|
||||
9| "▌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
7| "▌ const first = await tools.bash({ command: 'echo CODE_ONE' }) "
|
||||
style 0-0 fg=yellow
|
||||
10| "▌ const second = await tools.bash({ command: 'echo CODE_TWO' }) "
|
||||
8| "▌ const second = await tools.bash({ command: 'echo CODE_TWO' }) "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ console.log(first, second) "
|
||||
9| "▌ console.log(first, second) "
|
||||
style 0-0 fg=yellow
|
||||
12| "▌ return `${first}+${second}` "
|
||||
10| "▌ return `${first}+${second}` "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ "
|
||||
11| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
12| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
13| " "
|
||||
style 1-1 inverse
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| " "
|
||||
style 1-1 inverse
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
17| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
18-35| <blank>
|
||||
15| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
16-35| <blank>
|
||||
|
||||
@@ -3,50 +3,44 @@ lifecycle started=1 stopped=0 progress=active
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=17 bufferRow=17
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Show the live update. "
|
||||
6| "▌ Show the live update. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
8| <blank>
|
||||
9| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " Inspecting width and styles. "
|
||||
10| " Inspecting width and styles. "
|
||||
style 1-28 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| " Assistant "
|
||||
11| <blank>
|
||||
12| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
15| " Streaming visible state… "
|
||||
13| " Streaming visible state… "
|
||||
style 11-23 bold
|
||||
14| <blank>
|
||||
15| " ⠋ Responding 0s · total 0s — Enter sends steering, Esc cancels "
|
||||
style 1-1 fg=bright-blue
|
||||
style 3-62 fg=bright-black
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 fg=bright-blue
|
||||
17| " "
|
||||
style 1-1 inverse
|
||||
18| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 fg=bright-blue
|
||||
19| "◒ Working · 0s esc interrupt"
|
||||
style 0-13 fg=bright-blue
|
||||
style 83-95 dim
|
||||
19| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
20-35| <blank>
|
||||
|
||||
@@ -1,59 +1,49 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=18 bufferRow=18
|
||||
cursor hidden column=1 viewportRow=16 bufferRow=16
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ ◌ Inspect cordis runtime: tools "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ ◌ Inspect cordis runtime: tools "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-32 bold
|
||||
7| <blank>
|
||||
8| "▌ "
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
9| "▌ ◌ Mount plugin into live cordis runtime "
|
||||
7| "▌ ◌ Mount plugin into live cordis runtime "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-40 bold
|
||||
10| "▌ { "
|
||||
8| "▌ { "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ \"code\": \"return { name: 'snapshot-marker', apply(ctx) { ctx.provide('snapshotMarker', { "
|
||||
9| "▌ \"code\": \"return { name: 'snapshot-marker', apply(ctx) { ctx.provide('snapshotMarker', { "
|
||||
style 0-0 fg=yellow
|
||||
12| "▌ ready: true }) } }\" "
|
||||
10| "▌ ready: true }) } }\" "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ } "
|
||||
11| "▌ } "
|
||||
style 0-0 fg=yellow
|
||||
14| "▌ "
|
||||
12| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
15| <blank>
|
||||
16| "▌ ◌ Unmount dyn-1 "
|
||||
13| <blank>
|
||||
14| "▌ ◌ Unmount dyn-1 "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-16 bold
|
||||
15| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
16| " "
|
||||
style 1-1 inverse
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
18| " "
|
||||
style 1-1 inverse
|
||||
19| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
20| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
21-35| <blank>
|
||||
18| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
19-35| <blank>
|
||||
|
||||
@@ -1,67 +1,63 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=1 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor visible column=0 viewportRow=30 bufferRow=30
|
||||
cursor visible column=0 viewportRow=31 bufferRow=31
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Keyboard shortcuts "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Keyboard shortcuts "
|
||||
style 1-18 fg=bright-blue bold
|
||||
7| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
5| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 1-61 fg=bright-black
|
||||
8| " Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
6| " Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
style 1-75 fg=bright-black
|
||||
9| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
7| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 1-73 fg=bright-black
|
||||
10| " "
|
||||
11| " /cancel — Cancel the active turn "
|
||||
style 1-32 fg=bright-black
|
||||
12| " /clear — Clear the transcript view (session history is unchanged) "
|
||||
8| " "
|
||||
9| " /clear — Clear the transcript view (session history is unchanged) "
|
||||
style 1-65 fg=bright-black
|
||||
13| " /exit — Exit after the active turn reaches idle "
|
||||
10| " /exit — Exit after the active turn reaches idle "
|
||||
style 1-47 fg=bright-black
|
||||
14| " /help — Show keyboard shortcuts and commands "
|
||||
11| " /help — Show keyboard shortcuts and commands "
|
||||
style 1-44 fg=bright-black
|
||||
15| " /model [[provider/]model] — Show or switch this session's model "
|
||||
12| " /model [[provider/]model] — Show or switch this session's model "
|
||||
style 1-63 fg=bright-black
|
||||
16| " /reasoning — Toggle reasoning blocks "
|
||||
13| " /reasoning — Toggle reasoning blocks "
|
||||
style 1-36 fg=bright-black
|
||||
17| " /redraw — Invalidate components and redraw the terminal "
|
||||
14| " /redraw — Invalidate components and redraw the terminal "
|
||||
style 1-55 fg=bright-black
|
||||
15| " /reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
style 1-88 fg=bright-black
|
||||
16| " /resume — List this workspace's resumable sessions "
|
||||
style 1-50 fg=bright-black
|
||||
17| " /status — Show detailed session diagnostics "
|
||||
style 1-43 fg=bright-black
|
||||
18| " /tools — Expand or collapse all tool cards "
|
||||
style 1-42 fg=bright-black
|
||||
19| <blank>
|
||||
20| " provider stream failed after partial output "
|
||||
19| " /skill:<name> [instructions] — load a skill into the conversation "
|
||||
style 1-65 fg=bright-black
|
||||
20| <blank>
|
||||
21| " provider stream failed after partial output "
|
||||
style 1-43 fg=red
|
||||
21| <blank>
|
||||
22| " The previous process ended during this turn. "
|
||||
22| <blank>
|
||||
23| " The previous process ended during this turn. "
|
||||
style 1-44 fg=yellow
|
||||
23| <blank>
|
||||
24| " Unknown command: /unknown-advanced-command "
|
||||
24| <blank>
|
||||
25| " Unknown command: /unknown-advanced-command "
|
||||
style 1-42 fg=yellow
|
||||
25| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
26| " "
|
||||
27| " "
|
||||
style 1-1 inverse
|
||||
27| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
28| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
28| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 34-91 dim
|
||||
29-31| <blank>
|
||||
29| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 65-91 dim
|
||||
30-31| <blank>
|
||||
|
||||
@@ -1,56 +1,46 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=17 bufferRow=17
|
||||
cursor hidden column=1 viewportRow=15 bufferRow=15
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
7| "▌ ◌ workflow: tui-matrix "
|
||||
5| "▌ ◌ workflow: tui-matrix "
|
||||
style 0-0 fg=yellow
|
||||
style 2-2 fg=yellow bold
|
||||
style 3-23 bold
|
||||
8| "▌ phase('Inspect') "
|
||||
6| "▌ phase('Inspect') "
|
||||
style 0-0 fg=yellow
|
||||
9| "▌ const reports = await parallel([ "
|
||||
7| "▌ const reports = await parallel([ "
|
||||
style 0-0 fg=yellow
|
||||
10| "▌ () => agent('Audit layout', { label: 'layout', phase: 'Inspect' }), "
|
||||
8| "▌ () => agent('Audit layout', { label: 'layout', phase: 'Inspect' }), "
|
||||
style 0-0 fg=yellow
|
||||
11| "▌ … +1 lines (Ctrl+O to expand) "
|
||||
9| "▌ … +1 lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=yellow
|
||||
style 2-30 dim
|
||||
12| "▌ ]) "
|
||||
10| "▌ ]) "
|
||||
style 0-0 fg=yellow
|
||||
13| "▌ phase('Verify') "
|
||||
11| "▌ phase('Verify') "
|
||||
style 0-0 fg=yellow
|
||||
14| "▌ return { reports, verdict: 'covered' } "
|
||||
12| "▌ return { reports, verdict: 'covered' } "
|
||||
style 0-0 fg=yellow
|
||||
15| "▌ "
|
||||
13| "▌ "
|
||||
style 0-0 fg=yellow
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| " "
|
||||
style 1-1 inverse
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
17| " "
|
||||
style 1-1 inverse
|
||||
18| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
19| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
20-35| <blank>
|
||||
17| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
18-35| <blank>
|
||||
|
||||
@@ -1,67 +1,63 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=26 bufferRow=26
|
||||
cursor hidden column=1 viewportRow=27 bufferRow=27
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Keyboard shortcuts "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Keyboard shortcuts "
|
||||
style 1-18 fg=bright-blue bold
|
||||
7| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
5| " Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 1-61 fg=bright-black
|
||||
8| " Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
6| " Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
style 1-75 fg=bright-black
|
||||
9| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
7| " Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 1-73 fg=bright-black
|
||||
10| " "
|
||||
11| " /cancel — Cancel the active turn "
|
||||
style 1-32 fg=bright-black
|
||||
12| " /clear — Clear the transcript view (session history is unchanged) "
|
||||
8| " "
|
||||
9| " /clear — Clear the transcript view (session history is unchanged) "
|
||||
style 1-65 fg=bright-black
|
||||
13| " /exit — Exit after the active turn reaches idle "
|
||||
10| " /exit — Exit after the active turn reaches idle "
|
||||
style 1-47 fg=bright-black
|
||||
14| " /help — Show keyboard shortcuts and commands "
|
||||
11| " /help — Show keyboard shortcuts and commands "
|
||||
style 1-44 fg=bright-black
|
||||
15| " /model [[provider/]model] — Show or switch this session's model "
|
||||
12| " /model [[provider/]model] — Show or switch this session's model "
|
||||
style 1-63 fg=bright-black
|
||||
16| " /reasoning — Toggle reasoning blocks "
|
||||
13| " /reasoning — Toggle reasoning blocks "
|
||||
style 1-36 fg=bright-black
|
||||
17| " /redraw — Invalidate components and redraw the terminal "
|
||||
14| " /redraw — Invalidate components and redraw the terminal "
|
||||
style 1-55 fg=bright-black
|
||||
15| " /reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
style 1-88 fg=bright-black
|
||||
16| " /resume — List this workspace's resumable sessions "
|
||||
style 1-50 fg=bright-black
|
||||
17| " /status — Show detailed session diagnostics "
|
||||
style 1-43 fg=bright-black
|
||||
18| " /tools — Expand or collapse all tool cards "
|
||||
style 1-42 fg=bright-black
|
||||
19| <blank>
|
||||
20| " provider stream failed after partial output "
|
||||
19| " /skill:<name> [instructions] — load a skill into the conversation "
|
||||
style 1-65 fg=bright-black
|
||||
20| <blank>
|
||||
21| " provider stream failed after partial output "
|
||||
style 1-43 fg=red
|
||||
21| <blank>
|
||||
22| " The previous process ended during this turn. "
|
||||
22| <blank>
|
||||
23| " The previous process ended during this turn. "
|
||||
style 1-44 fg=yellow
|
||||
23| <blank>
|
||||
24| " Unknown command: /unknown-advanced-command "
|
||||
24| <blank>
|
||||
25| " Unknown command: /unknown-advanced-command "
|
||||
style 1-42 fg=yellow
|
||||
25| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
26| " "
|
||||
27| " "
|
||||
style 1-1 inverse
|
||||
27| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
28| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
28| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 34-91 dim
|
||||
29-31| <blank>
|
||||
29| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 65-91 dim
|
||||
30-31| <blank>
|
||||
|
||||
@@ -3,33 +3,23 @@ lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=0 viewportRow=31 bufferRow=31
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
4| " "
|
||||
style 1-1 inverse
|
||||
5| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
6| " "
|
||||
style 1-1 inverse
|
||||
7| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
8| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 34-91 dim
|
||||
9-12| <blank>
|
||||
6| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 65-91 dim
|
||||
7-12| <blank>
|
||||
13| " ╭ Select model ────────────────────────────────────────────────────────╮ "
|
||||
style 10-81 fg=bright-blue
|
||||
14| " │ → deepseek/deepseek-v4-flash DeepSeek V4 Flash — current │ "
|
||||
|
||||
@@ -1,35 +1,25 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=8 bufferRow=8
|
||||
cursor hidden column=1 viewportRow=6 bufferRow=6
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-91 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 91-91 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 91-91 fg=bright-blue
|
||||
3| "│ deepseek-v4-pro • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-33 dim
|
||||
style 91-91 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-91 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Model selected: deepseek/deepseek-v4-pro. New steps will use it. "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-pro • main-session"
|
||||
style 1-32 dim
|
||||
3| <blank>
|
||||
4| " Model selected: deepseek/deepseek-v4-pro. New steps will use it. "
|
||||
style 1-64 fg=bright-black
|
||||
5| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
6| " "
|
||||
style 1-1 inverse
|
||||
7| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
8| " "
|
||||
style 1-1 inverse
|
||||
9| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
10| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-pro(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 36-91 dim
|
||||
11-31| <blank>
|
||||
8| "deepseek-v4-pro /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-41 dim
|
||||
style 65-91 dim
|
||||
9-31| <blank>
|
||||
|
||||
@@ -3,23 +3,17 @@ lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=56 viewportRow=17 bufferRow=17
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────╮"
|
||||
style 0-55 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 55-55 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 55-55 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 55-55 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────╯"
|
||||
style 0-55 fg=bright-blue
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| "────────────────────────────────────────────────────────"
|
||||
style 0-55 dim
|
||||
4| " "
|
||||
style 1-1 inverse
|
||||
5| " "
|
||||
6| " Question 1/3 (3 unanswered) · Coverage "
|
||||
style 2-39 fg=bright-black
|
||||
|
||||
@@ -3,27 +3,22 @@ lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=0 viewportRow=19 bufferRow=19
|
||||
viewport
|
||||
0| "╭──────────────────────────────────────────────────────╮"
|
||||
style 0-55 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 55-55 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 55-55 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 55-55 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────╯"
|
||||
style 0-55 fg=bright-blue
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| "────────────────────────────────────────────────────────"
|
||||
style 0-55 dim
|
||||
4| " "
|
||||
style 1-1 inverse
|
||||
5| "────────────────────────────────────────────────────────"
|
||||
style 0-55 dim
|
||||
6| " "
|
||||
style 1-1 inverse
|
||||
6| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context"
|
||||
style 0-43 dim
|
||||
style 46-55 dim
|
||||
7| " "
|
||||
8| " Question 1/3 (3 unanswered) · Coverage "
|
||||
style 2-39 fg=bright-black
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=10 bufferRow=10
|
||||
buffer
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Resumable sessions "
|
||||
style 1-18 fg=bright-blue bold
|
||||
5| " 2024-01-02 03:04 (current) "
|
||||
style 1-16 fg=bright-black
|
||||
style 17-26 fg=green
|
||||
6| " RESUME_SESSION_ID=main-session dsh "
|
||||
7| " 2024-01-01 00:00 "
|
||||
style 1-16 fg=bright-black
|
||||
8| " RESUME_SESSION_ID=earlier-session dsh "
|
||||
9| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
10| " "
|
||||
style 1-1 inverse
|
||||
11| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
12| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 65-91 dim
|
||||
13-31| <blank>
|
||||
@@ -1,48 +1,38 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=15 bufferRow=15
|
||||
cursor hidden column=1 viewportRow=13 bufferRow=13
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Start then cancel. "
|
||||
6| "▌ Start then cancel. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Retrying model request (1/2) in 1000ms: temporary transport failure "
|
||||
8| <blank>
|
||||
9| " Retrying model request (1/2) in 1000ms: temporary transport failure "
|
||||
style 1-67 fg=yellow
|
||||
12| <blank>
|
||||
13| " Turn cancelled. "
|
||||
10| <blank>
|
||||
11| " Turn cancelled. "
|
||||
style 1-15 fg=yellow
|
||||
12| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
13| " "
|
||||
style 1-1 inverse
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| " "
|
||||
style 1-1 inverse
|
||||
16| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
17| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
18-35| <blank>
|
||||
15| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
16-35| <blank>
|
||||
|
||||
@@ -1,45 +1,35 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=13 bufferRow=13
|
||||
cursor hidden column=1 viewportRow=11 bufferRow=11
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Let the bounded policy exhaust. "
|
||||
6| "▌ Let the bounded policy exhaust. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " provider still unavailable "
|
||||
8| <blank>
|
||||
9| " provider still unavailable "
|
||||
style 1-26 fg=red
|
||||
10| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
11| " "
|
||||
style 1-1 inverse
|
||||
12| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
13| " "
|
||||
style 1-1 inverse
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
16-35| <blank>
|
||||
13| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
14-35| <blank>
|
||||
|
||||
@@ -1,49 +1,39 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=16 bufferRow=16
|
||||
cursor hidden column=1 viewportRow=14 bufferRow=14
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Recover this request. "
|
||||
6| "▌ Recover this request. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Retrying model request (1/2) in 500ms: provider rate limit "
|
||||
8| <blank>
|
||||
9| " Retrying model request (1/2) in 500ms: provider rate limit "
|
||||
style 1-58 fg=yellow
|
||||
12| <blank>
|
||||
13| " Assistant "
|
||||
10| <blank>
|
||||
11| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
14| " Recovered on the next bounded attempt. "
|
||||
12| " Recovered on the next bounded attempt. "
|
||||
13| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
14| " "
|
||||
style 1-1 inverse
|
||||
15| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
16| " "
|
||||
style 1-1 inverse
|
||||
17| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
18| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
19-35| <blank>
|
||||
16| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
17-35| <blank>
|
||||
|
||||
@@ -1,45 +1,35 @@
|
||||
terminal 96x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=13 bufferRow=13
|
||||
cursor hidden column=1 viewportRow=11 bufferRow=11
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-95 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 95-95 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 95-95 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-95 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Recover this request. "
|
||||
6| "▌ Recover this request. "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Retrying model request (1/2) in 500ms: provider rate limit "
|
||||
8| <blank>
|
||||
9| " Retrying model request (1/2) in 500ms: provider rate limit "
|
||||
style 1-58 fg=yellow
|
||||
10| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
11| " "
|
||||
style 1-1 inverse
|
||||
12| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
13| " "
|
||||
style 1-1 inverse
|
||||
14| "────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-95 dim
|
||||
15| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 38-95 dim
|
||||
16-35| <blank>
|
||||
13| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 69-95 dim
|
||||
14-35| <blank>
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
terminal 56x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Inspect session diagnostics — DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=32 bufferRow=32
|
||||
buffer
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Inspect session diagnostics"
|
||||
style 1-27 fg=bright-black
|
||||
2| " deepseek-v4-pro • main-session"
|
||||
style 1-32 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
6| "▌ inspect this session "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
8| <blank>
|
||||
9| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
10| " Session inspected. "
|
||||
11| <blank>
|
||||
12| "╭─ Session status ─────────────────────────────────────╮"
|
||||
style 0-2 dim
|
||||
style 3-16 fg=bright-blue bold
|
||||
style 17-55 dim
|
||||
13| "│ Session: main-session │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
14| "│ Title: Inspect session diagnostics │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
15| "│ Directory: /workspace/project │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
16| "│ Model: deepseek/deepseek-v4-pro (reasoning │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 40-55 dim
|
||||
17| "│ shown) │"
|
||||
style 0-0 dim
|
||||
style 15-20 dim
|
||||
style 55-55 dim
|
||||
18| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
19| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
20| "│ tool call │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
21| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
22| "│ Tokens: 1,250 input + 340 output │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
23| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 15-15 dim
|
||||
style 16-26 fg=bright-blue
|
||||
style 27-32 dim
|
||||
style 55-55 dim
|
||||
24| "│ + 250 write) │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
25| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 15-15 dim
|
||||
style 16-20 fg=bright-blue
|
||||
style 21-32 dim
|
||||
style 55-55 dim
|
||||
26| "│ 128,000) │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
27| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
28| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
29| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 55-55 dim
|
||||
30| "╰──────────────────────────────────────────────────────╯"
|
||||
style 0-55 dim
|
||||
31| "────────────────────────────────────────────────────────"
|
||||
style 0-55 dim
|
||||
32| " "
|
||||
style 1-1 inverse
|
||||
33| "────────────────────────────────────────────────────────"
|
||||
style 0-55 dim
|
||||
34| "deepseek-v4-pro /workspace/project ↑1.3k ↓340 cache 6"
|
||||
style 0-55 dim
|
||||
35| <blank>
|
||||
@@ -0,0 +1,99 @@
|
||||
terminal 92x32 buffer=normal length=32 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Inspect session diagnostics — DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=28 bufferRow=28
|
||||
buffer
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Inspect session diagnostics"
|
||||
style 1-27 fg=bright-black
|
||||
2| " deepseek-v4-pro • main-session"
|
||||
style 1-32 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
6| "▌ inspect this session "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
8| <blank>
|
||||
9| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
10| " Session inspected. "
|
||||
11| <blank>
|
||||
12| "╭─ Session status ─────────────────────────────────────────────────╮"
|
||||
style 0-2 dim
|
||||
style 3-16 fg=bright-blue bold
|
||||
style 17-67 dim
|
||||
13| "│ Session: main-session │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
14| "│ Title: Inspect session diagnostics │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
15| "│ Directory: /workspace/project │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
16| "│ Model: deepseek/deepseek-v4-pro (reasoning shown) │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 40-56 dim
|
||||
style 67-67 dim
|
||||
17| "│ │"
|
||||
style 0-0 dim
|
||||
style 67-67 dim
|
||||
18| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 tool call │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
19| "│ │"
|
||||
style 0-0 dim
|
||||
style 67-67 dim
|
||||
20| "│ Tokens: 1,250 input + 340 output │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
21| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read + 250 write) │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 15-15 dim
|
||||
style 16-26 fg=bright-blue
|
||||
style 27-32 dim
|
||||
style 67-67 dim
|
||||
22| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / 128,000) │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 15-15 dim
|
||||
style 16-20 fg=bright-blue
|
||||
style 21-32 dim
|
||||
style 67-67 dim
|
||||
23| "│ │"
|
||||
style 0-0 dim
|
||||
style 67-67 dim
|
||||
24| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
25| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 fg=bright-black
|
||||
style 67-67 dim
|
||||
26| "╰──────────────────────────────────────────────────────────────────╯"
|
||||
style 0-67 dim
|
||||
27| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
28| " "
|
||||
style 1-1 inverse
|
||||
29| "────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-91 dim
|
||||
30| "deepseek-v4-pro /workspace/project ↑1.3k ↓340 cache 67% 33% context tools:collapsed"
|
||||
style 0-57 dim
|
||||
style 64-91 dim
|
||||
31| <blank>
|
||||
@@ -1,40 +1,30 @@
|
||||
terminal 44x18 buffer=normal length=18 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=11 bufferRow=11
|
||||
cursor hidden column=1 viewportRow=9 bufferRow=9
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────╮"
|
||||
style 0-43 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 43-43 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 43-43 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 43-43 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────╯"
|
||||
style 0-43 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Context · compact "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Context · compact "
|
||||
style 1-17 dim
|
||||
7| " Compacted summary: the prior command "
|
||||
5| " Compacted summary: the prior command "
|
||||
style 1-43 fg=bright-black
|
||||
8| " completed and its details were retired "
|
||||
6| " completed and its details were retired "
|
||||
style 1-43 fg=bright-black
|
||||
9| " from the active surface. "
|
||||
7| " from the active surface. "
|
||||
style 1-24 fg=bright-black
|
||||
8| "────────────────────────────────────────────"
|
||||
style 0-43 dim
|
||||
9| " "
|
||||
style 1-1 inverse
|
||||
10| "────────────────────────────────────────────"
|
||||
style 0-43 dim
|
||||
11| " "
|
||||
style 1-1 inverse
|
||||
12| "────────────────────────────────────────────"
|
||||
11| "deepseek-v4-flash /workspace/project ↑0 ↓0"
|
||||
style 0-43 dim
|
||||
13| " 0% context deepseek-v4-flash(reasoning:on)"
|
||||
style 1-43 dim
|
||||
14-17| <blank>
|
||||
12-17| <blank>
|
||||
|
||||
@@ -1,37 +1,27 @@
|
||||
terminal 104x30 buffer=normal length=30 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=9 bufferRow=9
|
||||
cursor hidden column=1 viewportRow=7 bufferRow=7
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-103 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 103-103 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 103-103 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 103-103 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-103 fg=bright-blue
|
||||
5| <blank>
|
||||
6| " Context · compact "
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Context · compact "
|
||||
style 1-17 dim
|
||||
7| " Compacted summary: the prior command completed and its details were retired from the active surface. "
|
||||
5| " Compacted summary: the prior command completed and its details were retired from the active surface. "
|
||||
style 1-100 fg=bright-black
|
||||
6| "────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-103 dim
|
||||
7| " "
|
||||
style 1-1 inverse
|
||||
8| "────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-103 dim
|
||||
9| " "
|
||||
style 1-1 inverse
|
||||
10| "────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-103 dim
|
||||
11| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 46-103 dim
|
||||
12-29| <blank>
|
||||
9| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 77-103 dim
|
||||
10-29| <blank>
|
||||
|
||||
@@ -1,68 +1,59 @@
|
||||
terminal 80x24 buffer=normal length=25 base=1 viewport=1
|
||||
terminal 80x24 buffer=normal length=24 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH snapshot"
|
||||
cursor hidden column=1 viewportRow=21 bufferRow=22
|
||||
cursor hidden column=1 viewportRow=20 bufferRow=20
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-79 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Snapshot agent ready."
|
||||
style 1-21 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 79-79 fg=bright-blue
|
||||
2| "│ Snapshot agent ready. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-22 fg=bright-black
|
||||
style 79-79 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 79-79 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-79 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Old prompt with a long line that exercises wrapping before compaction. "
|
||||
6| "▌ Old prompt with a long line that exercises wrapping before compaction. "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
8| <blank>
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| "▌ "
|
||||
style 0-0 fg=green
|
||||
12| "▌ ✓ pnpm run test:coverage "
|
||||
10| "▌ ✓ pnpm run test:coverage "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-25 bold
|
||||
13| "▌ Run the coverage gate "
|
||||
11| "▌ Run the coverage gate "
|
||||
style 0-0 fg=green
|
||||
style 2-22 fg=bright-black
|
||||
14| "▌ /workspace/project "
|
||||
12| "▌ /workspace/project "
|
||||
style 0-0 fg=green
|
||||
style 2-19 dim
|
||||
15| "▌ packages/ui/tui 100% "
|
||||
13| "▌ packages/ui/tui 100% "
|
||||
style 0-0 fg=green
|
||||
16| "▌ … +1 lines (Ctrl+O to expand) "
|
||||
14| "▌ … +1 lines (Ctrl+O to expand) "
|
||||
style 0-0 fg=green
|
||||
style 2-30 dim
|
||||
17| "▌ 1 test skipped "
|
||||
15| "▌ 1 test skipped "
|
||||
style 0-0 fg=green
|
||||
18| "▌ coverage complete "
|
||||
16| "▌ coverage complete "
|
||||
style 0-0 fg=green
|
||||
19| "▌ [exit 0] "
|
||||
17| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
20| "▌ "
|
||||
18| "▌ "
|
||||
style 0-0 fg=green
|
||||
19| "────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-79 dim
|
||||
20| " "
|
||||
style 1-1 inverse
|
||||
21| "────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-79 dim
|
||||
22| " "
|
||||
style 1-1 inverse
|
||||
23| "────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-79 dim
|
||||
24| "/workspace/pro ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-13 dim
|
||||
style 22-79 dim
|
||||
22| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 53-79 dim
|
||||
23| <blank>
|
||||
|
||||
@@ -1,87 +1,77 @@
|
||||
terminal 100x34 buffer=normal length=40 base=6 viewport=6
|
||||
terminal 100x34 buffer=normal length=38 base=4 viewport=4
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Unsafe terminal title \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
|
||||
cursor hidden column=100 viewportRow=33 bufferRow=39
|
||||
cursor hidden column=100 viewportRow=33 bufferRow=37
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Unsafe welcome \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m"
|
||||
style 1-60 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Unsafe welcome \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-61 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Unsafe user \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
6| "▌ Unsafe user \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
8| <blank>
|
||||
9| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " Unsafe reasoning \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
10| " Unsafe reasoning \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 1-62 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| " Assistant "
|
||||
11| <blank>
|
||||
12| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
15| " Unsafe assistant \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
13| " Unsafe assistant \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
14| <blank>
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ ✓ Unsafe title \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
16| "▌ ✓ Unsafe title \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-61 bold
|
||||
19| "▌ Unsafe description \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
17| "▌ Unsafe description \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 0-0 fg=green
|
||||
style 2-65 fg=bright-black
|
||||
20| "▌ /unsafe/\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
18| "▌ /unsafe/\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 0-0 fg=green
|
||||
style 2-54 dim
|
||||
21| "▌ Unsafe output \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
19| "▌ Unsafe output \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 0-0 fg=green
|
||||
22| "▌ [signal SIG\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m] "
|
||||
20| "▌ [signal SIG\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m] "
|
||||
style 0-0 fg=green
|
||||
style 2-58 fg=red
|
||||
23| "▌ "
|
||||
21| "▌ "
|
||||
style 0-0 fg=green
|
||||
24| <blank>
|
||||
25| " Context · unsafe-\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
22| <blank>
|
||||
23| " Context · unsafe-\\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 1-62 dim
|
||||
26| " Unsafe context \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
24| " Unsafe context \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 1-60 fg=bright-black
|
||||
27| <blank>
|
||||
28| " Prompt blocked: Unsafe policy \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
25| <blank>
|
||||
26| " Prompt blocked: Unsafe policy \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 1-75 fg=yellow
|
||||
29| <blank>
|
||||
30| " Unsafe turn error \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
27| <blank>
|
||||
28| " Unsafe turn error \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 1-63 fg=red
|
||||
31| <blank>
|
||||
32| " "
|
||||
33| " Question 1/1 (1 unanswered) · Unsafe header \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
29| <blank>
|
||||
30| " "
|
||||
31| " Question 1/1 (1 unanswered) · Unsafe header \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
style 2-90 fg=bright-black
|
||||
34| " Unsafe question \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
35| " "
|
||||
36| " › 1. Unsafe option \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m Unsafe detail \\x1b]2;snapshot-c "
|
||||
32| " Unsafe question \\x1b]2;snapshot-controlled\\x07\\x09\\x7f\\x9b31m "
|
||||
33| " "
|
||||
34| " › 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
|
||||
37| " Tab custom answer • ↑/↓ navigate • Enter submit • Esc interrupt "
|
||||
35| " Tab custom answer • ↑/↓ navigate • Enter submit • Esc interrupt "
|
||||
style 2-64 dim
|
||||
38| " "
|
||||
39| "/workspace/project ↑0 ↓0 0% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 42-99 dim
|
||||
36| " "
|
||||
37| "deepseek-v4-flash /workspace/project ↑0 ↓0 0% context tools:collapsed"
|
||||
style 0-43 dim
|
||||
style 73-99 dim
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { mkdir, readdir, writeFile } from 'node:fs/promises'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { afterAll, describe, expect, it } from 'vitest'
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest'
|
||||
import type { Context } from 'cordis'
|
||||
import { agentEvents } from '@deepseek-ai/dsh-agent'
|
||||
import { CallId, type ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||
import type {} from '@deepseek-ai/dsh-llm-retry'
|
||||
import type { JsonValue, Session } from '@deepseek-ai/dsh-session'
|
||||
import { SessionId, type JsonValue, type Session } from '@deepseek-ai/dsh-session'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry, { type ToolDefinition, type ToolResultView } from '@deepseek-ai/dsh-tools'
|
||||
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
|
||||
@@ -30,6 +30,7 @@ const CHECKPOINTS = [
|
||||
'retry-recovered',
|
||||
'retry-cancelled',
|
||||
'retry-exhausted',
|
||||
'banner-gradient',
|
||||
'code-mode-pending',
|
||||
'dynamic-workflow-pending',
|
||||
'cordis-tools-pending',
|
||||
@@ -45,6 +46,9 @@ const CHECKPOINTS = [
|
||||
'model-switching',
|
||||
'errors-and-help',
|
||||
'disposed-terminal',
|
||||
'resume-sessions',
|
||||
'status-diagnostics',
|
||||
'status-diagnostics-narrow',
|
||||
] as const
|
||||
|
||||
type Checkpoint = typeof CHECKPOINTS[number]
|
||||
@@ -56,9 +60,23 @@ async function checkpoint(
|
||||
name: Checkpoint,
|
||||
terminal: HeadlessTerminal,
|
||||
options: TerminalSnapshotOptions = {},
|
||||
bannerGradient = false,
|
||||
): Promise<void> {
|
||||
observedCheckpoints.add(name)
|
||||
expect(terminal.themeViolations(), `${name} must remain theme-agnostic`).toEqual([])
|
||||
const violations = terminal.themeViolations()
|
||||
if (bannerGradient) {
|
||||
// The banner paints its product name in the DeepSeek brand gradient with
|
||||
// 24-bit foreground codes: the sole sanctioned truecolor. Require it to be
|
||||
// present and to never leak a background or extended-palette color into the
|
||||
// otherwise theme-agnostic UI.
|
||||
expect(violations, `${name} must render the banner gradient`).not.toEqual([])
|
||||
expect(
|
||||
violations.every(entry => entry.endsWith('rgb-fg')),
|
||||
`${name} must confine truecolor to the banner foreground`,
|
||||
).toBe(true)
|
||||
} else {
|
||||
expect(violations, `${name} must remain theme-agnostic`).toEqual([])
|
||||
}
|
||||
const snapshot = await terminal.snapshot(options)
|
||||
const path = join(SNAPSHOTS_DIR, `${name}.expected.txt`)
|
||||
if (REFRESHING) {
|
||||
@@ -309,6 +327,12 @@ describe('TUI terminal-state snapshots', () => {
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('paints the startup banner product name in the DeepSeek brand gradient on truecolor terminals', async () => {
|
||||
const harness = await setupSnapshot({ config: { truecolor: true } })
|
||||
await checkpoint('banner-gradient', harness.terminal, {}, true)
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins Code Mode run_code with its production presenter', async () => {
|
||||
const harness = await setupSnapshot({ configureContext: configureAdvancedTools })
|
||||
const call = {
|
||||
@@ -597,6 +621,63 @@ describe('TUI terminal-state snapshots', () => {
|
||||
await checkpoint('model-switching', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('lists this workspace\'s resumable sessions with their commands', async () => {
|
||||
const harness = await setupSnapshot({
|
||||
config: { resumeCommand: 'RESUME_SESSION_ID={session} dsh' },
|
||||
sessionPersistence: { list: async () => [
|
||||
{ version: 0, id: SessionId('main-session'), createdAt: Date.parse('2024-01-02T03:04:00Z'), cwd: '/workspace/project' },
|
||||
{ version: 0, id: SessionId('earlier-session'), createdAt: Date.parse('2024-01-01T00:00:00Z'), cwd: '/workspace/project' },
|
||||
] },
|
||||
}, { columns: 92, rows: 32 })
|
||||
harness.terminal.send('/resume')
|
||||
harness.terminal.send('\r')
|
||||
// `/resume` scans persistence asynchronously, so the listing renders a tick
|
||||
// after submit (the unit suite waits the same way); settle, then flush.
|
||||
await new Promise(resolve => setTimeout(resolve, 60))
|
||||
await harness.terminal.flush()
|
||||
await checkpoint('resume-sessions', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
})
|
||||
|
||||
it('pins the detailed session diagnostics card', async () => {
|
||||
const dateNow = vi.spyOn(Date, 'now').mockReturnValue(Date.parse('2026-07-22T09:10:11.000Z'))
|
||||
const harness = await setupSnapshot({
|
||||
contextWindow: 128_000,
|
||||
contextTokens: 42_000,
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek-v4-pro' },
|
||||
beforeMount(session) {
|
||||
appendUser(session, 'inspect this session')
|
||||
appendAssistant(session, [{ type: 'text', text: 'Session inspected.' }], {
|
||||
inputTokens: 1_250,
|
||||
outputTokens: 340,
|
||||
cacheReadTokens: 3_000,
|
||||
cacheWriteTokens: 250,
|
||||
})
|
||||
session.append('tool/call', {
|
||||
turn: 1,
|
||||
step: 1,
|
||||
callId: CallId('status-call'),
|
||||
name: 'read',
|
||||
arguments: '{"path":"README.md"}',
|
||||
})
|
||||
session.append('session/title', {
|
||||
title: 'Inspect session diagnostics',
|
||||
messageSeqs: [1],
|
||||
source: { kind: 'fallback' },
|
||||
})
|
||||
},
|
||||
}, { columns: 92, rows: 32 })
|
||||
await renderAfter(harness, () => {
|
||||
harness.terminal.send('/status')
|
||||
harness.terminal.send('\r')
|
||||
})
|
||||
await checkpoint('status-diagnostics', harness.terminal, { includeScrollback: true })
|
||||
await renderAfter(harness, () => { harness.terminal.resize(56, 36) })
|
||||
await checkpoint('status-diagnostics-narrow', harness.terminal, { includeScrollback: true })
|
||||
await disposeSnapshot(harness)
|
||||
dateNow.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@@ -4,9 +4,10 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import type { Terminal } from '@earendil-works/pi-tui'
|
||||
import AgentRegistry, { agentEvents, assembleContextFor, type Agent } from '@deepseek-ai/dsh-agent'
|
||||
import type { LlmCallConfig } from '@deepseek-ai/dsh-llm'
|
||||
import { type LlmCallConfig } from '@deepseek-ai/dsh-llm'
|
||||
import CommandService, { type CommandInvocation } from '@deepseek-ai/dsh-commands'
|
||||
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import SessionStore, { SessionId, type SessionHeader } from '@deepseek-ai/dsh-session'
|
||||
import SkillService, { type SkillDefinition, type SkillSummary } from '@deepseek-ai/dsh-skill'
|
||||
import type {} from '@deepseek-ai/dsh-session-title'
|
||||
import type { ToolDefinition } from '@deepseek-ai/dsh-tools'
|
||||
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
||||
@@ -14,6 +15,7 @@ import type {} from '@deepseek-ai/dsh-llm-retry'
|
||||
import {
|
||||
createTuiChat,
|
||||
mountTui,
|
||||
renderSkillInvocation,
|
||||
resolveTuiConfig,
|
||||
type TuiRuntime,
|
||||
} from '../src/index.ts'
|
||||
@@ -127,6 +129,15 @@ function provideTokenMeter(ctx: Context): void {
|
||||
} as never)
|
||||
}
|
||||
|
||||
/** Minimal advisory-catalog llm stub for tests composing their own context. */
|
||||
function provideLlmCatalog(ctx: Context): void {
|
||||
ctx.provide('llm', {
|
||||
listProviders: () => [],
|
||||
listModels: () => Promise.resolve([]),
|
||||
resolveModelContext: () => Promise.resolve(undefined),
|
||||
} as never)
|
||||
}
|
||||
|
||||
describe('TUI config', () => {
|
||||
it('defaults every direct-call TUI option', () => {
|
||||
expect(resolveTuiConfig(undefined)).toEqual({
|
||||
@@ -140,6 +151,7 @@ describe('TUI config', () => {
|
||||
modelDialogMaxHeight: 20,
|
||||
showHardwareCursor: false,
|
||||
color: true,
|
||||
truecolor: false,
|
||||
title: 'DeepSeek Harness',
|
||||
})
|
||||
expect(resolveTuiConfig({
|
||||
@@ -153,6 +165,7 @@ describe('TUI config', () => {
|
||||
modelDialogMaxHeight: 16,
|
||||
showHardwareCursor: true,
|
||||
color: false,
|
||||
truecolor: true,
|
||||
title: 'DSH',
|
||||
})).toEqual({
|
||||
showReasoning: false,
|
||||
@@ -165,11 +178,121 @@ describe('TUI config', () => {
|
||||
modelDialogMaxHeight: 16,
|
||||
showHardwareCursor: true,
|
||||
color: false,
|
||||
truecolor: true,
|
||||
title: 'DSH',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('resume command and /resume', () => {
|
||||
const RESUME = 'RESUME_SESSION_ID={session} dsh'
|
||||
const header = (id: string, createdAt: number, cwd: string): SessionHeader =>
|
||||
({ version: 0, id: SessionId(id), createdAt, cwd })
|
||||
|
||||
it('prints the resume command on exit once the session is persisted', async () => {
|
||||
const result = await setup({
|
||||
cwd: '/workspace',
|
||||
config: { resumeCommand: RESUME },
|
||||
sessionPersistence: { list: async () => [header('main-session', 1000, '/workspace')] },
|
||||
})
|
||||
result.terminal.send('/exit')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('To resume this session: RESUME_SESSION_ID=main-session dsh')
|
||||
expect(result.exit).toHaveBeenCalledWith(0)
|
||||
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 } })
|
||||
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)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('omits the exit hint when the session listing fails', async () => {
|
||||
const result = await setup({
|
||||
cwd: '/workspace',
|
||||
config: { resumeCommand: RESUME },
|
||||
sessionPersistence: { list: () => Promise.reject(new Error('disk gone')) },
|
||||
})
|
||||
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)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('lists this workspace\'s sessions newest-first and marks the current one', async () => {
|
||||
const result = await setup({
|
||||
cwd: '/workspace',
|
||||
config: { resumeCommand: RESUME },
|
||||
sessionPersistence: {
|
||||
list: async () => [
|
||||
header('main-session', 1000, '/workspace'),
|
||||
header('older-session', 500, '/workspace'),
|
||||
header('newer-session', 2000, '/workspace'),
|
||||
header('foreign-session', 3000, '/elsewhere'),
|
||||
],
|
||||
},
|
||||
})
|
||||
result.terminal.send('/resume')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
const output = result.terminal.output
|
||||
expect(output).toContain('Resumable sessions')
|
||||
expect(output).toContain('RESUME_SESSION_ID=main-session dsh')
|
||||
expect(output).toContain('(current)')
|
||||
expect(output).toContain('RESUME_SESSION_ID=newer-session dsh')
|
||||
expect(output).not.toContain('foreign-session')
|
||||
// Newest-first: the newer session's command precedes the current session's.
|
||||
// Match the full resume command, not the bare id: the banner detail line
|
||||
// echoes the current session id (`main-session`) above the listing.
|
||||
expect(output.indexOf('RESUME_SESSION_ID=newer-session')).toBeLessThan(
|
||||
output.indexOf('RESUME_SESSION_ID=main-session'),
|
||||
)
|
||||
expect(output.indexOf('RESUME_SESSION_ID=main-session')).toBeLessThan(
|
||||
output.indexOf('RESUME_SESSION_ID=older-session'),
|
||||
)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('warns from /resume when resume is not configured', async () => {
|
||||
const result = await setup({ cwd: '/workspace' })
|
||||
result.terminal.send('/resume')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Resume is not configured')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('warns from /resume when no persistence backend is mounted', async () => {
|
||||
const result = await setup({ cwd: '/workspace', config: { resumeCommand: RESUME } })
|
||||
result.terminal.send('/resume')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('no persistence backend is mounted')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('notes from /resume when no workspace sessions are persisted yet', async () => {
|
||||
const result = await setup({
|
||||
cwd: '/workspace',
|
||||
config: { resumeCommand: RESUME },
|
||||
sessionPersistence: { list: async () => [header('foreign-session', 10, '/elsewhere')] },
|
||||
})
|
||||
result.terminal.send('/resume')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('No resumable sessions found')
|
||||
await dispose(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('pi-tui chat lifecycle and transcript', () => {
|
||||
it('uses the latest log-backed title for the header subtitle and terminal window', async () => {
|
||||
const result = await setup({
|
||||
@@ -208,6 +331,9 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
const result = await setup({
|
||||
contextWindow: 100,
|
||||
contextTokens: 42,
|
||||
// Short cwd: the footer clips its right (context/tools) segment first,
|
||||
// and the default worktree path would swallow it at 88 columns.
|
||||
cwd: '/opt',
|
||||
now: () => now,
|
||||
beforeMount(session) {
|
||||
appendUser(session, 'restored prompt')
|
||||
@@ -234,13 +360,14 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
expect(result.terminal.output).toContain('restored answer')
|
||||
expect(result.terminal.output).toContain('write tests')
|
||||
expect(result.terminal.output).toContain('↑1.3k ↓42')
|
||||
expect(result.terminal.output).toContain('42% context tools:compact deepseek-v4-flash(reasoning:on)')
|
||||
// Context resolution is async (resolveModelContext); settle before reading.
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('42% context tools:collapsed')
|
||||
// Narrow terminals clip the right-hand context/tools segment first; the
|
||||
// model-led left segment stays.
|
||||
result.terminal.resize(52)
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('42% context deepseek-v4-flash(reasoning:on)')
|
||||
result.terminal.resize(65)
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('↑1.3k ↓42 42% context deepseek-v4-flash(reasoning:on)')
|
||||
expect(result.terminal.output).toContain('deepseek-v4-flash')
|
||||
result.terminal.resize(88)
|
||||
await tick()
|
||||
|
||||
@@ -329,8 +456,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
expect(result.terminal.output).toContain('final live answer')
|
||||
})
|
||||
|
||||
expect(result.terminal.output).toContain('◒ Working · 8s')
|
||||
expect(result.terminal.output).toContain('esc interrupt')
|
||||
expect(result.terminal.output).toContain('Enter sends steering, Esc cancels')
|
||||
expect(result.terminal.output).toContain('Steering')
|
||||
expect(result.terminal.output).toContain('user context')
|
||||
expect(result.terminal.output).toContain('Prompt blocked')
|
||||
@@ -352,7 +478,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
agentEvents(result.ctx, result.agent).emit('agent/status', 'idle')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('↑1.8k ↓50')
|
||||
expect(result.terminal.output).toContain('deepseek-v4-flash(reasoning:off)')
|
||||
expect(result.terminal.output).toContain('deepseek-v4-flash')
|
||||
expect(result.terminal.progress.at(-1)).toBe(false)
|
||||
await dispose(result)
|
||||
expect(result.terminal.stopped).toBe(1)
|
||||
@@ -421,6 +547,170 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('badges queued steering on the running status line and clears it as each drains', async () => {
|
||||
// Pin a cwd free of the substring under test; the footer renders the path.
|
||||
const result = await setup({ status: 'running', cwd: '/workspace' })
|
||||
// Running with nothing queued: the plain steering hint, no badge.
|
||||
expect(result.terminal.output).toContain('— Enter sends steering, Esc cancels')
|
||||
expect(result.terminal.output).not.toContain('queued')
|
||||
|
||||
const queueSteering = (text: string): void => {
|
||||
result.ctx.emit('agent/queued', result.agent, [{ type: 'text', text }], { source: { kind: 'user' }, steering: true })
|
||||
}
|
||||
const drainSteering = (text: string): void => {
|
||||
result.session.append('steering/message', { turn: 1, content: [{ type: 'text', text }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
// A steering queue for a different agent never touches this status line.
|
||||
const other = { ...result.agent, id: SessionId('other') } as Agent
|
||||
result.terminal.output = ''
|
||||
result.ctx.emit('agent/queued', other, [{ type: 'text', text: 'elsewhere' }], { source: { kind: 'user' }, steering: true })
|
||||
await tick()
|
||||
expect(result.terminal.output).not.toContain('queued')
|
||||
|
||||
// Two steering messages queue while the turn runs.
|
||||
queueSteering('first')
|
||||
result.terminal.output = ''
|
||||
queueSteering('second')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('2 queued · Enter sends steering, Esc cancels')
|
||||
|
||||
// A non-steering queue (an idle-style send) leaves the badge untouched.
|
||||
result.terminal.output = ''
|
||||
result.ctx.emit('agent/queued', result.agent, [{ type: 'text', text: 'sent' }], { source: { kind: 'user' }, steering: false })
|
||||
drainSteering('first')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('1 queued')
|
||||
expect(result.terminal.output).not.toContain('2 queued')
|
||||
|
||||
// Draining the last queued message returns the plain hint.
|
||||
result.terminal.output = ''
|
||||
drainSteering('second')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('— Enter sends steering, Esc cancels')
|
||||
expect(result.terminal.output).not.toContain('queued')
|
||||
|
||||
// A drain with no matching queued entry is ignored rather than underflowing.
|
||||
result.terminal.output = ''
|
||||
drainSteering('continuation')
|
||||
queueSteering('after')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('1 queued')
|
||||
|
||||
// A loop-authored steering event (plugin source, no matching agent/queued)
|
||||
// cannot consume a pending user slot, even when it drains first.
|
||||
result.terminal.output = ''
|
||||
result.session.append('steering/message', {
|
||||
turn: 1,
|
||||
content: [{ type: 'text', text: 'continue: goal not reached' }],
|
||||
source: { kind: 'plugin', plugin: 'hooks' },
|
||||
}, { surfaceOp: 'append' })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('1 queued')
|
||||
result.terminal.output = ''
|
||||
drainSteering('after')
|
||||
await tick()
|
||||
expect(result.terminal.output).not.toContain('queued')
|
||||
|
||||
// The turn ending resets the badge, so the next running turn starts clean.
|
||||
result.agent.status = 'idle'
|
||||
result.ctx.emit('agent/status', result.agent, 'idle')
|
||||
result.agent.status = 'running'
|
||||
result.terminal.output = ''
|
||||
result.ctx.emit('agent/status', result.agent, 'running')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('— Enter sends steering, Esc cancels')
|
||||
expect(result.terminal.output).not.toContain('queued')
|
||||
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('derives the fine-grained turn phase from session lifecycle events', async () => {
|
||||
// A live event before the turn runs has no status controller to move.
|
||||
const idle = await setup()
|
||||
// A steering queue arriving while idle has no status line to badge, so the
|
||||
// refresh is a no-op beyond requesting a render.
|
||||
idle.ctx.emit('agent/queued', idle.agent, [{ type: 'text', text: 'early' }], { source: { kind: 'user' }, steering: true })
|
||||
idle.session.append('tool/call', { turn: 1, step: 0, callId: 'pre' as never, name: 'bash', arguments: '{}' })
|
||||
await tick()
|
||||
expect(idle.terminal.output).not.toContain('Executing tools')
|
||||
expect(idle.terminal.output).not.toContain('queued')
|
||||
await dispose(idle)
|
||||
|
||||
const result = await setup({ status: 'running' })
|
||||
expect(result.terminal.output).toContain('Waiting for the first token')
|
||||
|
||||
result.terminal.output = ''
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'block-start', index: 0, blockType: 'reasoning' } })
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'reasoning-delta', index: 0, text: 'mull it over' } })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Thinking')
|
||||
|
||||
result.terminal.output = ''
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'block-start', index: 1, blockType: 'text' } })
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'text-delta', index: 1, text: 'answering' } })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Responding')
|
||||
|
||||
result.terminal.output = ''
|
||||
result.session.append('tool/call', { turn: 1, step: 0, callId: 'c1' as never, name: 'bash', arguments: '{}' })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Executing tools')
|
||||
|
||||
// The next step reopens the wait window and resets the executing label.
|
||||
result.terminal.output = ''
|
||||
result.session.append('step/start', { turn: 1, step: 1 })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Waiting for the first token')
|
||||
expect(result.terminal.output).not.toContain('Executing tools')
|
||||
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('refreshes the running status elapsed time on its own timer', async () => {
|
||||
const result = await setup({ status: 'running' })
|
||||
result.terminal.output = ''
|
||||
// The loader repaints "0s" until the controller's own interval fires; a
|
||||
// non-zero elapsed proves the refresh, not just the loader's animation.
|
||||
await new Promise(resolve => setTimeout(resolve, 1_300))
|
||||
expect(result.terminal.output).toMatch(/Waiting for the first token [1-9]s/)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('shows minutes and seconds once a step passes a minute', async () => {
|
||||
const result = await setup({ status: 'running' })
|
||||
const base = Date.now()
|
||||
const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(base + 95_000)
|
||||
result.terminal.output = ''
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'text-delta', index: 0, text: 'hi' } })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('total 1m')
|
||||
nowSpy.mockRestore()
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('preserves the turn phase and elapsed time across a mid-turn color-scheme change', async () => {
|
||||
const result = await setup({ status: 'running' })
|
||||
const base = Date.now()
|
||||
const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(base)
|
||||
// Advance into `responding`, anchoring the phase clock at `base`.
|
||||
result.session.append('assistant/chunk', { turn: 1, step: 0, chunk: { type: 'text-delta', index: 0, text: 'answering' } })
|
||||
await tick()
|
||||
|
||||
// Four seconds later the terminal reports a light color scheme, rebuilding
|
||||
// the status loader; the phase and its elapsed time must survive the rebuild.
|
||||
nowSpy.mockReturnValue(base + 4_000)
|
||||
result.terminal.output = ''
|
||||
result.terminal.send('\x1b[?997;2n')
|
||||
await tick()
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Responding 4s')
|
||||
expect(result.terminal.output).not.toContain('Waiting for the first token')
|
||||
|
||||
nowSpy.mockRestore()
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('renders the ANSI palette and every markdown/content style', async () => {
|
||||
const result = await setup({
|
||||
cwd: '/workspace',
|
||||
@@ -524,6 +814,126 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
await dispose(logicalResult)
|
||||
})
|
||||
|
||||
it('shows the session cache hit rate in the footer and updates it live', async () => {
|
||||
// Empty session: no input billed yet, so the cache segment is hidden.
|
||||
// A cwd without "cache" in it keeps the negative assertion unambiguous.
|
||||
const empty = await setup({ cwd: '/opt' })
|
||||
expect(empty.terminal.output).toContain('↑0 ↓0')
|
||||
expect(empty.terminal.output).not.toContain('cache')
|
||||
await dispose(empty)
|
||||
|
||||
const result = await setup({
|
||||
// Pin a short cwd so the footer never clips the cache segment: the
|
||||
// default is process.cwd(), and a deep worktree path truncates
|
||||
// `cache 60%` at the terminal width.
|
||||
cwd: '/opt',
|
||||
beforeMount(session) {
|
||||
// Cold call: 10 billed input tokens, none served from cache.
|
||||
appendAssistant(session, [{ type: 'text', text: 'cold' }], { inputTokens: 10, outputTokens: 5 })
|
||||
},
|
||||
})
|
||||
expect(result.terminal.output).toContain('cache 0%')
|
||||
|
||||
result.terminal.output = ''
|
||||
// Warm call lands live on the next step (same-step usage replaces rather
|
||||
// than accumulates): 5 uncached + 30 cache-read + 5 cache-write billed
|
||||
// input, so 30 of the 50 total prompt tokens are hits → 60%.
|
||||
appendAssistant(result.session, [{ type: 'text', text: 'warm' }], {
|
||||
inputTokens: 5,
|
||||
outputTokens: 5,
|
||||
cacheReadTokens: 30,
|
||||
cacheWriteTokens: 5,
|
||||
}, { turn: 1, step: 2 })
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('cache 60%')
|
||||
expect(result.terminal.output).not.toContain('cache 0%')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('shows detailed session diagnostics while the agent is running', async () => {
|
||||
const timestamp = Date.parse('2026-07-22T09:10:11.000Z')
|
||||
const dateNow = vi.spyOn(Date, 'now').mockReturnValue(timestamp)
|
||||
const result = await setup({
|
||||
cwd: '/workspace/status',
|
||||
contextWindow: 128_000,
|
||||
contextTokens: 42_000,
|
||||
config: { showReasoning: false },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek-v4-pro' },
|
||||
beforeMount(session) {
|
||||
session.append('session/title', {
|
||||
title: 'Inspect status \u001B]2;unsafe\u0007',
|
||||
messageSeqs: [1],
|
||||
source: { kind: 'fallback' },
|
||||
})
|
||||
appendAssistant(session, [{ type: 'text', text: 'measured' }], {
|
||||
inputTokens: 1_250,
|
||||
outputTokens: 340,
|
||||
cacheReadTokens: 3_000,
|
||||
cacheWriteTokens: 250,
|
||||
})
|
||||
session.append('tool/call', {
|
||||
turn: 1, step: 1, callId: 'status-call-1' as never, name: 'read', arguments: '{}',
|
||||
})
|
||||
session.append('tool/call', {
|
||||
turn: 1, step: 1, callId: 'status-call-2' as never, name: 'write', arguments: '{}',
|
||||
})
|
||||
},
|
||||
})
|
||||
result.agent.status = 'running'
|
||||
agentEvents(result.ctx, result.agent).emit('agent/status', 'running')
|
||||
result.terminal.send('/status')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
|
||||
expect(result.terminal.output).toContain('Session status')
|
||||
expect(result.terminal.output).toContain('main-session')
|
||||
expect(result.terminal.output).toContain('Inspect status \\x1b]2;unsafe\\x07')
|
||||
expect(result.terminal.output).toContain('/workspace/status')
|
||||
expect(result.terminal.output).toContain('deepseek/deepseek-v4-pro (reasoning hidden)')
|
||||
expect(result.terminal.output).toContain('running · 6 events · 1 turn · 1 step · 2 tool calls')
|
||||
expect(result.terminal.output).toContain('1,250 input + 340 output')
|
||||
expect(result.terminal.output).toContain('[███████████░░░░░] 67% hit (3,000 read + 250 write)')
|
||||
expect(result.terminal.output).toContain('[█████░░░░░░░░░░░] 33% used (42,000 / 128,000)')
|
||||
expect(result.terminal.output).toContain('2026-07-22 09:10:11 UTC')
|
||||
expect(result.terminal.output).not.toContain('\u001B]2;unsafe\u0007')
|
||||
|
||||
result.terminal.resize(56)
|
||||
result.terminal.send('/redraw')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
|
||||
await dispose(result)
|
||||
dateNow.mockRestore()
|
||||
})
|
||||
|
||||
it('labels unavailable status diagnostics without inventing values', async () => {
|
||||
const timestamp = Date.parse('2026-07-22T10:11:12.000Z')
|
||||
const dateNow = vi.spyOn(Date, 'now').mockReturnValue(timestamp)
|
||||
const result = await setup({
|
||||
cwd: null,
|
||||
omitInitialLifecycle: true,
|
||||
contextTokens: 7,
|
||||
agentOptions: {},
|
||||
catalog: {
|
||||
providers: [],
|
||||
models: [],
|
||||
resolveModelContext: () => Promise.resolve(undefined),
|
||||
},
|
||||
})
|
||||
result.terminal.send('/status')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
|
||||
expect(result.terminal.output).toContain('untitled')
|
||||
expect(result.terminal.output).toContain('unset (reasoning shown)')
|
||||
expect(result.terminal.output).toContain('idle · 0 events · 0 turns · 0 steps · 0 tool calls')
|
||||
expect(result.terminal.output).toContain('n/a (0 read + 0 write)')
|
||||
expect(result.terminal.output).toContain('7 used · capacity unknown')
|
||||
expect(result.terminal.output).toContain('2026-07-22 10:11:12 UTC')
|
||||
await dispose(result)
|
||||
dateNow.mockRestore()
|
||||
})
|
||||
|
||||
it('sends, steers, handles commands, global keys, and disposed-agent input', async () => {
|
||||
const result = await setup()
|
||||
|
||||
@@ -545,17 +955,15 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
result.terminal.send('\x03')
|
||||
result.terminal.send('\x12')
|
||||
result.terminal.send('\x0f')
|
||||
result.terminal.send('/cancel')
|
||||
result.terminal.send('\r')
|
||||
expect(result.agent.cancelled).toContainEqual({ kind: 'user' })
|
||||
|
||||
result.agent.status = 'idle'
|
||||
for (const command of ['/help', '/reasoning', '/tools', '/redraw']) {
|
||||
for (const command of ['/help', '/reasoning', '/tools', '/redraw', '/reload']) {
|
||||
result.terminal.send(command)
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
}
|
||||
for (const command of ['/clear', '/cancel', '/wat']) {
|
||||
for (const command of ['/clear', '/wat']) {
|
||||
result.terminal.send(command)
|
||||
result.terminal.send('\r')
|
||||
}
|
||||
@@ -568,8 +976,9 @@ 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('already idle')
|
||||
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')
|
||||
expect(result.exit).toHaveBeenCalledWith(0)
|
||||
await result.controller.dispose()
|
||||
await result.ctx.fiber.dispose()
|
||||
@@ -635,7 +1044,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
expect(result.agent.steered).toEqual([])
|
||||
initialContext.resolve({ contextWindow: 100 })
|
||||
await tick()
|
||||
expect(result.terminal.output).not.toContain('50% context tools:compact b1(reasoning:on)')
|
||||
expect(result.terminal.output).not.toContain('50% context tools:collapsed')
|
||||
|
||||
result.terminal.send('/model')
|
||||
result.terminal.send('\r')
|
||||
@@ -646,7 +1055,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
result.agent.status = 'idle'
|
||||
result.ctx.emit('agent/status', result.agent, 'idle')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('25% context tools:compact b1(reasoning:on)')
|
||||
expect(result.terminal.output).toContain('b1 ')
|
||||
expect(result.terminal.output).toContain('25% context tools:collapsed')
|
||||
|
||||
const assembly = await result.ctx.systemPrompt.assemble(assembleContextFor(result.agent))
|
||||
expect(assembly.variables).toMatchObject({ provider: 'beta', model: 'b1' })
|
||||
@@ -691,7 +1101,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
unset.terminal.send('\r')
|
||||
await tick()
|
||||
expect(unset.terminal.output).toContain('Model selected: alpha/a1')
|
||||
expect(unset.terminal.output).toContain('context unknown tools:compact a1(reasoning:on)')
|
||||
expect(unset.terminal.output).toContain('a1 ')
|
||||
expect(unset.terminal.output).not.toContain('% context')
|
||||
await dispose(unset)
|
||||
|
||||
const empty = await setup({ agentOptions: {}, catalog: { providers: [], models: [] } })
|
||||
@@ -790,6 +1201,11 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
description: 'Fail a plugin command',
|
||||
handler: () => { throw new Error('plugin command exploded') },
|
||||
})
|
||||
result.ctx.commands.register({
|
||||
name: 'plugin-error',
|
||||
description: 'Return an error result',
|
||||
handler: () => ({ kind: 'error' as const, text: 'plugin error result' }),
|
||||
})
|
||||
|
||||
result.terminal.send('/plugin-check value ')
|
||||
result.terminal.send('\r')
|
||||
@@ -806,6 +1222,10 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Command failed: plugin command exploded')
|
||||
result.terminal.send('/plugin-error')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('plugin error result')
|
||||
result.terminal.send('/help')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
@@ -815,6 +1235,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
await result.controller.dispose()
|
||||
expect(result.ctx.commands.list(result.agent).map(command => command.name)).toEqual([
|
||||
'plugin-check',
|
||||
'plugin-error',
|
||||
'plugin-fail',
|
||||
])
|
||||
await result.ctx.fiber.dispose()
|
||||
@@ -923,6 +1344,153 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('skill slash command', () => {
|
||||
const withSkills = async (ctx: Context): Promise<void> => {
|
||||
ctx.provide('tools', { get() { return undefined } } as never)
|
||||
await ctx.plugin(SkillService)
|
||||
const skills = ctx.get('skills')
|
||||
if (skills === undefined) throw new Error('skills service not mounted')
|
||||
skills.register({ name: 'demo-skill', description: 'Demo skill for tests', source: 'runtime', provider: 'runtime', content: 'Demo instructions body.' })
|
||||
skills.register({ name: 'hidden-skill', description: 'Model-hidden skill', source: 'runtime', provider: 'runtime', content: 'Hidden instructions body.', disableModelInvocation: true })
|
||||
}
|
||||
|
||||
it('offers non-hidden skills as slash completions and hides model-disabled ones', async () => {
|
||||
const result = await setup({ configureContext: withSkills })
|
||||
result.terminal.send('/skill')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('demo-skill')
|
||||
expect(result.terminal.output).not.toContain('hidden-skill')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('loads a skill as a user turn, appending typed instructions', async () => {
|
||||
const result = await setup({ configureContext: withSkills })
|
||||
result.terminal.send('/skill:demo-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.agent.sent).toEqual([[{ type: 'text', text: '<skill name="demo-skill">\nDemo instructions body.\n</skill>' }]])
|
||||
|
||||
result.agent.status = 'running'
|
||||
result.terminal.send('/skill:demo-skill focus on tests')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.agent.steered).toEqual([[{ type: 'text', text: '<skill name="demo-skill">\nDemo instructions body.\n</skill>\n\nfocus on tests' }]])
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('invokes a model-disabled skill by its exact name', async () => {
|
||||
const result = await setup({ configureContext: withSkills })
|
||||
result.terminal.send('/skill:hidden-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.agent.sent).toEqual([[{ type: 'text', text: '<skill name="hidden-skill">\nHidden instructions body.\n</skill>' }]])
|
||||
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')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
result.terminal.send('/skill:')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
// A space right after the colon parses to an empty name, not a name of
|
||||
// "focus"; the documented syntax puts the name immediately after the colon.
|
||||
result.terminal.send('/skill: focus')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Unknown skill: does-not-exist')
|
||||
expect(result.terminal.output).toContain('Usage: /skill:<name>')
|
||||
expect(result.agent.sent).toEqual([])
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('warns when no skill service is mounted', async () => {
|
||||
const result = await setup()
|
||||
result.terminal.send('/skill:demo-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Skills are not available')
|
||||
expect(result.agent.sent).toEqual([])
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('surfaces skill lookup failures as an error notice', async () => {
|
||||
const result = await setup({
|
||||
configureContext: async (ctx) => {
|
||||
ctx.provide('tools', { get() { return undefined } } as never)
|
||||
ctx.provide('skills', {
|
||||
list: () => Promise.reject(new Error('list boom')),
|
||||
get: () => Promise.reject(new Error('get boom')),
|
||||
} as never)
|
||||
},
|
||||
})
|
||||
result.terminal.send('/skill:demo-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('failed to load')
|
||||
expect(result.terminal.output).toContain('get boom')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('drops skill list and lookup results that settle after disposal', async () => {
|
||||
const pendingList: Array<(value: SkillSummary[]) => void> = []
|
||||
const pendingGet: Array<{ resolve: (value: SkillDefinition | undefined) => void; reject: (error: unknown) => void }> = []
|
||||
const result = await setup({
|
||||
configureContext: async (ctx) => {
|
||||
ctx.provide('tools', { get() { return undefined } } as never)
|
||||
ctx.provide('skills', {
|
||||
list: () => new Promise<SkillSummary[]>((resolve) => { pendingList.push(resolve) }),
|
||||
get: () => new Promise<SkillDefinition | undefined>((resolve, reject) => { pendingGet.push({ resolve, reject }) }),
|
||||
} as never)
|
||||
},
|
||||
})
|
||||
result.terminal.send('/skill:demo-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
result.terminal.send('/skill:other-skill')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
await dispose(result)
|
||||
|
||||
for (const resolve of pendingList) resolve([{ name: 'late', description: 'late', source: 'runtime', provider: 'runtime' }])
|
||||
pendingGet[0]?.resolve({ name: 'demo-skill', description: 'late', source: 'runtime', provider: 'runtime', content: 'late body' })
|
||||
pendingGet[1]?.reject(new Error('late failure'))
|
||||
await tick()
|
||||
expect(result.agent.sent).toEqual([])
|
||||
expect(result.terminal.output).not.toContain('late failure')
|
||||
expect(result.terminal.output).not.toContain('late body')
|
||||
})
|
||||
})
|
||||
|
||||
describe('renderSkillInvocation', () => {
|
||||
const skill: SkillDefinition = {
|
||||
name: 'demo-skill',
|
||||
description: 'Demo skill',
|
||||
source: 'runtime',
|
||||
provider: 'runtime',
|
||||
content: 'Body text.',
|
||||
}
|
||||
|
||||
it('renders directory, url, opaque, and absent resource bases', () => {
|
||||
expect(renderSkillInvocation({ ...skill, resourceBase: { kind: 'directory', path: '/skills/demo' } }, '')).toBe(
|
||||
'<skill name="demo-skill">\nReferences in this skill are relative to /skills/demo.\n\nBody text.\n</skill>',
|
||||
)
|
||||
expect(renderSkillInvocation({ ...skill, resourceBase: { kind: 'url', url: 'https://x/y' } }, 'go')).toBe(
|
||||
'<skill name="demo-skill">\nReferences in this skill are relative to https://x/y.\n\nBody text.\n</skill>\n\ngo',
|
||||
)
|
||||
expect(renderSkillInvocation({ ...skill, resourceBase: { kind: 'opaque', description: 'held in memory' } }, '')).toBe(
|
||||
'<skill name="demo-skill">\nheld in memory\n\nBody text.\n</skill>',
|
||||
)
|
||||
expect(renderSkillInvocation(skill, '')).toBe('<skill name="demo-skill">\nBody text.\n</skill>')
|
||||
})
|
||||
|
||||
it('throws on an unknown resource base kind', () => {
|
||||
expect(() => renderSkillInvocation({ ...skill, resourceBase: { kind: 'future' } as never }, '')).toThrow('unreachable variant')
|
||||
})
|
||||
})
|
||||
|
||||
describe('tool cards and surface replay', () => {
|
||||
const tools: Record<string, ToolDefinition> = {
|
||||
bash: {
|
||||
@@ -1125,12 +1693,13 @@ describe('TUI user-interaction dialogs', () => {
|
||||
|
||||
const single = result.ctx.userInteraction.ask({
|
||||
questions: [{
|
||||
id: 'mode', header: 'Mode', question: 'Choose a mode',
|
||||
id: 'mode', header: 'Mode', question: 'Choose a mode', detail: 'This choice controls the next turn.',
|
||||
options: [{ label: 'Safe', description: 'Use checks' }, { label: 'Fast' }],
|
||||
}],
|
||||
})
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Choose a mode')
|
||||
expect(result.terminal.output).toContain('This choice controls the next turn.')
|
||||
expect(result.terminal.output).toContain('Question 1/1 (1 unanswered) · Mode')
|
||||
expect(result.terminal.output).toContain('1/2')
|
||||
result.terminal.send('\x1b[B')
|
||||
@@ -1295,6 +1864,40 @@ describe('terminal mounting', () => {
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('degrades /reload to a warning when mounted as a real plugin without a Loader', async () => {
|
||||
// Production shape: the TUI runs inside a plugin fiber, where a bare
|
||||
// `ctx.loader` proxy read would THROW `cannot get property without
|
||||
// inject` — only the non-throwing `ctx.get` lookup degrades gracefully.
|
||||
const ctx = new Context()
|
||||
provideTokenMeter(ctx)
|
||||
provideLlmCatalog(ctx)
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(AgentRegistry)
|
||||
await ctx.plugin(CommandService)
|
||||
await ctx.plugin(UserInteractionService)
|
||||
ctx.provide('tools', { get: () => undefined } as never)
|
||||
const session = ctx.sessions.create(SessionId('main'))
|
||||
ctx.agents.register({
|
||||
id: session.id, options: {}, session, status: 'idle', ctx,
|
||||
send() {}, steer() {}, inject() {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
const terminal = new FakeTerminal()
|
||||
// Mirror dsh-tui's own inject (minus loader, the absence under test).
|
||||
await ctx.plugin({
|
||||
inject: ['agents', 'commands', 'userInteraction', 'tools', 'llm', 'tokenMeter'],
|
||||
apply: (pluginCtx: Context) => {
|
||||
mountTui(pluginCtx, { color: false }, { terminal, exit: vi.fn() })
|
||||
},
|
||||
})
|
||||
await tick()
|
||||
expect(terminal.started).toBe(1)
|
||||
terminal.send('/reload')
|
||||
terminal.send('\r')
|
||||
await tick()
|
||||
expect(terminal.output).toContain('/reload needs the cordis Loader')
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('waits for its configured agent before starting the TUI', async () => {
|
||||
const ctx = new Context()
|
||||
provideTokenMeter(ctx)
|
||||
@@ -1476,4 +2079,175 @@ describe('terminal mounting', () => {
|
||||
expect(terminal.output).toContain('\x1b[2mdeepseek-v4-flash')
|
||||
await disposeTuiTestHarness(result)
|
||||
})
|
||||
it('runs /reload against every file-backed loader subtree, reports completion, and rejects re-entry while in flight', async () => {
|
||||
const refreshed: string[] = []
|
||||
let releaseRefresh!: () => void
|
||||
const gate = new Promise<void>((resolve) => { releaseRefresh = resolve })
|
||||
const result = await setup({
|
||||
configureContext: async (ctx) => {
|
||||
ctx.provide('tools', { get: () => undefined } as never)
|
||||
// A structural Loader: two file-backed subtrees and one plain entry.
|
||||
// The first subtree blocks on a gate so re-entry can be probed
|
||||
// deterministically mid-flight.
|
||||
ctx.provide('loader', {
|
||||
entries: () => [
|
||||
{ subtree: { refresh: async () => { refreshed.push('root'); await gate } } },
|
||||
{},
|
||||
{ subtree: { refresh: async () => { refreshed.push('nested') } } },
|
||||
],
|
||||
} as never)
|
||||
},
|
||||
})
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Reloading 2 config tree(s)')
|
||||
// Second /reload while the first is gated: refused, no extra refreshes.
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('A config reload is already running.')
|
||||
expect(refreshed.sort()).toEqual(['nested', 'root'])
|
||||
releaseRefresh()
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Config reload complete.')
|
||||
// The guard released: a third /reload runs again.
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(refreshed).toHaveLength(4)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('reports a /reload failure if a refresh ever rejects', async () => {
|
||||
const result = await setup({
|
||||
configureContext: async (ctx) => {
|
||||
ctx.provide('tools', { get: () => undefined } as never)
|
||||
ctx.provide('loader', {
|
||||
entries: () => [{ subtree: { refresh: () => Promise.reject(new Error('disk gone')) } }],
|
||||
} as never)
|
||||
},
|
||||
})
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Config reload failed: disk gone')
|
||||
// The failure arm also releases the re-entrancy guard.
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).not.toContain('A config reload is already running.')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('refuses /reload while the agent is running and allows it back at idle', async () => {
|
||||
const refreshed: string[] = []
|
||||
const result = await setup({
|
||||
status: 'running',
|
||||
configureContext: async (ctx) => {
|
||||
ctx.provide('tools', { get: () => undefined } as never)
|
||||
ctx.provide('loader', {
|
||||
entries: () => [{ subtree: { refresh: async () => { refreshed.push('tree') } } }],
|
||||
} as never)
|
||||
},
|
||||
})
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('/reload requires an idle agent (status: running).')
|
||||
expect(refreshed).toHaveLength(0)
|
||||
// Back at idle the same command runs.
|
||||
result.agent.status = 'idle'
|
||||
result.terminal.send('/reload')
|
||||
result.terminal.send('\r')
|
||||
await tick()
|
||||
expect(refreshed).toHaveLength(1)
|
||||
expect(result.terminal.output).toContain('Config reload complete.')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('banner sweep reveal', () => {
|
||||
it('renders the product name through the brand-gradient path when truecolor is enabled', async () => {
|
||||
// The product name carries a per-letter 24-bit gradient from the brand
|
||||
// indigo to light blue; the per-letter layout is pinned by the
|
||||
// `banner-gradient` terminal snapshot.
|
||||
const result = await setup({ config: { color: true, truecolor: true } })
|
||||
expect(result.terminal.output).toContain('\x1b[38;2;77;107;254m')
|
||||
expect(result.terminal.output).toContain('\x1b[38;2;36;152;255m')
|
||||
expect(result.terminal.output).toContain('HARNESS')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('sweeps the whole borderless banner in when no welcome is configured, ending complete', async () => {
|
||||
const intervals = vi.spyOn(globalThis, 'setInterval')
|
||||
const cleared = vi.spyOn(globalThis, 'clearInterval')
|
||||
const result = await setup({ omitWelcome: true })
|
||||
const revealHandle = intervals.mock.results.at(-1)?.value as ReturnType<typeof setInterval>
|
||||
// Run the sweep to natural completion — it clears its own timer at the end.
|
||||
const done = (): boolean => cleared.mock.calls.some(call => call[0] === revealHandle)
|
||||
const deadline = Date.now() + 5000
|
||||
while (!done() && Date.now() < deadline) await tick()
|
||||
intervals.mockRestore()
|
||||
cleared.mockRestore()
|
||||
// The finished banner carries the title and the model • session detail.
|
||||
expect(result.terminal.output).toContain('DEEPSEEK')
|
||||
expect(result.terminal.output).toContain('HARNESS')
|
||||
expect(result.terminal.output).toContain('main-session')
|
||||
// Borderless: no box-drawing frame around the banner.
|
||||
expect(result.terminal.output).not.toContain('╭')
|
||||
expect(result.terminal.output).not.toContain('╮')
|
||||
// A mid-sweep frame rendered a clipped title: `DEEPSEEK` with no `HARNESS`
|
||||
// on the same line.
|
||||
const clipped = result.terminal.output
|
||||
.split('\n')
|
||||
.some(line => line.includes('DEEPSEEK') && !line.includes('HARNESS'))
|
||||
expect(clipped).toBe(true)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('renders a configured welcome verbatim in a complete banner with no sweep', async () => {
|
||||
const result = await setup()
|
||||
await tick()
|
||||
expect(result.terminal.output).toContain('Coding agent ready.')
|
||||
expect(result.terminal.output).toContain('DEEPSEEK')
|
||||
expect(result.terminal.output).not.toContain('╭')
|
||||
// No reveal frames: the banner is drawn whole from the first render, so no
|
||||
// clipped-title frame ever appears.
|
||||
const clipped = result.terminal.output
|
||||
.split('\n')
|
||||
.some(line => line.includes('DEEPSEEK') && !line.includes('HARNESS'))
|
||||
expect(clipped).toBe(false)
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('omits the subtitle line entirely when no welcome is configured', async () => {
|
||||
const result = await setup({ omitWelcome: true })
|
||||
const deadline = Date.now() + 5000
|
||||
while (!result.terminal.output.includes('main-session') && Date.now() < deadline) await tick()
|
||||
// Banner is title + detail only — no subtitle between them.
|
||||
expect(result.terminal.output).toContain('deepseek-v4-flash')
|
||||
expect(result.terminal.output).not.toContain('ready.')
|
||||
await dispose(result)
|
||||
})
|
||||
|
||||
it('stops a mid-sweep animation on dispose', async () => {
|
||||
// The output-stability probe alone is insensitive to a leaked interval
|
||||
// (pi-tui's stopped guard silences post-stop renders), so capture the
|
||||
// reveal's own interval handle and assert dispose clears exactly it.
|
||||
const intervals = vi.spyOn(globalThis, 'setInterval')
|
||||
const result = await setup({ omitWelcome: true })
|
||||
const revealHandle = intervals.mock.results.at(-1)?.value as ReturnType<typeof setInterval>
|
||||
expect(revealHandle).toBeDefined()
|
||||
const cleared = vi.spyOn(globalThis, 'clearInterval')
|
||||
await dispose(result)
|
||||
expect(cleared.mock.calls.some(call => call[0] === revealHandle)).toBe(true)
|
||||
intervals.mockRestore()
|
||||
cleared.mockRestore()
|
||||
const settled = result.terminal.output.length
|
||||
await tick()
|
||||
await tick()
|
||||
expect(result.terminal.output.length).toBe(settled)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user