feat: sweep all sections for already-done tasks before picking new work

This commit is contained in:
Azreen Jamal
2026-03-06 16:33:46 +08:00
parent 8309fc1869
commit 768ccada4b
+69 -10
View File
@@ -89,17 +89,13 @@ export class TaskLoop {
}
try {
logger.info("task-loop", "Polling for Asana tasks...");
// First: sweep all sections for tasks that are already done
await this.sweepDoneTasks();
// Search TODO sections in priority order
let tasks: AsanaTask[] = [];
for (const sectionName of SECTIONS.TODO) {
tasks = await this.asana.getIncompleteTasks(this.config.asanaProjectGid, sectionName);
if (tasks.length > 0) {
logger.info("task-loop", `Found ${tasks.length} task(s) in "${sectionName}"`);
break;
}
}
// Then: pick up new tasks to execute
logger.info("task-loop", "Polling for new Asana tasks...");
let tasks = await this.getTasksFromSections(this.config.asanaProjectGid, SECTIONS.TODO);
if (tasks.length === 0) {
logger.info("task-loop", "No pending tasks found");
@@ -260,6 +256,69 @@ EVIDENCE: one line why`;
}
}
private async sweepDoneTasks() {
try {
// Get all incomplete tasks from all active sections (not just TODO)
const sweepSections = [...SECTIONS.TODO, ...SECTIONS.IN_PROGRESS];
const allTasks: AsanaTask[] = [];
for (const sectionName of sweepSections) {
const section = await this.asana.findSection(this.config.asanaProjectGid, sectionName);
if (!section) continue;
const tasks = await this.asana.getSectionTasks(section.gid);
const incomplete = tasks.filter((t) => !t.completed);
allTasks.push(...incomplete);
}
if (allTasks.length === 0) return;
// Deduplicate by GID
const seen = new Set<string>();
const uniqueTasks = allTasks.filter((t) => {
if (seen.has(t.gid)) return false;
seen.add(t.gid);
return true;
});
logger.info("task-loop", `Sweeping ${uniqueTasks.length} incomplete tasks for already-done work`);
for (const task of uniqueTasks) {
const check = await this.verifyTaskAlreadyDone(task);
if (check.done) {
logger.info("task-loop", `Sweep: "${task.name}" is already done`, { evidence: check.evidence });
await this.asana.addComment(
task.gid,
`✅ Pi Worker sweep: This task is **already completed** on the server.\n\nEvidence:\n${check.evidence}`
);
const doneSection = await this.findFirstSection(SECTIONS.DONE);
if (doneSection) {
await this.asana.moveTaskToSection(task.gid, doneSection.gid);
}
await this.asana.updateTask(task.gid, { completed: true });
logger.info("task-loop", `Sweep: Marked done: ${task.name}`);
} else {
logger.debug("task-loop", `Sweep: "${task.name}" not yet done`, { evidence: check.evidence });
}
}
} catch (error: any) {
logger.error("task-loop", `Sweep error: ${error.message}`);
}
}
private async getTasksFromSections(projectGid: string, sectionNames: string[]): Promise<AsanaTask[]> {
for (const name of sectionNames) {
const section = await this.asana.findSection(projectGid, name);
if (!section) continue;
const tasks = await this.asana.getSectionTasks(section.gid);
const incomplete = tasks.filter((t) => !t.completed);
if (incomplete.length > 0) return incomplete;
}
return [];
}
private buildTaskContext(task: AsanaTask): string {
const parts = [
`Asana Task: ${task.name}`,