feat: strengthen task workflow and compaction recovery

This commit is contained in:
lesetong
2026-07-23 01:23:10 +08:00
parent fe05b278a4
commit 7d876735b2
13 changed files with 380 additions and 81 deletions
+53 -13
View File
@@ -21,32 +21,59 @@ async function execute(tool: any, params: unknown) {
return tool.execute("call", params, undefined, undefined, {});
}
test("registers the five requested tools with minimal top-level parameters", () => {
test("registers five focused tools without the old add_task alias", () => {
const { tools } = registeredTools();
assert.deepEqual([...tools.keys()], ["add_task", "update_task", "rm_task", "list_task", "get_task"]);
assert.deepEqual(Object.keys(tools.get("add_task").parameters.properties), ["tasks"]);
assert.deepEqual([...tools.keys()], ["set_tasks", "update_task", "rm_task", "list_task", "get_task"]);
assert.deepEqual(Object.keys(tools.get("set_tasks").parameters.properties), ["mode", "tasks", "force"]);
assert.deepEqual(Object.keys(tools.get("update_task").parameters.properties), ["tasks"]);
assert.deepEqual(Object.keys(tools.get("rm_task").parameters.properties), ["ids"]);
assert.deepEqual(Object.keys(tools.get("rm_task").parameters.properties), ["ids", "reason"]);
assert.deepEqual(Object.keys(tools.get("list_task").parameters.properties), []);
assert.deepEqual(Object.keys(tools.get("get_task").parameters.properties), ["ids"]);
});
test("mutations return compact content and complete persistence snapshots", async () => {
test("set_tasks appends optional-description tasks and persists a complete snapshot", async () => {
const harness = registeredTools();
const result = await execute(harness.tools.get("add_task"), {
tasks: [{ name: "Parent", description: "Parent", children: [{ name: "Child", description: "Child" }] }],
const result = await execute(harness.tools.get("set_tasks"), {
mode: "append",
tasks: [{ name: "Parent", children: [{ name: "Child", description: "Useful detail" }] }],
});
assert.equal(result.content[0].text, "Added 2 tasks: 1, 2. 0/2 done.");
assert.equal(result.details.action, "append");
assert.equal(result.details.snapshot.tasks.length, 2);
assert.equal(result.details.snapshot.tasks[0].description, undefined);
assert.equal(result.details.snapshot.nextId, 3);
assert.equal(harness.changes(), 1);
});
test("tool validation errors are summarized while preserving atomic state", async () => {
test("set_tasks atomically replaces or clears the tree and resets IDs", async () => {
const harness = registeredTools();
await execute(harness.tools.get("add_task"), {
tasks: [{ name: "Parent", description: "Parent", children: [{ name: "Child", description: "Child" }] }],
await execute(harness.tools.get("set_tasks"), {
mode: "append",
tasks: [{ name: "Old", status: "done" }],
});
const replaced = await execute(harness.tools.get("set_tasks"), {
mode: "replace",
tasks: [{ name: "New", status: "in-progress" }],
});
assert.equal(replaced.content[0].text, "Replaced task tree with 1 task. 0/1 done. Task IDs restart at 1.");
assert.deepEqual(harness.state.list().map((task) => [task.id, task.name]), [[1, "New"]]);
const cleared = await execute(harness.tools.get("set_tasks"), {
mode: "replace",
tasks: [],
force: true,
});
assert.equal(cleared.content[0].text, "Cleared task tree. Task IDs reset to 1.");
assert.deepEqual(harness.state.snapshot(), { tasks: [], nextId: 1 });
});
test("tool validation errors preserve atomic state", async () => {
const harness = registeredTools();
await execute(harness.tools.get("set_tasks"), {
mode: "append",
tasks: [{ name: "Parent", children: [{ name: "Child" }] }],
});
const before = harness.state.snapshot();
@@ -58,10 +85,22 @@ test("tool validation errors are summarized while preserving atomic state", asyn
assert.equal(harness.changes(), 1);
});
test("list is compact and get returns full JSON for multiple IDs", async () => {
test("rm_task requires and reports a constrained removal reason", async () => {
const harness = registeredTools();
await execute(harness.tools.get("add_task"), {
tasks: [{ name: "Parent", description: "Detailed", children: [{ name: "Child", description: "Child detail" }] }],
await execute(harness.tools.get("set_tasks"), {
mode: "append",
tasks: [{ name: "Duplicate" }],
});
const removed = await execute(harness.tools.get("rm_task"), { ids: [1], reason: "duplicate" });
assert.match(removed.content[0].text, /Reason: duplicate\.$/);
assert.deepEqual(harness.state.list(), []);
});
test("list is compact and get returns available details for multiple IDs", async () => {
const harness = registeredTools();
await execute(harness.tools.get("set_tasks"), {
mode: "append",
tasks: [{ name: "Parent", description: "Detailed", children: [{ name: "Child" }] }],
});
const list = await execute(harness.tools.get("list_task"), {});
@@ -71,5 +110,6 @@ test("list is compact and get returns full JSON for multiple IDs", async () => {
const parsed = JSON.parse(get.content[0].text);
assert.equal(parsed[0].description, "Detailed");
assert.deepEqual(parsed[0].childrenIds, [2]);
assert.equal(parsed[1].description, undefined);
assert.equal(parsed[1].parentId, 1);
});