Files
hongjr03 74f5c4a02e fix(hub): render Feishu checklist from TaskCreate/TaskUpdate
Headless Claud agents expose TaskCreate/TaskUpdate rather than TodoWrite.
Fold those tool events into the live card checklist, pass real tool names
and inputs through tool-result, and hide Task* noise once the panel is up.
2026-07-23 23:21:34 +08:00

112 lines
3.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
applyChecklistToolEvent,
isTodoWriteTool,
parseTodoWriteInput,
todoProgressSummary,
} from "../../src/agent/todoList.js";
import { buildAgentCard } from "../../src/feishu/card/builder.js";
describe("todo list parse", () => {
it("accepts TodoWrite payloads", () => {
const todos = parseTodoWriteInput({
todos: [
{ content: "搜题", status: "completed", activeForm: "正在搜题" },
{ content: "写报告", status: "in_progress", activeForm: "正在写报告" },
{ content: "发卡片", status: "pending" },
],
});
expect(todos).toEqual([
{ id: undefined, content: "搜题", status: "completed", activeForm: "正在搜题" },
{ id: undefined, content: "写报告", status: "in_progress", activeForm: "正在写报告" },
{ id: undefined, content: "发卡片", status: "pending", activeForm: undefined },
]);
expect(todoProgressSummary(todos!)).toEqual({ completed: 1, total: 3, inProgress: 1 });
});
it("folds TaskCreate + TaskUpdate into a checklist", () => {
let todos = applyChecklistToolEvent([], {
toolName: "TaskCreate",
input: { subject: "说你好", description: "greet" },
result: "Task #1 created successfully: 说你好",
});
expect(todos).toEqual([
{ id: "1", content: "说你好", status: "pending", activeForm: undefined },
]);
todos = applyChecklistToolEvent(todos!, {
toolName: "TaskCreate_1",
input: { subject: "算 1+1", description: "math" },
result: "Task #2 created successfully: 算 1+1",
});
todos = applyChecklistToolEvent(todos!, {
toolName: "TaskUpdate",
input: { taskId: "1", status: "in_progress", activeForm: "正在问好" },
result: "Updated task #1 status",
});
todos = applyChecklistToolEvent(todos!, {
toolName: "TaskUpdate_4",
input: { taskId: "1", status: "completed" },
result: "Updated task #1 status",
});
todos = applyChecklistToolEvent(todos!, {
toolName: "TaskUpdate",
input: { taskId: "2", status: "completed" },
result: "Updated task #2 status",
});
expect(todos).toEqual([
{ id: "1", content: "说你好", status: "completed", activeForm: "正在问好" },
{ id: "2", content: "算 1+1", status: "completed", activeForm: undefined },
]);
expect(todoProgressSummary(todos!)).toEqual({ completed: 2, total: 2, inProgress: 0 });
});
it("recognizes TodoWrite tool names", () => {
expect(isTodoWriteTool("TodoWrite")).toBe(true);
expect(isTodoWriteTool("mcp__cph_hub__todo_write")).toBe(true);
expect(isTodoWriteTool("Bash")).toBe(false);
});
});
describe("agent card todo panel", () => {
it("renders a progress checklist when todos are present", () => {
const card = buildAgentCard({
phase: "streaming",
text: "",
reasoningText: undefined,
todos: [
{ id: "1", content: "A", status: "completed", activeForm: undefined },
{ id: "2", content: "B", status: "in_progress", activeForm: "Doing B" },
{ id: "3", content: "C", status: "pending", activeForm: undefined },
],
toolUseSteps: [
{
id: "1",
seq: 1,
toolName: "TaskCreate",
toolUseId: "t1",
input: {},
result: undefined,
error: undefined,
status: "success",
startedAt: 0,
finishedAt: 1,
durationMs: 1,
},
],
toolUseElapsedMs: 10,
isError: undefined,
interrupted: undefined,
runId: "run-1",
});
const json = JSON.stringify(card);
expect(json).toContain("任务进度 1/3");
expect(json).toContain("Doing B");
expect(json).toContain("collapsible_panel");
// TaskCreate noise filtered when checklist present (no separate tool panel if only Task*)
expect(json).not.toContain("TaskCreate");
});
});