fix(coding-agent/task): fixed task glyphs for running, pending, and completed progress

- Updated task call and result headers to use the dispatch glyph during running async calls instead of spinner-style states.
- Switched running and pending agent rows to a static done-dot marker and reused the dot with foreground color settling when rows complete.
- Updated task rendering tests to validate the new glyphs and ensure running/pending rows do not emit spinner or pending symbols.
This commit is contained in:
can1357
2026-06-12 04:58:21 +02:00
parent 228d536a36
commit 4f0360e77a
4 changed files with 89 additions and 25 deletions
@@ -66,7 +66,7 @@ describe("task progress rendering", () => {
vi.restoreAllMocks();
resetSettingsForTest();
});
it("renders running task rows static with the task icon", async () => {
it("renders running task rows static with the agent dot", async () => {
const theme = (await getThemeByName("dark"))!;
expect(theme).toBeDefined();
const options: RenderResultOptions = { expanded: false, isPartial: true, spinnerFrame: 0 };
@@ -88,13 +88,14 @@ describe("task progress rendering", () => {
const rawRow1 = renderRow(700);
const strippedRow = Bun.stripANSI(rawRow0);
expect(strippedRow).toContain(`${theme.symbol("tool.task")} CountPackages: List workspace packages`);
expect(strippedRow).toContain(`${theme.status.done} CountPackages: List workspace packages`);
expect(strippedRow).not.toContain(theme.symbol("tool.task"));
expect(strippedRow).not.toContain(theme.status.running);
expect(strippedRow).not.toContain(theme.getSpinnerFrames("status")[0]);
expect(rawRow0).toBe(rawRow1);
});
it("keeps the task icon when shimmer is disabled", async () => {
it("keeps the agent dot when shimmer is disabled", async () => {
const theme = (await getThemeByName("dark"))!;
resetSettingsForTest();
await Settings.init({ inMemory: true, overrides: { "display.shimmer": "disabled" } });
@@ -111,12 +112,12 @@ describe("task progress rendering", () => {
),
);
expect(strippedRow).toContain(`${theme.symbol("tool.task")} KeySettingsHotPaths`);
expect(strippedRow).toContain(`${theme.status.done} KeySettingsHotPaths`);
expect(strippedRow).not.toContain(theme.status.running);
expect(strippedRow).not.toContain(theme.getSpinnerFrames("status")[0]);
});
it("renders pending task rows with the task icon, not the pending glyph", async () => {
it("renders pending task rows with the agent dot, not the pending glyph", async () => {
const theme = (await getThemeByName("dark"))!;
const options: RenderResultOptions = { expanded: false, isPartial: true, spinnerFrame: 0 };
const progress = runningProgress({
@@ -141,11 +142,57 @@ describe("task progress rendering", () => {
const rawRow1 = renderRow(700);
const strippedRow = Bun.stripANSI(rawRow0);
expect(strippedRow).toContain(`${theme.symbol("tool.task")} BestGpt: Combine winners for gpt`);
expect(strippedRow).toContain(`${theme.status.done} BestGpt: Combine winners for gpt`);
expect(strippedRow).not.toContain(theme.status.pending);
expect(rawRow0).toBe(rawRow1);
});
it("settles completed rows to the foreground color with the same dot", async () => {
const theme = (await getThemeByName("dark"))!;
const options: RenderResultOptions = { expanded: false, isPartial: true, spinnerFrame: 0 };
const progress = runningProgress({
id: "DonePkg",
status: "completed",
description: "List workspace packages",
});
const row = findRow(
taskToolRenderer.renderResult(
{ content: [{ type: "text", text: "" }], details: detailsFor(progress) },
options,
theme,
),
"DonePkg",
);
const stripped = Bun.stripANSI(row);
expect(stripped).toContain(`${theme.status.done} DonePkg: List workspace packages`);
expect(stripped).not.toContain(theme.symbol("tool.task"));
// Same dot as live rows; completion reads as the label settling from
// accent to the plain foreground color.
const titlePart = `${theme.bold("DonePkg")}: List workspace packages`;
expect(row).toContain(theme.fg("text", titlePart));
expect(row).not.toContain(theme.fg("accent", titlePart));
});
it("shows the dispatch glyph in the header while agents run, not a spinner", async () => {
const theme = (await getThemeByName("dark"))!;
const options: RenderResultOptions = { expanded: false, isPartial: true, spinnerFrame: 0 };
const header = findRow(
taskToolRenderer.renderResult(
{ content: [{ type: "text", text: "" }], details: detailsFor(runningProgress()) },
options,
theme,
),
"Task",
);
const stripped = Bun.stripANSI(header);
expect(stripped).toContain(`${theme.symbol("tool.task")} Task`);
expect(stripped).not.toContain(theme.status.running);
expect(stripped).not.toContain(theme.getSpinnerFrames("status")[0]);
});
it("renders the assignment markdown inside the result frame", async () => {
const theme = (await getThemeByName("dark"))!;
setThemeInstance(theme);