/** * Task hierarchy tree building — buildTaskTree and related helpers. * @task T10064 * @epic T9834 */ import type { Task, TaskPriority } from '@cleocode/contracts'; /** Task record shape expected from the data layer — alias for the contracts Task type. */ type TaskRecord = Task; /** Tree node representation for task hierarchy. */ export interface FlatTreeNode { /** Unique task identifier (e.g. "T001"). */ id: string; /** Human-readable task title. */ title: string; /** Current task status (e.g. "pending", "done"). */ status: string; /** * Task type classification. * @defaultValue "task" */ type?: string; /** Child nodes in the hierarchy tree. */ children: FlatTreeNode[]; /** * Task priority level. * * Sourced directly from the task record's `priority` field. * @defaultValue "medium" */ priority: TaskPriority; /** * Direct dependency IDs for this task. * * Reflects the raw `depends` array from the task record. Empty array when * the task has no declared dependencies. */ depends: string[]; /** * Open (unresolved) dependency IDs that are currently blocking this task. * * A dependency is considered open when its status is not `"done"` or * `"cancelled"`. Empty when all dependencies are resolved. */ blockedBy: string[]; /** * Whether this task is immediately actionable. * * `true` when `blockedBy` is empty AND `status` is `"pending"` or * `"active"`. `false` for tasks that are done, cancelled, archived, or * blocked by open dependencies. */ ready: boolean; /** * Full transitive blocker chain for this task. * * Contains every open dependency reachable by walking the `depends` graph * upstream from this task (deduplicated, cycle-safe). Only populated when * `withBlockers` is requested at tree-build time. * * @see {@link getTransitiveBlockers} */ blockerChain?: string[]; /** * Leaf-level blockers — the root-cause tasks that must be resolved first. * * A subset of `blockerChain` containing only those tasks whose own * dependencies are all resolved (or that have no dependencies). Resolving * these tasks is the minimal set of work needed to make progress. Only * populated when `withBlockers` is requested at tree-build time. * * @see {@link getLeafBlockers} */ leafBlockers?: string[]; } /** * Recursively build a tree node for a task, sorting children by position ASC. * * Children are sorted by their `position` field (null/undefined treated as 0) * using a stable comparison so equal positions preserve insertion order. * * In addition to the basic identity fields, each node is annotated with * dependency metadata derived from `allTasks`: * - `priority` — copied directly from the task record. * - `depends` — raw direct dependency IDs from the task record. * - `blockedBy` — subset of `depends` whose referenced tasks are not yet * done or cancelled (i.e. still open). * - `ready` — `true` when `blockedBy` is empty AND the task is in a * pending or active state. * - `blockerChain` — full transitive blocker chain (only when `allTasksFlat` * is provided, i.e. when `withBlockers` was requested). * - `leafBlockers` — terminal root-cause blockers (only when `allTasksFlat` * is provided). * * @param task - The task to build a node for. * @param childrenMap - Map of parentId to ordered child list. * @param taskMap - Flat lookup map of all tasks by ID, used to resolve * dependency status when computing `blockedBy`. * @param allTasksFlat - Full flat task array used for transitive blocker walks. * Pass only when `withBlockers` is true; omit otherwise * to skip the blocker-chain computation entirely. */ export declare function buildTreeNode(task: TaskRecord, childrenMap: Map, taskMap: Map, allTasksFlat?: TaskRecord[]): FlatTreeNode; /** * Recursively build upstream dependency nodes for a task. * * @param taskId - Starting task ID. * @param taskMap - Flat lookup map of all tasks by ID. * @param visited - Tracks visited nodes to avoid cycles. */ export declare function buildUpstreamTree(taskId: string, taskMap: Map, visited?: Set): FlatTreeNode[]; /** Count all nodes in a tree including children recursively. */ export declare function countNodes(nodes: FlatTreeNode[]): number; /** * Read hierarchy config limits from project config file. * * @param projectRoot - Absolute path to the CLEO project root directory. */ export declare function getHierarchyLimits(projectRoot: string): { maxDepth: number; maxSiblings: number; }; /** * Build hierarchy tree for tasks. * * @param projectRoot - Absolute path to the CLEO project root directory. * @param taskId - Optional root task ID; when provided, builds the subtree * rooted at this task. * @param withBlockers - When `true`, each node in the tree is annotated with * `blockerChain` (full transitive blocker IDs) and * `leafBlockers` (root-cause terminal blockers). The task * array is converted to a flat list **once** and passed to * every `buildTreeNode` call so the graph walk is not * repeated per-DB-query. * @returns The tree nodes and total node count. * * @remarks * When no taskId is given, returns all root-level tasks with their full subtrees. * When a taskId is given, returns that single task as the root with its descendants. * * @example * ```typescript * const { tree, totalNodes } = await coreTaskTree('/project', 'T042'); * console.log(`${totalNodes} nodes in subtree`); * ``` * * @example * ```typescript * // With transitive blocker chains * const { tree } = await coreTaskTree('/project', undefined, true); * const node = tree[0]; * console.log(node.blockerChain); // ['T010', 'T011'] * console.log(node.leafBlockers); // ['T011'] * ``` * * @task T4790 * @task T1206 */ export declare function coreTaskTree(projectRoot: string, taskId?: string, withBlockers?: boolean): Promise<{ tree: FlatTreeNode[]; totalNodes: number; }>; export {}; //# sourceMappingURL=task-tree.d.ts.map