Files
pi-lgtm/src/auto-clear.ts
T
2026-06-14 20:09:30 +08:00

96 lines
3.0 KiB
TypeScript

/**
* auto-clear.ts — Turn-based auto-clearing of completed tasks.
*
* Two modes:
* - "on_task_complete": each completed task gets its own REMINDER_INTERVAL countdown, deleted individually
* - "on_list_complete": countdown starts when ALL tasks are completed, cleared as a batch
*
* Both use the same turn delay (REMINDER_INTERVAL) for consistency.
*/
import type { TaskStore } from "./task-store.js";
export type AutoClearMode = "never" | "on_list_complete" | "on_task_complete";
export class AutoClearManager {
/** Per-task: turn when task was marked completed ("on_task_complete" mode). */
private completedAtTurn = new Map<string, number>();
/** Turn when ALL tasks became completed ("on_list_complete" mode). */
private allCompletedAtTurn: number | null = null;
constructor(
private getStore: () => TaskStore,
private getMode: () => AutoClearMode,
/** How many turns completed tasks linger before auto-clearing. */
private clearDelayTurns = 4,
) {}
/** Record a task completion. Call AFTER cascade logic. */
trackCompletion(taskId: string, currentTurn: number): void {
const mode = this.getMode();
if (mode === "never") return;
if (mode === "on_task_complete") {
this.completedAtTurn.set(taskId, currentTurn);
} else if (mode === "on_list_complete") {
this.checkAllCompleted(currentTurn);
}
}
/** Check if all tasks are completed and start/reset the batch countdown. */
private checkAllCompleted(currentTurn: number): void {
const tasks = this.getStore().list();
if (tasks.length > 0 && tasks.every((t) => t.status === "completed")) {
if (this.allCompletedAtTurn === null)
this.allCompletedAtTurn = currentTurn;
} else {
this.allCompletedAtTurn = null;
}
}
/** Reset batch countdown (e.g., when a new task is created or task goes non-completed). */
resetBatchCountdown(): void {
this.allCompletedAtTurn = null;
}
/** Reset all tracking state (e.g., on new session). */
reset(): void {
this.completedAtTurn.clear();
this.allCompletedAtTurn = null;
}
/**
* Called on each turn start. Deletes tasks whose linger period has expired.
* Returns true if any tasks were cleared.
*/
onTurnStart(currentTurn: number): boolean {
const mode = this.getMode();
let cleared = false;
if (mode === "on_task_complete") {
for (const [taskId, turn] of this.completedAtTurn) {
const task = this.getStore().get(taskId);
if (!task || task.status !== "completed") {
// Task was deleted or reverted — drop stale tracking entry
this.completedAtTurn.delete(taskId);
} else if (currentTurn - turn >= this.clearDelayTurns) {
this.getStore().delete(taskId);
this.completedAtTurn.delete(taskId);
cleared = true;
}
}
} else if (
mode === "on_list_complete" &&
this.allCompletedAtTurn !== null
) {
if (currentTurn - this.allCompletedAtTurn >= this.clearDelayTurns) {
this.getStore().clearCompleted();
this.allCompletedAtTurn = null;
cleared = true;
}
}
return cleared;
}
}