fix(tui): reduce redundant runtime chrome

This commit is contained in:
chengyongru
2026-08-21 17:11:01 +08:00
committed by chengyongru
parent d28687e2e1
commit e9ac83d03f
6 changed files with 183 additions and 30 deletions
+59 -7
View File
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, test } from "bun:test"
import { CliRenderEvents, TextareaRenderable, TextRenderable } from "@opentui/core"
import { BoxRenderable, CliRenderEvents, TextareaRenderable, TextRenderable } from "@opentui/core"
import {
MockTreeSitterClient,
createTestRenderer,
@@ -1279,9 +1279,9 @@ describe("NanobotTui layout", () => {
expect(setup.renderer.width).toBe(width)
expect(setup.renderer.height).toBe(height)
expect(frame).not.toContain("undefined")
expect(occurrences(frame, "Ask nanobot anything")).toBeLessThanOrEqual(1)
expect(occurrences(frame, "Steer this turn…")).toBeLessThanOrEqual(1)
if (width >= 30 && height >= 9) {
expect(occurrences(frame, "Ask nanobot anything")).toBe(1)
expect(occurrences(frame, "Steer this turn…")).toBe(1)
}
expect(occurrences(frame, "nanobot · test/model")).toBe(height >= 14 ? 1 : 0)
}
@@ -1774,13 +1774,18 @@ describe("NanobotTui layout", () => {
expect(frame).toMatch(/Thinking\s+0s/u)
expect(frame).not.toMatch(/[]/u)
expect(frame).not.toContain("hidden reasoning")
const status = (app as unknown as {
const ui = app as unknown as {
status: {
content: { chunks: Array<{ fg?: { toInts(): number[] } }> }
plainText: string
}
}).status
composer: TextareaRenderable
composerFrame: BoxRenderable
}
const status = ui.status
expect(status.plainText).toMatch(/^Thinking\s+0s/u)
expect(ui.composer.placeholder).toBe("Steer this turn…")
expect(ui.composerFrame.height).toBe(3)
const shimmerColors = new Set(
status.content.chunks
.slice(0, "Thinking".length)
@@ -1803,7 +1808,11 @@ describe("NanobotTui layout", () => {
expect(frame).toMatch(/Working\s+0s/u)
expect(frame).not.toMatch(/[]/u)
expect(frame).toContain(" Running pwd")
expect(occurrences(frame, "pwd")).toBe(1)
expect(status.plainText).not.toContain("pwd")
app.accept({ event: "turn_end", chat_id: "chat" })
await setup.flush()
expect(ui.composer.placeholder).toBe("Ask nanobot anything")
})
test("folds long tool traces without discarding their details", async () => {
@@ -1823,8 +1832,9 @@ describe("NanobotTui layout", () => {
await setup.renderOnce()
let frame = setup.captureCharFrame()
expect(frame).toContain("5 earlier steps · Ctrl+O expand")
expect(frame).toContain("7 earlier steps · Ctrl+O expand")
expect(frame).not.toContain("tool_0")
expect(frame).toContain("tool_7")
expect(frame).toContain("tool_9")
setup.mockInput.pressKey("O", { ctrl: true })
@@ -1860,6 +1870,37 @@ describe("NanobotTui layout", () => {
app.accept({ event: "turn_end", chat_id: "chat" })
})
test("groups consecutive file activity only in the collapsed preview", async () => {
setup = await createRenderer({ width: 72, height: 20, screenMode: "alternate-screen" })
const app = mount(setup)
app.accept({
event: "message",
chat_id: "chat",
text: "file progress",
kind: "tool_hint",
tool_events: Array.from({ length: 6 }, (_, index) => ({
phase: "end" as const,
call_id: `read-${index}`,
name: "read_file",
arguments: { path: `/tmp/nanobot-workspace/src/file-${index}.ts` },
})),
})
await setup.renderOnce()
let frame = setup.captureCharFrame()
expect(frame).toContain("6 steps · Ctrl+O expand")
expect(frame).toContain("✓ Read 6 files")
expect(frame).not.toContain("src/file-0.ts")
setup.mockInput.pressKey("O", { ctrl: true })
await setup.renderOnce()
frame = setup.captureCharFrame()
expect(frame).not.toContain("Read 6 files")
expect(frame).toContain("src/file-0.ts")
expect(frame).toContain("src/file-5.ts")
})
test("supports keyboard transcript navigation without rebuilding the layout", async () => {
setup = await createRenderer({ width: 64, height: 16, screenMode: "alternate-screen" })
const app = mount(setup)
@@ -2235,6 +2276,10 @@ describe("NanobotTui in a Herdr pane", () => {
new MockTreeSitterClient({ autoResolveTimeout: 0 }),
host,
)
const ui = app as unknown as {
composer: TextareaRenderable
composerFrame: BoxRenderable
}
await setup.mockInput.typeText("/")
await setup.flush()
@@ -2243,6 +2288,7 @@ describe("NanobotTui in a Herdr pane", () => {
expect(commandFrame).toContain("/new-chat")
expect(commandFrame).toContain("/branch")
setup.mockInput.pressEscape()
ui.composer.setText("")
app.accept({ event: "attached", chat_id: "chat" })
app.accept({
@@ -2259,6 +2305,12 @@ describe("NanobotTui in a Herdr pane", () => {
kind: "tool_hint",
tool_events: [{ phase: "end", call_id: "read", name: "read_file", arguments: { path: "app.ts" } }],
})
await setup.flush()
const activeFrame = setup.captureCharFrame()
expect(occurrences(activeFrame, " Ship the Herdr integration")).toBe(1)
expect(occurrences(activeFrame, "app.ts")).toBe(1)
expect(ui.composer.placeholder).toBe("Steer this turn…")
expect(ui.composerFrame.height).toBe(3)
app.accept({
event: "turn_end",
chat_id: "chat",
@@ -2273,7 +2325,7 @@ describe("NanobotTui in a Herdr pane", () => {
const frame = setup.captureCharFrame()
expect(sessions).toEqual(["chat"])
expect(frame).toContain(" Ship the Herdr integration")
expect(occurrences(frame, " Ship the Herdr integration")).toBe(1)
expect(frame).not.toContain(">_ nanobot")
expect(frame).not.toContain("test/model")
expect(states.some(({ state }) => state === "working")).toBe(true)