/** * NEXUS filesystem project scanner. * * Walks filesystem roots looking for directories that contain a `.cleo/` * subdirectory, cross-references them against the nexus registry, and * optionally auto-registers unregistered projects. * * @task T1473 */ import { type EngineResult } from '../engine-result.js'; /** Auto-register error record. */ export interface ScanAutoRegisterError { /** Project path that failed to register. */ path: string; /** Error message. */ error: string; } /** Options for {@link scanForProjects}. */ export interface ProjectsScanOptions { /** * Comma-separated string or array of search roots. Default: the parent * directories of live registered projects ({@link listRegistryParentRoots}); * `~/code` and `~/projects` only when the registry yields none (T12476). */ roots?: string | string[]; /** Maximum directory traversal depth (default: 4, max: 20). */ maxDepth?: number; /** When true, register all discovered unregistered projects. */ autoRegister?: boolean; /** When true, also report already-registered projects. */ includeExisting?: boolean; } /** Result envelope for {@link scanForProjects}. */ export interface ProjectsScanResult { /** Search roots actually walked. */ roots: string[]; /** Unregistered project paths found. */ unregistered: string[]; /** Already-registered project paths (only populated when includeExisting). */ registered: string[]; /** Summary counts. */ tally: { total: number; unregistered: number; registered: number; }; /** Paths auto-registered (only when autoRegister). */ autoRegistered: string[]; /** Auto-register errors (only when autoRegister). */ autoRegisterErrors: ScanAutoRegisterError[]; } /** * Return the device number for a path, or -1 on error. * Used to detect filesystem boundary crossings. * * @param p - Absolute path to stat. * @returns Device number or -1. */ export declare function getDevice(p: string): number; /** * Walk a directory tree looking for directories named `.cleo/`. * Candidates are returned as absolute parent directory paths (the project root). * * Does NOT follow symlinks. Does NOT cross mount points (different `dev`). * * @param dir - Absolute directory path to walk. * @param depth - Current recursion depth (0 = root). * @param maxDepth - Maximum recursion depth. * @param rootDev - Device number of the search root for boundary checks. * @returns Array of absolute project-root paths that contain a `.cleo/` dir. * * @example * const projects = walkForCleo('/home/user/code', 0, 4, getDevice('/home/user/code')); */ export declare function walkForCleo(dir: string, depth: number, maxDepth: number, rootDev: number): string[]; /** Options for {@link walkForCleoBounded}. */ export interface BoundedWalkOptions { /** Maximum traversal depth below each root (0 = the root only). */ maxDepth: number; /** Directories read at once. */ concurrency: number; /** Per-directory read budget; a slower directory is reported, not waited on. */ timeoutMs: number; } /** Result of {@link walkForCleoBounded}. */ export interface BoundedWalkResult { /** Absolute project roots (directories containing `.cleo/`), sorted. */ found: string[]; /** Directories whose read exceeded the budget. */ timedOut: string[]; /** Directories that could not be read for a reason other than absence. */ unreadable: string[]; } /** * Settle `promise`, or `'timeout'` after `ms`. The timer never keeps the * process alive. The underlying operation is not cancelled — its result is * simply not waited for. * * @param promise - Operation to wait for. * @param ms - Budget in milliseconds. * @returns The settled value, or `'timeout'`. * * @example * ```ts * const entries = await withinBudget(readdir(dir), 2000); * ``` */ export declare function withinBudget(promise: Promise, ms: number): Promise; /** * Asynchronous {@link walkForCleo} for machine-wide scans (T12471): reads at * most `concurrency` directories at once and gives each read `timeoutMs`, so * one hung mount cannot stall a scan of hundreds of projects. Same rules as * the synchronous walker: no symlinks, no mount crossings, {@link SKIP_DIRS} * skipped. A timed-out or unreadable directory is reported, never treated as * empty proof of absence. * * @param roots - Absolute directories to walk. * @param opts - Depth, concurrency and per-directory budget. * @returns Project roots found, plus the directories that were not read. * * @example * ```ts * const { found } = await walkForCleoBounded(['/home/me/code'], { maxDepth: 2, concurrency: 16, timeoutMs: 2000 }); * ``` */ export declare function walkForCleoBounded(roots: readonly string[], opts: BoundedWalkOptions): Promise; /** * Walk filesystem roots to discover CLEO project directories. * * Searches for directories containing a `.cleo/` subdirectory, cross-references * them against the nexus registry, and optionally auto-registers the unregistered * ones. * * @param opts - Scan options. * @returns Scan result with discovered, registered, and auto-registered paths. * * @example * const result = await scanForProjects({ maxDepth: 3, autoRegister: false }); * console.log(result.unregistered); */ export declare function scanForProjects(opts?: ProjectsScanOptions): Promise; export declare function nexusProjectsScan(opts: { roots?: string; maxDepth?: number; autoRegister?: boolean; includeExisting?: boolean; }): Promise>; //# sourceMappingURL=projects-scan.d.ts.map