(res: http.ServerResponse, url: URL)
| 676 | } |
| 677 | |
| 678 | private serveTasks(res: http.ServerResponse, url: URL): void { |
| 679 | this.store.recordViewerEvent("tasks_list"); |
| 680 | const status = url.searchParams.get("status") ?? undefined; |
| 681 | const owner = url.searchParams.get("owner") ?? undefined; |
| 682 | const session = url.searchParams.get("session") ?? undefined; |
| 683 | const limit = Math.min(100, Math.max(1, Number(url.searchParams.get("limit")) || 50)); |
| 684 | const offset = Math.max(0, Number(url.searchParams.get("offset")) || 0); |
| 685 | const { tasks, total } = this.store.listTasks({ status, limit, offset, owner, session }); |
| 686 | |
| 687 | const db = (this.store as any).db; |
| 688 | const items = tasks.map((t) => { |
| 689 | const meta = db.prepare("SELECT skill_status, owner FROM tasks WHERE id = ?").get(t.id) as { skill_status: string | null; owner: string | null } | undefined; |
| 690 | const hubTask = this.getHubTaskForLocal(t.id); |
| 691 | const share = this.resolveTaskTeamShareForApi(t.id, hubTask); |
| 692 | return { |
| 693 | id: t.id, |
| 694 | sessionKey: t.sessionKey, |
| 695 | title: t.title, |
| 696 | summary: t.summary ?? "", |
| 697 | status: t.status, |
| 698 | startedAt: t.startedAt, |
| 699 | endedAt: t.endedAt, |
| 700 | chunkCount: this.store.countChunksByTask(t.id), |
| 701 | skillStatus: meta?.skill_status ?? null, |
| 702 | owner: meta?.owner ?? "agent:main", |
| 703 | sharingVisibility: share.visibility, |
| 704 | }; |
| 705 | }); |
| 706 | |
| 707 | this.backfillTaskEmbeddings(items); |
| 708 | this.jsonResponse(res, { tasks: items, total, limit, offset }); |
| 709 | this.autoFinalizeStaleTasks(); |
| 710 | } |
| 711 | |
| 712 | private getTaskAutoFinalizeMs(): number { |
| 713 | const hours = this.ctx?.config?.taskAutoFinalizeHours; |
no test coverage detected