mini: monochrome rendered markdown only (#38656)
This commit is contained in:
parent
00f063b381
commit
4184149b90
7 changed files with 322 additions and 45 deletions
|
|
@ -231,29 +231,28 @@ describe("run entry body", () => {
|
|||
})
|
||||
|
||||
test("promotes subagent results to markdown and falls back to structured summaries", () => {
|
||||
expect(
|
||||
entryBody(
|
||||
toolCommit({
|
||||
tool: "subagent",
|
||||
state: {
|
||||
status: "completed",
|
||||
input: {
|
||||
description: "Inspect reducer",
|
||||
agent: "explore",
|
||||
},
|
||||
content: [{ type: "text", text: "# Findings\n\n- Footer stays live" }],
|
||||
metadata: {
|
||||
sessionID: "ses-child-1",
|
||||
status: "completed",
|
||||
output: "# Findings\n\n- Footer stays live",
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
const result = toolCommit({
|
||||
tool: "subagent",
|
||||
state: {
|
||||
status: "completed",
|
||||
input: {
|
||||
description: "Inspect reducer",
|
||||
agent: "explore",
|
||||
},
|
||||
content: [{ type: "text", text: "# Findings\n\n- Footer stays live" }],
|
||||
metadata: {
|
||||
sessionID: "ses-child-1",
|
||||
status: "completed",
|
||||
output: "# Findings\n\n- Footer stays live",
|
||||
},
|
||||
},
|
||||
})
|
||||
const markdown = {
|
||||
type: "markdown",
|
||||
content: "# Findings\n\n- Footer stays live",
|
||||
})
|
||||
} as const
|
||||
expect(entryBody(result)).toEqual(markdown)
|
||||
expect(entryBody(result, { mono: true })).toEqual(markdown)
|
||||
|
||||
expect(
|
||||
structured(
|
||||
|
|
|
|||
|
|
@ -381,6 +381,83 @@ test("run entry content updates when live commit text changes", async () => {
|
|||
}
|
||||
})
|
||||
|
||||
test("run entry content preserves monochrome markdown grammar", async () => {
|
||||
const [commit, setCommit] = createSignal<StreamCommit>({
|
||||
kind: "assistant",
|
||||
text: "• literal\n\n———\n\narrow →",
|
||||
phase: "progress",
|
||||
source: "assistant",
|
||||
messageID: "msg-1",
|
||||
partID: "part-1",
|
||||
})
|
||||
const app = await testRender(
|
||||
() => (
|
||||
<box width={60} height={8}>
|
||||
<RunEntryContent commit={commit()} theme={RUN_THEME_FALLBACK} opts={{ mono: true }} />
|
||||
</box>
|
||||
),
|
||||
{ width: 60, height: 8 },
|
||||
)
|
||||
|
||||
try {
|
||||
await app.renderOnce()
|
||||
const rows = app
|
||||
.captureCharFrame()
|
||||
.split("\n")
|
||||
.map((row) => row.trimEnd())
|
||||
expect(rows).toContain("* literal")
|
||||
expect(rows).toContain("------")
|
||||
expect(rows).toContain("arrow ->")
|
||||
expect(rows.join("\n")).not.toMatch(/[^\x00-\x7f]/)
|
||||
|
||||
setCommit({ ...commit(), text: "- Café\n- arrow →\n- third …" })
|
||||
await app.renderOnce()
|
||||
expect(app.captureCharFrame()).toContain("- arrow ->")
|
||||
expect(app.captureCharFrame()).toContain("- third ...")
|
||||
|
||||
setCommit({ ...commit(), text: "| A | B |\n| - | - |\n| Café | → |" })
|
||||
await app.renderOnce()
|
||||
expect(app.captureCharFrame()).toContain("Caf?")
|
||||
expect(app.captureCharFrame()).toContain("->")
|
||||
setCommit({ ...commit(), text: "| A | B |\n| - | - |\n| Café | … |" })
|
||||
await app.renderOnce()
|
||||
expect(app.captureCharFrame()).toContain("...")
|
||||
|
||||
setCommit({ ...commit(), text: "```\nCafé → …\n```" })
|
||||
await app.renderOnce()
|
||||
expect(app.captureCharFrame()).toContain("Caf? -> ...")
|
||||
expect(app.captureCharFrame()).not.toMatch(/[^\x00-\x7f]/)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("run entry content eagerly renders final monochrome markdown", async () => {
|
||||
const app = await testRender(
|
||||
() => (
|
||||
<box width={60} height={6}>
|
||||
<RunEntryContent
|
||||
commit={{ kind: "tool", text: "", phase: "final", source: "tool", tool: "subagent" }}
|
||||
body={{ type: "markdown", content: "# Café →\n\n```markdown\nCafé →\n```" }}
|
||||
theme={RUN_THEME_FALLBACK}
|
||||
opts={{ mono: true }}
|
||||
/>
|
||||
</box>
|
||||
),
|
||||
{ width: 60, height: 6 },
|
||||
)
|
||||
|
||||
try {
|
||||
await app.renderOnce()
|
||||
const frame = app.captureCharFrame()
|
||||
expect(frame).toContain("# Caf? ->")
|
||||
expect(frame).toContain("Caf? ->")
|
||||
expect(frame).not.toMatch(/[^\x00-\x7f]/)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("direct command panel renders grouped actions without catalog commands", async () => {
|
||||
const [commands] = createSignal<RunCommand[] | undefined>([
|
||||
command({ name: "review", description: "Review code" }),
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ async function setup(
|
|||
theme?: RunTheme
|
||||
onThemeRelease?: (theme: RunTheme) => void
|
||||
mono?: boolean
|
||||
failHighlight?: boolean
|
||||
} = {},
|
||||
) {
|
||||
const out = await createTestRenderer({
|
||||
|
|
@ -83,6 +84,11 @@ async function setup(
|
|||
|
||||
const treeSitterClient = new MockTreeSitterClient({ autoResolveTimeout: 0 })
|
||||
treeSitterClient.setMockResult({ highlights: [] })
|
||||
if (input.failHighlight) {
|
||||
treeSitterClient.highlightOnce = async () => {
|
||||
throw new Error("highlight failed")
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
renderer: out.renderer,
|
||||
|
|
@ -217,7 +223,25 @@ test("renders monochrome scrollback as ASCII markdown", async () => {
|
|||
try {
|
||||
await out.scrollback.append(assistant("# H"))
|
||||
expect(Reflect.get(out.scrollback, "active")?.renderable).toBeInstanceOf(MarkdownRenderable)
|
||||
await out.scrollback.append(assistant("éading →\n\n> “quote”\n\n---\n\n| A | B |\n| - | - |\n| α | β |"))
|
||||
await out.scrollback.append(
|
||||
assistant(
|
||||
"éading →\n\n> “quote”\n\n---\n\n| A | B |\n| - | - |\n| α | β |\n\n• literal\n\n———\n\n[café](https://example.com/café)",
|
||||
),
|
||||
)
|
||||
const active: unknown = Reflect.get(out.scrollback, "active")
|
||||
const renderable =
|
||||
active && typeof active === "object" && "renderable" in active && active.renderable instanceof MarkdownRenderable
|
||||
? active.renderable
|
||||
: undefined
|
||||
expect(renderable?._blockStates.slice(-3).map((state) => state.token.type)).toEqual([
|
||||
"paragraph",
|
||||
"paragraph",
|
||||
"paragraph",
|
||||
])
|
||||
const link = renderable?._blockStates.at(-1)?.token
|
||||
const tokens = link && "tokens" in link && Array.isArray(link.tokens) ? link.tokens : []
|
||||
const href = tokens.find((token) => "href" in token)
|
||||
expect(href && "href" in href ? href.href : undefined).toBe("https://example.com/café")
|
||||
await out.scrollback.complete()
|
||||
out.renderer.writeToScrollback((ctx) => ({
|
||||
root: new TextRenderable(ctx.renderContext, {
|
||||
|
|
@ -235,6 +259,8 @@ test("renders monochrome scrollback as ASCII markdown", async () => {
|
|||
expect(rendered).toContain('| "quote"')
|
||||
expect(rendered).toContain("------------------------------------------------------------")
|
||||
expect(rendered).toContain("? ?")
|
||||
expect(rendered).toContain("* literal")
|
||||
expect(rendered).toContain("------")
|
||||
expect(rendered).toContain("plain ? emoji ?")
|
||||
expect(rendered).not.toMatch(/[^\x00-\x7f]/)
|
||||
} finally {
|
||||
|
|
@ -243,6 +269,64 @@ test("renders monochrome scrollback as ASCII markdown", async () => {
|
|||
}
|
||||
})
|
||||
|
||||
test("renders completed subagent markdown in monochrome mode", async () => {
|
||||
const out = await setup({ mono: true, width: 60 })
|
||||
|
||||
try {
|
||||
await out.scrollback.append(
|
||||
toolCommit({
|
||||
tool: "subagent",
|
||||
phase: "final",
|
||||
toolState: "completed",
|
||||
state: {
|
||||
status: "completed",
|
||||
input: { description: "Inspect reducer", agent: "explore" },
|
||||
content: [{ type: "text", text: "# Findings\n\n- Café → stable" }],
|
||||
metadata: {
|
||||
sessionID: "ses-child-1",
|
||||
status: "completed",
|
||||
output: "# Findings\n\n- Café → stable",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const commits = claim(out.renderer)
|
||||
try {
|
||||
expect(commits).toHaveLength(1)
|
||||
expect(commits[0]?.trailingNewline).toBe(true)
|
||||
const output = render(commits)
|
||||
expect(output).toContain("# Findings")
|
||||
expect(output).toContain("- Caf? -> stable")
|
||||
expect(output).not.toMatch(/[^\x00-\x7f]/)
|
||||
} finally {
|
||||
destroy(commits)
|
||||
}
|
||||
} finally {
|
||||
out.scrollback.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("keeps fenced code monochrome when highlighting fails", async () => {
|
||||
const out = await setup({ mono: true, failHighlight: true })
|
||||
|
||||
try {
|
||||
await out.scrollback.append(assistant("```ts\nCafé → …\n```"))
|
||||
await out.scrollback.complete()
|
||||
|
||||
const commits = claim(out.renderer)
|
||||
try {
|
||||
const output = render(commits)
|
||||
expect(output).toContain("Caf? -> ...")
|
||||
expect(output).not.toMatch(/[^\x00-\x7f]/)
|
||||
} finally {
|
||||
destroy(commits)
|
||||
}
|
||||
} finally {
|
||||
out.scrollback.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
function user(text: string): StreamCommit {
|
||||
return {
|
||||
kind: "user",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue