feat(FN-5129): complete Step 3 — gate archiveTask lineage references
Fusion-Task-Id: FN-5129 Fusion-Task-Lineage: 77519a37-0552-4e8b-8061-ce84012de978
This commit is contained in:
committed by
gsxdsm
parent
5d9669ad35
commit
bd8bd745d5
@@ -6250,16 +6250,21 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
* Archive all tasks currently in the "done" column.
|
||||
* Returns an array of archived tasks.
|
||||
*/
|
||||
async archiveAllDone(): Promise<Task[]> {
|
||||
async archiveAllDone(options?: { removeLineageReferences?: boolean }): Promise<Task[]> {
|
||||
const doneTasks = await this.listTasks({ slim: true, column: "done" });
|
||||
|
||||
|
||||
if (doneTasks.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Archive all done tasks concurrently
|
||||
const archivedTasks = await Promise.all(
|
||||
doneTasks.map((task) => this.archiveTask(task.id))
|
||||
doneTasks.map((task) =>
|
||||
this.archiveTask(task.id, {
|
||||
cleanup: true,
|
||||
removeLineageReferences: options?.removeLineageReferences,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return archivedTasks;
|
||||
@@ -6268,10 +6273,13 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
/**
|
||||
* Archive a done task (move from done → archived).
|
||||
* Logs the action and emits `task:moved` event.
|
||||
* @param cleanup - When true, also attempts branch cleanup before writing the
|
||||
* cold archive entry. Active task storage is always removed.
|
||||
* @param optionsOrCleanup - Boolean cleanup flag for backward compatibility,
|
||||
* or an options object that also allows removeLineageReferences.
|
||||
*/
|
||||
async archiveTask(id: string, cleanup: boolean = true): Promise<Task> {
|
||||
async archiveTask(
|
||||
id: string,
|
||||
optionsOrCleanup: boolean | { cleanup?: boolean; removeLineageReferences?: boolean } = true,
|
||||
): Promise<Task> {
|
||||
return this.withTaskLock(id, async () => {
|
||||
const dir = this.taskDir(id);
|
||||
const task = await this.readTaskJson(dir);
|
||||
@@ -6287,6 +6295,13 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
);
|
||||
}
|
||||
|
||||
const cleanup = typeof optionsOrCleanup === "boolean" ? optionsOrCleanup : optionsOrCleanup.cleanup !== false;
|
||||
const removeLineageReferences = typeof optionsOrCleanup === "object" && optionsOrCleanup.removeLineageReferences === true;
|
||||
const lineageChildIds = this.findLiveLineageChildren(id);
|
||||
if (lineageChildIds.length > 0 && !removeLineageReferences) {
|
||||
throw new TaskHasLineageChildrenError(id, lineageChildIds);
|
||||
}
|
||||
|
||||
task.column = "archived";
|
||||
task.columnMovedAt = new Date().toISOString();
|
||||
task.updatedAt = task.columnMovedAt;
|
||||
@@ -6314,9 +6329,13 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
const entry = await this.taskToArchiveEntry(task, task.columnMovedAt);
|
||||
this.archiveDb.upsert(entry);
|
||||
|
||||
this.clearLinkedAgentTaskIds(id, task.updatedAt);
|
||||
this.db.prepare('DELETE FROM tasks WHERE id = ?').run(id);
|
||||
this.db.bumpLastModified();
|
||||
let rewrittenLineageChildren: Task[] = [];
|
||||
this.db.transaction(() => {
|
||||
rewrittenLineageChildren = this.rewriteLineageChildrenForRemoval(id, lineageChildIds);
|
||||
this.clearLinkedAgentTaskIds(id, task.updatedAt);
|
||||
this.db.prepare('DELETE FROM tasks WHERE id = ?').run(id);
|
||||
this.db.bumpLastModified();
|
||||
});
|
||||
|
||||
const { rm } = await import("node:fs/promises");
|
||||
await rm(dir, { recursive: true, force: true });
|
||||
@@ -6325,6 +6344,9 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
this.taskCache.delete(id);
|
||||
}
|
||||
|
||||
for (const lineageChild of rewrittenLineageChildren) {
|
||||
this.emit("task:updated", lineageChild);
|
||||
}
|
||||
this.emit("task:moved", { task, from: "done" as Column, to: "archived" as Column, source: "engine" });
|
||||
return this.archiveEntryToTask(entry, false);
|
||||
});
|
||||
@@ -8102,6 +8124,10 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
/**
|
||||
* Cleanup any legacy active archived tasks by writing compact entries to
|
||||
* archive.db and removing task directories.
|
||||
*
|
||||
* Note: lineage pointers to archived/deleted parents are tolerated here.
|
||||
* This cleanup runs on already-archived rows, and lineage integrity gates
|
||||
* are enforced earlier on deleteTask/archiveTask for live children only.
|
||||
*/
|
||||
async cleanupArchivedTasks(): Promise<string[]> {
|
||||
const archivedTasks = await this.listTasks({ column: "archived" });
|
||||
|
||||
Reference in New Issue
Block a user