Merge remote-tracking branch 'origin/master' into worktree/pr468-retarget-latest-master
# Conflicts: # docs/config-catalog.md # docs/event-producer-consumer.md # docs/module-graph.md # packages/examples/tui-demo/src/index.ts # packages/examples/tui-demo/tests/tui-agent.spec.ts # packages/ui/tui/README.md # packages/ui/tui/package.json # packages/ui/tui/src/index.ts # packages/ui/tui/tests/tui.spec.ts # packages/ui/tui/tsconfig.json # pnpm-lock.yaml # vitest.config.ts
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# @deepseek-ai/dsh-tui
|
||||
|
||||
The interactive terminal front door for DeepSeek Harness agents, built on [`@earendil-works/pi-tui`](https://www.npmjs.com/package/@earendil-works/pi-tui). It requires stdin and stdout TTYs; scripts and Loader pipes should use the headless [`@deepseek-ai/dsh-cli-demo`](../../examples/cli-demo/README.md) app instead.
|
||||
The interactive terminal front door for DeepSeek Harness agents, built on [`@earendil-works/pi-tui`](https://www.npmjs.com/package/@earendil-works/pi-tui). It requires stdin and stdout TTYs; scripts and Loader pipes should use the one-shot [`@deepseek-ai/dsh-cli-demo`](../../examples/cli-demo/README.md) app instead.
|
||||
|
||||
The implemented [TUI feature Agent Note](../../../.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md) owns the front-door decision; the [terminal-state snapshot Agent Note](../../../.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md) owns its verification strategy.
|
||||
|
||||
Interactive terminals on macOS, Linux, and Windows are supported. Windows uses pi-tui's native console VT-input handling, and the [Windows support Agent Note](../../../.agents/notes/implemented/feature/2026-07-20-windows-tui-support.md) owns the platform decision and ConPTY process verification.
|
||||
|
||||
This package owns interactive terminal presentation and input only. It injects `agents`, [`commands`](../commands/README.md), `llm`, `systemPrompt`, `tokenMeter`, `tools`, and `userInteraction`, then drives an agent created or resumed by app or developer code. Agent lifecycle, persistence, and the model-facing [`ask_user_question`](../tool-ask-user/README.md) tool remain separate composition entries.
|
||||
This package owns interactive terminal presentation and input only. It injects `agents`, [`commands`](../commands/README.md), `llm`, `systemPrompt`, `tokenMeter`, `tools`, and `userInteraction`, optionally reads a `skills` service (present only when one is mounted), then drives an agent created or resumed by app or developer code. Agent lifecycle, persistence, and the model-facing [`ask_user_question`](../tool-ask-user/README.md) tool remain separate composition entries.
|
||||
|
||||
The TUI rebuilds resumed history from the active session surface, renders Markdown responses and reasoning, applies each tool's `presentCall` / `presentResult` intent to terminal, diff, or generic cards, keeps the latest `todo/write` plan above the editor, and presents `ctx.userInteraction` questions in a wide bottom-left keyboard panel with progress, numbered options, and aligned descriptions. The latest logged session title becomes the header subtitle, with `welcome` before a title exists, and the terminal window title becomes `<session title> — <configured title>`. A durable `llm/retry` event retracts the failed step's live chunks and renders the scheduled retry count, delay, and failure in the transcript; success, exhaustion, and cancellation then settle through ordinary session events. The footer totals each logged model step's usage once, including failed attempts, while treating committed-message usage as a fallback for logs without a usage chunk. Its idle view compares token-meter pressure with `ctx.llm.resolveModelContext()` for the current route, displays `context unknown` when the adapter has no capacity metadata, and also shows tool-card mode and the current model with reasoning state; while the agent runs, an elapsed working indicator and `esc interrupt` replace that summary. Surface replacement events rebuild the transcript so compacted history does not reappear.
|
||||
|
||||
@@ -14,15 +14,25 @@ An embedding may provide `TuiRuntime.formatCwd` when its logical workspace label
|
||||
|
||||
Before model output, session events, tool presenters, questions, configuration, or diagnostics reach pi-tui's ANSI-aware renderers or the terminal title, the TUI renders C0 and C1 controls other than line feeds as visible `\xNN` text. Those sources cannot add terminal control sequences; the TUI and pi-tui retain ownership of terminal rendering and styling.
|
||||
|
||||
While the agent is running, ordinary editor submissions call `agent.steer()`; otherwise they call `agent.send()`. That choice uses the status after optional asynchronous preparation: `send()` dispatches `agent/prompt-submit`, while in-turn `steer()` joins at a steering checkpoint without that hook. When optional `ctx.sessionReferences` is mounted, the existing `@` file menu also offers metadata-only session candidates, inserts `@[label](dsh-session:<payload>)`, and prepares its snapshot before dispatch. Preparation disables duplicate submit; failure restores the editor input. A slash at the start of the submitted line enters `ctx.commands` instead: known commands execute directly and unknown commands produce a warning, with no automatic fallthrough to the model. A command producer may explicitly schedule agent work; [`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-surfaces) uses that contract for `/plan [message]`. The TUI registers `/help`, `/model`, `/clear`, `/cancel`, `/reasoning`, `/tools`, `/redraw`, and `/exit` as agent-scoped definitions; every other effective command joins autocomplete and `/help` dynamically. Ctrl+C or Escape cancels a running turn. Tool cards collapse long bodies into a configurable head/tail preview; Ctrl+O toggles every card between its preview and full output. Ctrl+R toggles reasoning, Ctrl+L redraws, and Ctrl+D exits while idle.
|
||||
When optional `ctx.sessionReferences` is mounted, the existing `@` file menu also offers metadata-only session candidates, inserts `@[label](dsh-session:<payload>)`, and prepares the selected snapshots before dispatch. Preparation disables duplicate submission and restores the editor input on failure. The TUI chooses `agent.steer()` or `agent.send()` from the status after that asynchronous preparation, so idle sends still dispatch `agent/prompt-submit` while in-turn steering joins at a checkpoint without that hook.
|
||||
|
||||
While the agent is running, ordinary editor submissions call `agent.steer()`; otherwise they call `agent.send()`. A slash at the start of the submitted line enters `ctx.commands` instead: known commands execute directly, unknown commands produce a warning, and neither path automatically reaches the model. A command producer may explicitly schedule agent work; [`dsh-plan-mode`](../../plan/plan-mode/README.md#model-and-human-surfaces) uses that contract for `/plan [message]`. The TUI registers `/help`, `/model`, `/clear`, `/reasoning`, `/tools`, `/redraw`, `/reload`, `/resume`, `/status`, and `/exit` as agent-scoped definitions; every other effective command joins autocomplete and `/help` dynamically, as do `/skill:` completions. A status line above the editor reports the turn phase the TUI derives from session events — waiting for the first token, thinking, responding, or executing tools — with the elapsed time in that phase and the running step total, refreshed each second, and ends with the `Enter sends steering, Esc cancels` hint; while steering messages wait to reach the model it inserts a `N queued ·` badge before the hint that clears as each drains. Ctrl+C or Escape cancels a running turn. Tool cards collapse long bodies into a configurable head/tail preview; Ctrl+O toggles every card between its preview and full output. Ctrl+R toggles reasoning, Ctrl+L redraws, and Ctrl+D exits while idle.
|
||||
|
||||
`/model` opens the advisory `ctx.llm` catalog as a keyboard selector: Up/Down moves, Enter selects, and Escape closes it. `/model <model>` still selects an unambiguous model id directly, while `/model <provider>/<model>` selects an exact target. The configured target or latest logged request header initializes the selector, and an unlisted current model remains visible because catalogs are advisory. Selection is local to this TUI session. Prompt assembly snapshots the target for one step, replaces `{{provider}}` and `{{model}}`, and applies the same pair through `agent/request`; a switch during assembly therefore starts with a later step. The request header durably records targets that reach the model, while an unused selection remains process-local.
|
||||
|
||||
`/reload` (EXPERIMENTAL, dev-only) re-reads every file-backed loader config tree and applies the diff to the running app — the HMR watcher's config path, invoked manually; it needs the cordis Loader in the context and degrades to a warning without one, runs only while the agent is idle, and refuses re-entry while a reload is in flight. Module-source hot reload remains watcher-owned. When a `skills` service is mounted, `/skill:<name> [instructions]` loads that skill's instructions into the conversation as a user turn; autocomplete lists the model-invocable skills, and any skill (including a model-disabled one) is loadable by its exact name.
|
||||
|
||||
The footer sums the session's reported usage as `↑<uncached input> ↓<output>`, followed by `cache <rate>%` once any input has been billed — the share of billed prompt tokens (uncached input plus cache reads and writes) served from the provider cache, rounded to a percent. It also compares token-meter pressure with `ctx.llm.resolveModelContext()` for the current route (omitting the context share when the adapter has no capacity metadata) and shows the current model and tool-card mode; the right side clips first when the footer is narrow.
|
||||
|
||||
`/status` adds a point-in-time diagnostics card to the transcript and remains available while the agent runs. It reports the session id, title, working directory, selected provider/model, reasoning-block visibility, agent state, event/turn/step/tool-call counts, exact input/output/cache token buckets, KV-cache hit rate, token-meter context use and capacity, creation time, and latest event time. Missing titles, models, cache input, or context capacity are labeled instead of inferred. The card is terminal-only and does not duplicate the compact footer.
|
||||
|
||||
When `resumeCommand` is set and a `sessionPersistence` backend is mounted, exiting prints the resume command for the current session (once it has been persisted, so an abandoned session yields no hint), and `/resume` lists this workspace's persisted sessions newest-first, each with its resume command and a marker on the current one. `{session}` in the template expands to the session id; the TUI only prints commands to copy and never resumes in place.
|
||||
|
||||
## Config
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `welcome` | `ready.` | Header subtitle until the session has a logged title. |
|
||||
| `welcome` | — | Banner subtitle line until the session has a logged title; unset, the banner sweeps in with no subtitle |
|
||||
| `sessionId` | `main` | Exact shared agent/session identity driven by the terminal |
|
||||
| `showReasoning` | `true` | Render reasoning blocks |
|
||||
| `maxToolOutputLines` | `6` | Output lines retained across a collapsed tool card's head/tail preview |
|
||||
@@ -35,6 +45,7 @@ While the agent is running, ordinary editor submissions call `agent.steer()`; ot
|
||||
| `showHardwareCursor` | `false` | Show the hardware cursor at pi-tui's IME marker |
|
||||
| `color` | `true` | Apply the built-in ANSI palette (see [Color](#color)) |
|
||||
| `title` | `DeepSeek Harness` | Product suffix for the terminal window title. |
|
||||
| `resumeCommand` | — | Shell command template for the exit hint and `/resume`, with `{session}` expanded to the session id; unset disables both. Needs a `sessionPersistence` backend |
|
||||
|
||||
```yaml
|
||||
- id: terminal
|
||||
@@ -82,6 +93,20 @@ The selector adds no messages. A target change may alter interpolated system-pro
|
||||
|
||||
Changing provider or model enters that target's cache domain; no cache reuse across distinct targets is assumed.
|
||||
|
||||
### Manual skill invocation
|
||||
|
||||
#### What the model sees
|
||||
|
||||
A `/skill:<name> [instructions]` submission loads the named skill and delivers one text block: a `<skill name="…">` element wrapping the skill's instructions — preceded, when the provider exposes a resource base, by a line locating the skill's relative resources — followed by any trailing instructions the user typed. Delivery follows the same send-while-idle / steer-while-running rule as ordinary input. The command, not the model, chooses the skill; model-disabled skills are omitted from autocomplete but stay loadable by exact name.
|
||||
|
||||
#### Token effect
|
||||
|
||||
The rendered skill block and trailing instructions are retained as one user turn under the agent loop's normal session-history and compaction rules; a repeated invocation appends the body again.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
||||
|
||||
### Interactive user-question answers
|
||||
|
||||
#### What the model sees
|
||||
@@ -100,4 +125,5 @@ Append-only; newly visible content follows the reusable request prefix and does
|
||||
|
||||
- **One configured session owns the transcript and editor** — questions from other agents can still use the shared overlay provider, but session rendering and prompt input remain bound to `sessionId`.
|
||||
- **Tool cards are text terminal presentations** — terminal, diff, and generic cards use tool-owned titles/content, but session content currently has no image block for inline image rendering.
|
||||
- **Non-TTY operation is intentionally unsupported** — automation must use the headless app rather than expecting an internal fallback.
|
||||
- **Non-TTY operation is intentionally unsupported** — app bundles that need automation must compose a one-shot or server front door (`dsh-cli-demo`, `dsh-acp`) rather than expecting an internal fallback.
|
||||
- **Manual `/skill:` invocation always reloads the full skill body** — the TUI does not detect a skill already present in the conversation, so repeated invocations append its instructions again.
|
||||
|
||||
@@ -35,13 +35,23 @@
|
||||
"@deepseek-ai/dsh-llm-retry": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session-reference": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session-persistence": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session-title": "^0.0.1",
|
||||
"@deepseek-ai/dsh-skill": "^0.0.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
|
||||
"@deepseek-ai/dsh-token-meter": "^0.0.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.0.1",
|
||||
"@deepseek-ai/dsh-user-interaction": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@deepseek-ai/dsh-session-persistence": {
|
||||
"optional": true
|
||||
},
|
||||
"@deepseek-ai/dsh-skill": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-tui": "0.80.7",
|
||||
"schemastery": "^3.18.0"
|
||||
@@ -57,7 +67,9 @@
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-query": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-persistence": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-title": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-cordis": "workspace:^",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,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'
|
||||
@@ -27,11 +27,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
|
||||
@@ -42,6 +47,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> {
|
||||
@@ -77,19 +84,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 }
|
||||
@@ -105,17 +99,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[][] = []
|
||||
@@ -151,13 +167,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 }
|
||||
@@ -183,7 +202,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
|
||||
|
||||
29
packages/ui/tui/tests/snapshots/banner-gradient.expected.txt
Normal file
29
packages/ui/tui/tests/snapshots/banner-gradient.expected.txt
Normal file
@@ -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
|
||||
|
||||
32
packages/ui/tui/tests/snapshots/resume-sessions.expected.txt
Normal file
32
packages/ui/tui/tests/snapshots/resume-sessions.expected.txt
Normal file
@@ -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>
|
||||
|
||||
@@ -1,49 +1,39 @@
|
||||
terminal 96x24 buffer=normal length=24 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "DSH session reference"
|
||||
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| " Session reference snapshot."
|
||||
style 1-27 fg=bright-black
|
||||
2| " mock • target-session"
|
||||
style 1-23 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| "│ Session reference snapshot. │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-28 fg=bright-black
|
||||
style 95-95 fg=bright-blue
|
||||
3| "│ mock • target-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-24 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| "▌ Use @Source session "
|
||||
6| "▌ Use @Source session "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Referenced sessions · Source session (source-session) "
|
||||
8| <blank>
|
||||
9| " Referenced sessions · Source session (source-session) "
|
||||
style 1-53 dim
|
||||
12| <blank>
|
||||
13| " Assistant "
|
||||
10| <blank>
|
||||
11| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
14| " Combined reference request accepted. "
|
||||
12| " Combined reference request accepted. "
|
||||
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 context unknown tools:compact mock(reasoning:on)"
|
||||
style 0-24 dim
|
||||
style 46-95 dim
|
||||
19-23| <blank>
|
||||
16| "mock /workspace/project ↑0 ↓0 tools:collapsed"
|
||||
style 0-30 dim
|
||||
style 81-95 dim
|
||||
17-23| <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,13 @@
|
||||
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 { Session } from '@deepseek-ai/dsh-session'
|
||||
import { SessionId } 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 +31,7 @@ const CHECKPOINTS = [
|
||||
'retry-recovered',
|
||||
'retry-cancelled',
|
||||
'retry-exhausted',
|
||||
'banner-gradient',
|
||||
'code-mode-pending',
|
||||
'dynamic-workflow-pending',
|
||||
'cordis-tools-pending',
|
||||
@@ -45,6 +47,9 @@ const CHECKPOINTS = [
|
||||
'model-switching',
|
||||
'errors-and-help',
|
||||
'disposed-terminal',
|
||||
'resume-sessions',
|
||||
'status-diagnostics',
|
||||
'status-diagnostics-narrow',
|
||||
] as const
|
||||
|
||||
// Real-loop scenarios own their assertions in separate snapshot suites but
|
||||
@@ -60,9 +65,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) {
|
||||
@@ -312,6 +331,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 = {
|
||||
@@ -600,6 +625,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 { CombinedAutocompleteProvider, 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, type JsonValue } from '@deepseek-ai/dsh-session'
|
||||
import SessionStore, { SessionId, type JsonValue, 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'
|
||||
@@ -16,6 +17,7 @@ import type {} from '@deepseek-ai/dsh-llm-retry'
|
||||
import {
|
||||
createTuiChat,
|
||||
mountTui,
|
||||
renderSkillInvocation,
|
||||
resolveTuiConfig,
|
||||
type TuiRuntime,
|
||||
} from '../src/index.ts'
|
||||
@@ -124,6 +126,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({
|
||||
@@ -137,6 +148,7 @@ describe('TUI config', () => {
|
||||
modelDialogMaxHeight: 20,
|
||||
showHardwareCursor: false,
|
||||
color: true,
|
||||
truecolor: false,
|
||||
title: 'DeepSeek Harness',
|
||||
})
|
||||
expect(resolveTuiConfig({
|
||||
@@ -150,6 +162,7 @@ describe('TUI config', () => {
|
||||
modelDialogMaxHeight: 16,
|
||||
showHardwareCursor: true,
|
||||
color: false,
|
||||
truecolor: true,
|
||||
title: 'DSH',
|
||||
})).toEqual({
|
||||
showReasoning: false,
|
||||
@@ -162,11 +175,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({
|
||||
@@ -205,6 +328,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')
|
||||
@@ -231,13 +357,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()
|
||||
|
||||
@@ -326,8 +453,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')
|
||||
@@ -349,7 +475,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)
|
||||
@@ -418,6 +544,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' }, contexts: [], 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' }, contexts: [], 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' }, contexts: [], 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' }, contexts: [], 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',
|
||||
@@ -521,6 +811,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()
|
||||
|
||||
@@ -542,17 +952,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')
|
||||
}
|
||||
@@ -565,8 +973,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()
|
||||
@@ -975,7 +1384,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')
|
||||
@@ -986,7 +1395,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' })
|
||||
@@ -1031,7 +1441,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: [] } })
|
||||
@@ -1130,6 +1541,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')
|
||||
@@ -1146,6 +1562,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()
|
||||
@@ -1155,6 +1575,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()
|
||||
@@ -1263,6 +1684,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: {
|
||||
@@ -1636,6 +2204,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)
|
||||
@@ -1817,4 +2419,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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
{
|
||||
"path": "../../context/session-reference"
|
||||
},
|
||||
{
|
||||
"path": "../../session-persistence/session-persistence"
|
||||
},
|
||||
{
|
||||
"path": "../../session-title/session-title"
|
||||
},
|
||||
@@ -44,6 +47,9 @@
|
||||
{
|
||||
"path": "../commands"
|
||||
},
|
||||
{
|
||||
"path": "../../skill/skill"
|
||||
},
|
||||
{
|
||||
"path": "../user-interaction"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user