simplify collapsed task rows

This commit is contained in:
wassname
2026-06-14 11:49:36 +08:00
parent da2879d94c
commit 29c928c805
4 changed files with 140 additions and 52 deletions
+99
View File
@@ -0,0 +1,99 @@
import { describe, expect, it, vi } from "vitest";
import proofTasksExtension from "../src/index.js";
type RegisteredTool = {
name: string;
execute: (...args: any[]) => Promise<any>;
};
function makeHarness() {
const tools = new Map<string, RegisteredTool>();
const pi = {
on: vi.fn(),
registerTool: vi.fn((tool: RegisteredTool) => tools.set(tool.name, tool)),
registerCommand: vi.fn(),
sendMessage: vi.fn(),
};
proofTasksExtension(pi as any);
async function execTool(name: string, params: Record<string, unknown>) {
const tool = tools.get(name);
if (!tool) throw new Error(`Tool ${name} not registered`);
return tool.execute("tool-call", params, undefined, undefined, {});
}
return { execTool };
}
describe("TaskList", () => {
it("renders a compact one-line-per-task summary", async () => {
const harness = makeHarness();
await harness.execTool("TaskCreate", {
subject: "Design the flux capacitor",
description: "Desc",
done_criterion: "done",
});
await harness.execTool("TaskCreate", {
subject: "Acquiring plutonium",
description: "Desc",
done_criterion: "done",
progress_label: "Acquiring plutonium",
});
await harness.execTool("TaskCreate", {
subject: "Install flux capacitor in DeLorean",
description: "Desc",
done_criterion: "done",
parentId: "1",
});
await harness.execTool("TaskCreate", {
subject: "Test time travel at 88 mph",
description: "Desc",
done_criterion: "done",
});
await harness.execTool("TaskUpdate", { taskId: "1", status: "completed" });
await harness.execTool("TaskUpdate", { taskId: "2", status: "in_progress" });
await harness.execTool("TaskUpdate", { taskId: "3", add_blocked_by: ["1"] });
await harness.execTool("TaskUpdate", { taskId: "4", add_blocked_by: ["2", "3"] });
const result = await harness.execTool("TaskList", {});
const text = result.content[0].text;
expect(text).toContain("● 4 tasks (1 in progress, 3 open)");
expect(text).toContain("◻ #1 Design the flux capacitor");
expect(text).toContain("◼ #2 Acquiring plutonium");
expect(text).toContain("◻ #3 Install flux capacitor in DeLorean subtask of #1 blocked by #1");
expect(text).toContain("◻ #4 Test time travel at 88 mph blocked by #2, #3");
expect(text).not.toContain("[ACTIVE]");
expect(text).not.toContain("[PENDING]");
expect(text).not.toContain("[DONE");
expect(text).not.toContain("🛠");
expect(text).not.toContain("test:");
});
it("shows completed subtasks without proof-lane clutter", async () => {
const harness = makeHarness();
await harness.execTool("TaskCreate", {
subject: "Top-level goal",
description: "Desc",
done_criterion: "done",
});
await harness.execTool("TaskCreate", {
subject: "Finished checklist item",
description: "Desc",
done_criterion: "done",
parentId: "1",
});
await harness.execTool("TaskUpdate", { taskId: "2", status: "completed" });
const result = await harness.execTool("TaskList", {});
const text = result.content[0].text;
expect(text).toContain("● 2 tasks (1 done, 1 open)");
expect(text).toContain("✔ #2 Finished checklist item subtask of #1");
expect(text).not.toContain("[DONE");
expect(text).not.toContain("🛠");
});
});
+12 -10
View File
@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { REVIEW_BADGES } from "../src/review-badges.js";
import { TaskStore } from "../src/task-store.js";
import { TaskWidget, type Theme, type UICtx } from "../src/ui/task-widget.js";
@@ -73,11 +72,12 @@ describe("TaskWidget", () => {
widget.update();
const lines = renderWidget(ui.state);
expect(lines).toHaveLength(3); // header + 1 task + done_criterion
expect(lines).toHaveLength(2); // header + 1 task
expect(lines[0]).toContain("1 tasks");
expect(lines[0]).toContain("1 open");
expect(lines[1]).toContain("◻");
expect(lines[1]).toContain("Do something");
expect(lines[1]).not.toContain("done");
});
it("renders in-progress tasks with ◼ icon", () => {
@@ -100,16 +100,18 @@ describe("TaskWidget", () => {
expect(lines[1]).toContain("~~#1 Done task~~");
});
it("renders robot review badges on completed tasks", () => {
it("does not render proof badges on collapsed rows", () => {
store.create("Done task", "Desc", "done");
store.update("1", {
metadata: { robot_review_observations: ["Observed output drift on seed 2"] },
metadata: { robot_review_observations: ["Observed output drift on seed 2"], lgtm_evidence: "verbatim output" },
});
store.complete("1");
widget.update();
const lines = renderWidget(ui.state);
expect(lines[1]).toContain(REVIEW_BADGES.robot);
expect(lines[1]).not.toContain("[");
expect(lines[1]).not.toContain("🛠");
expect(lines[1]).not.toContain("🤖");
});
it("renders active tasks with spinner icon", () => {
@@ -181,9 +183,9 @@ describe("TaskWidget", () => {
widget.update();
const lines = renderWidget(ui.state);
// header + 5 visible tasks (each has 2 lines: task + done_criterion) + "...and 10 more"
expect(lines).toHaveLength(12);
expect(lines[11]).toContain("10 more");
// header + 5 visible tasks + "...and 10 more"
expect(lines).toHaveLength(7);
expect(lines[6]).toContain("10 more");
});
it("tracks token usage for active tasks", () => {
@@ -241,7 +243,7 @@ describe("TaskWidget", () => {
const lines = renderWidget(ui.state);
expect(lines[1]).toContain("Processing A…");
expect(lines[3]).toContain("Processing B…");
expect(lines[2]).toContain("Processing B…");
});
it("distributes token usage across all active tasks", () => {
@@ -257,7 +259,7 @@ describe("TaskWidget", () => {
const lines = renderWidget(ui.state);
// Both tasks should have the same token counts
expect(lines[1]).toContain("↑ 100");
expect(lines[3]).toContain("↑ 100");
expect(lines[2]).toContain("↑ 100");
});
it("dispose clears widget and timer", () => {