/** * @fileoverview Session-scoped task forest for the v0.9.0 home page. */ import type { TaskTreeNodeTask, TaskTreeNode } from "./cli-tasks-tree-adapter.js"; import { type TaskContextValue } from "./task-metadata.js"; export interface SessionScopedTask { id: number; title: string; description?: string; status: string; priority: string; type: string; progress?: number; current_status?: string; createdAt: string; updatedAt: string; tags: string[]; project_path?: string; parent_task_id?: number; context?: TaskContextValue; goals_and_expected_deliverables?: string; } export type TaskFetcher = (id: number) => Promise; export interface BuildSessionForestOptions { sessionStartedAt: string; maxAncestors?: number; /** * The CLI list source. Receives a `sinceIso` hint; the contract is that * tasks with `createdAt < sinceIso` MUST be omitted, so the test * fixture that filters by the session start can rely on the input * being already filtered. */ listTasks: (opts?: { limit?: number; sinceIso?: string; }) => Promise; /** * v0.9.0+: Optional fetcher for external ancestors — tasks whose * `parent_task_id` chain leads outside the session. When omitted, the * forest is limited to in-session tasks. */ taskFetcher?: TaskFetcher; } export interface SessionForestNode { task: SessionScopedTask; children: SessionForestNode[]; } /** * v2.2.0+: Options for the session-scope forest build. When * `currentSessionTaskIds` is supplied (recommended), the forest is * scoped to exactly those task ids — the plugin's hook handlers * populate this set in-memory when each new task is created. Pre- * existing / legacy tasks that the user has not touched in this * session are filtered out, even if their `createdAt` happens to fall * after `sessionStartedAt` (e.g. when the host CLI is restarted and * the clock skews). * * When omitted, `buildSessionForest` falls back to the v0.9.0 time- * based filter (`createdAt >= sessionStartedAt`) for backwards * compatibility with older callers and tests that pre-date v2.2.0. */ export interface BuildSessionForestRuntimeOptions { currentSessionTaskIds?: number[]; } export declare class TaskSessionStore { private readonly opts; private latestLeafId; /** * v2.2.0+: in-memory set of task ids created during this session. * Populated by the plugin's `task:before.create` / `task:after.create` * hook handlers via `recordSessionTask`. The home page filters * against this set so the user only sees tasks they touched in this * session plus their ancestor chain — never the entire pre-existing * corpus. */ private readonly sessionTaskIds; constructor(opts: BuildSessionForestOptions); /** * Returns the id of the most recently recorded leaf task in this session, * or undefined if no task has been recorded yet. The v0.9.0 home page * highlights this task with a `data-leaf="1"` attribute. */ getLatestLeafId(): number | undefined; /** * Record a leaf task id (called by the host plugin as new tasks appear). * Idempotent — only the most recent call wins. */ recordLeaf(taskId: number): void; /** * v2.2.0+: Record a task id created during this session. Called from * the plugin's `task:before.create` / `task:after.create` hook * handlers. Idempotent — re-recording the same id is a no-op. * * This is the authoritative source of "what tasks belong to the * current session" — more accurate than the v0.9.0 time-based * filter because it survives clock skew, host restarts, and tasks * created seconds before the plugin loaded. */ recordSessionTask(taskId: number): void; /** * v2.2.0+: Return a snapshot of all task ids the plugin has observed * being created in this session. The home page passes this list to * `buildSessionForest({ currentSessionTaskIds })` so the union tree * only includes session-touched tasks and their ancestors. */ getSessionTaskIds(): number[]; /** * v2.2.0+: Drop all recorded session task ids. Intended for tests * that want to reset state between scenarios; production code should * never call this. */ clearSessionTaskIds(): void; buildSessionForest(runtimeOpts?: BuildSessionForestRuntimeOptions): Promise; } export type { TaskTreeNodeTask, TaskTreeNode }; export declare function renderSessionForestPage(args: { forest: SessionForestNode[]; leafTaskId?: number; }): string; //# sourceMappingURL=task-session-store.d.ts.map