/**
 * Increment Number Management Utility
 *
 * Provides centralized utilities for managing increment numbers across
 * all SpecWeave directories (main, _archive, _abandoned, _paused).
 *
 * Prevents increment number reuse when increments are moved to subdirectories.
 *
 * CRITICAL FIX (v0.30.21): Removed cache entirely to prevent duplicate IDs.
 * The cache was premature optimization that caused bugs. Scanning 4 directories
 * is fast enough (~5ms) and doesn't need caching.
 *
 * PLATFORM SUFFIX CONVENTION (v0.32.0, extended v1.0.272):
 * Increments imported from external tools use platform-specific suffixes:
 *   G = GitHub, J = JIRA, A = Azure DevOps, E = Legacy/generic external
 * Example: 0111G-feature-name (from GitHub), 0111J-feature-name (from JIRA)
 * All suffixed variants share the same base number namespace.
 *
 * @module increment-utils
 * @since 0.18.3
 */
import { type PlatformSuffix, type Platform } from '../../sync/types.js';
/**
 * Recognized lifecycle sub-folders under .specweave/increments/
 * Any underscore-prefixed folder not in this list is considered invalid.
 */
export declare const RECOGNIZED_LIFECYCLE_FOLDERS: readonly ["_archive", "_abandoned", "_paused", "_backlog"];
export type LifecycleFolder = typeof RECOGNIZED_LIFECYCLE_FOLDERS[number];
/**
 * Centralized manager for increment number generation and validation.
 *
 * Scans ALL increment directories to ensure sequential numbering and
 * prevent duplicate increment IDs.
 *
 * @example
 * ```typescript
 * // Get next increment number
 * const nextId = IncrementNumberManager.getNextIncrementNumber();
 * console.log(nextId); // "0033"
 *
 * // Check if increment exists
 * const exists = IncrementNumberManager.incrementNumberExists("0032");
 * console.log(exists); // true
 * ```
 */
export declare class IncrementNumberManager {
    /**
     * Derive directories to scan from RECOGNIZED_LIFECYCLE_FOLDERS.
     * Single source of truth — all scan methods use this.
     *
     * @param incrementsDir - Path to .specweave/increments directory
     * @returns Array of { path, label } for active dir + all lifecycle folders
     * @private
     * @since 1.0.400
     */
    private static getDirsToScan;
    /**
     * Get the next available increment number across all directories.
     *
     * SEQUENTIAL STRATEGY (v1.0.x+):
     * - Returns highest existing number + 1
     * - Gaps in numbering are preserved (not backfilled)
     * - Simpler and more predictable than gap-filling
     *
     * ALWAYS performs fresh filesystem scan to guarantee unique IDs.
     * No caching - simplicity over premature optimization.
     *
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @param _useCache - DEPRECATED: ignored, always scans fresh (kept for API compatibility)
     * @returns Next increment number as 4-digit string (e.g., "0033")
     *
     * @example
     * ```typescript
     * // If increments [0001, 0002, 0004, 0005] exist:
     * const nextId = IncrementNumberManager.getNextIncrementNumber();
     * // "0006" - sequential, skips gap
     *
     * // If increments [0001, 0002, 0003] exist:
     * const nextId = IncrementNumberManager.getNextIncrementNumber();
     * // "0004" - sequential
     * ```
     */
    static getNextIncrementNumber(projectRoot?: string, _useCache?: boolean): string;
    /**
     * Get the next available increment number that won't collide in the target project's feature ID space.
     *
     * PER-PROJECT COLLISION PREVENTION (v1.0.19+):
     * - First gets candidate from global increment pool (sequential max+1)
     * - Then checks if that number would collide with existing FS-IDs in the target project
     * - If collision (FS-XXX or FS-XXXE exists), finds next available number
     *
     * This prevents the scenario where:
     * - Project ec-web-ui has external import FS-001E
     * - User creates internal increment 0001-feature → would derive to FS-001
     * - But FS-001 collides with FS-001E (same base number in unified sequence)
     *
     * @param projectRoot - Project root directory
     * @param projectId - Target project ID (from spec.md **Project**: field or config)
     * @param options - Additional options
     * @param options.isExternal - If true, checks for external collision (FS-XXXE)
     * @returns Next increment number as 4-digit string that won't collide in the project
     *
     * @example
     * ```typescript
     * // Project 'ec-web-ui' has FS-001E (from external import)
     * const nextId = IncrementNumberManager.getNextIncrementNumberForProject(
     *   process.cwd(),
     *   'ec-web-ui'
     * );
     * // Returns "0002" (skips 0001 because FS-001E exists)
     * ```
     *
     * @since 1.0.19
     */
    static getNextIncrementNumberForProject(projectRoot: string, projectId: string, options?: {
        isExternal?: boolean;
    }): string;
    /**
     * Check if an increment number already exists in any directory.
     *
     * Scans all directories to determine if the given increment number
     * has already been used. Normalizes 3-digit IDs to 4-digit for comparison.
     *
     * @param incrementNumber - Increment number to check (string or number)
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @returns true if increment exists, false otherwise
     *
     * @example
     * ```typescript
     * IncrementNumberManager.incrementNumberExists("0032"); // true
     * IncrementNumberManager.incrementNumberExists(32);     // true
     * IncrementNumberManager.incrementNumberExists("9999"); // false
     * ```
     */
    static incrementNumberExists(incrementNumber: string | number, projectRoot?: string): boolean;
    /**
     * Reserved names that CANNOT be used as increment IDs.
     * These names are reserved for SpecWeave internal use and would cause
     * structural violations if used as increment names.
     *
     * @since 1.0.105
     * @private
     */
    private static readonly RESERVED_INCREMENT_NAMES;
    /**
     * Get all existing increment numbers across all directories.
     *
     * CRITICAL COLLISION PREVENTION (v1.0.42):
     * Both internal (0001-xxx) and external (0001E-xxx) increments share
     * the SAME numeric namespace. This function extracts the BASE number
     * from both variants to ensure:
     * - If 0001E-external exists → 0001-internal is BLOCKED (returns 0002)
     * - If 0001-internal exists → 0001E-external is BLOCKED (returns 0002E)
     *
     * RESERVED NAME VALIDATION (v1.0.105):
     * Folders using reserved names like "reports", "backup", "temp" are
     * REJECTED and logged as errors. This prevents pollution of the
     * increments directory with folders that should not exist there.
     *
     * Returns a Set of all increment numbers found in:
     * 1. .specweave/increments/ (main)
     * 2. .specweave/increments/_archive/
     * 3. .specweave/increments/_abandoned/
     * 4. .specweave/increments/_paused/
     *
     * @param incrementsDir - Path to .specweave/increments directory
     * @returns Set of BASE increment numbers (e.g., Set([1, 2, 4, 5]))
     *          Note: Both 0001-xxx and 0001E-xxx contribute "1" to this set
     * @private
     * @since 0.33.1
     */
    private static getAllIncrementNumbers;
    /**
     * Generate an increment ID for external items.
     *
     * External increments (those working on imported GitHub/JIRA/ADO items)
     * use E suffix to maintain consistency with FS-XXXE and US-XXXE conventions.
     *
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @returns Next increment ID with E suffix (e.g., "0033E")
     *
     * @example
     * ```typescript
     * const id = IncrementNumberManager.getNextExternalIncrementNumber();
     * // "0033E" - for use as "0033E-feature-name"
     * ```
     *
     * @since 0.32.0
     */
    static getNextExternalIncrementNumber(projectRoot?: string): string;
    /**
     * Generate an increment number with platform-specific suffix.
     *
     * PLATFORM SUFFIX CONVENTION (v1.0.272):
     * - G = GitHub, J = JIRA, A = Azure DevOps
     * - Falls back to E for unknown platforms
     *
     * @param projectRoot - Project root directory
     * @param platform - Source platform ('github' | 'jira' | 'ado')
     * @returns Next increment number with platform suffix (e.g., "0033G")
     *
     * @example
     * ```typescript
     * const id = IncrementNumberManager.getNextPlatformIncrementNumber(cwd, 'github');
     * // "0033G" - for use as "0033G-feature-name"
     * ```
     *
     * @since 1.0.272
     */
    static getNextPlatformIncrementNumber(projectRoot: string | undefined, platform: Platform): string;
    /**
     * Validate that an increment number is valid (must be >= 0001, never 0000).
     *
     * CRITICAL VALIDATION (v1.0.104):
     * Increment numbers MUST start from 0001. 0000 is PERMANENTLY FORBIDDEN.
     * This prevents structural violations and invalid increment creation.
     *
     * @param number - Increment number to validate (4-digit string)
     * @throws Error if number is 0000
     *
     * @example
     * ```typescript
     * IncrementNumberManager.validateIncrementNumber('0001'); // OK
     * IncrementNumberManager.validateIncrementNumber('0042'); // OK
     * IncrementNumberManager.validateIncrementNumber('0000'); // THROWS ERROR
     * ```
     *
     * @since 1.0.104
     * @private
     */
    private static validateIncrementNumber;
    /**
     * Validate that an increment name is not a reserved keyword.
     *
     * CRITICAL VALIDATION (v1.0.105):
     * Increment names CANNOT use reserved keywords like "reports", "backup", "temp".
     * These names are reserved for SpecWeave internal use and would cause
     * structural violations if used as increment names.
     *
     * @param name - Increment name to validate (kebab-case)
     * @throws Error if name is reserved
     *
     * @example
     * ```typescript
     * IncrementNumberManager.validateIncrementName('my-feature'); // OK
     * IncrementNumberManager.validateIncrementName('reports');    // THROWS ERROR
     * IncrementNumberManager.validateIncrementName('backup');     // THROWS ERROR
     * ```
     *
     * @since 1.0.105
     * @private
     */
    private static validateIncrementName;
    /**
     * Generate a full increment folder name.
     *
     * @param name - Kebab-case increment name (e.g., "dora-metrics-fix")
     * @param options - Options for ID generation
     * @param options.isExternal - If true, adds E suffix for external items
     * @param options.projectRoot - Project root directory
     * @param options.projectId - Target project ID for per-project collision prevention (v1.0.19+)
     * @param options.skipValidation - If true, skips uniqueness validation (DANGEROUS - use only for testing)
     * @returns Full increment folder name (e.g., "0033E-dora-metrics-fix")
     *
     * @example
     * ```typescript
     * // Internal increment
     * const id = IncrementNumberManager.generateIncrementId('feature-name');
     * // "0033-feature-name"
     *
     * // External increment (GitHub/JIRA/ADO item)
     * const extId = IncrementNumberManager.generateIncrementId('dora-fix', { isExternal: true });
     * // "0033E-dora-fix"
     *
     * // With per-project collision prevention (v1.0.19+)
     * // If project 'ec-web-ui' has FS-001E, this returns "0002-feature" instead of "0001-feature"
     * const safeId = IncrementNumberManager.generateIncrementId('feature', { projectId: 'ec-web-ui' });
     * ```
     *
     * @since 0.32.0
     */
    static generateIncrementId(name: string, options?: {
        isExternal?: boolean;
        platformSuffix?: PlatformSuffix;
        projectRoot?: string;
        projectId?: string;
        skipValidation?: boolean;
    }): string;
    /**
     * Validate that a manually-specified increment ID is unique.
     *
     * CRITICAL: Use this when creating increments with explicit IDs (e.g., from splits).
     * The ID format "0141-feature-name" will be validated against all existing increments.
     *
     * @param incrementId - Full increment ID to validate (e.g., "0141-feature-name")
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @throws Error if increment number already exists
     *
     * @example
     * ```typescript
     * // Before creating increment folder with explicit ID:
     * IncrementNumberManager.validateExplicitId('0141-my-feature');
     * // Throws if 0141 already exists!
     * ```
     *
     * @since 0.34.0
     */
    static validateExplicitId(incrementId: string, projectRoot?: string): void;
    /**
     * Check if an increment ID represents an external item.
     *
     * External increments have E suffix: 0033E-name
     * Internal increments do not: 0033-name
     *
     * @param incrementId - Increment ID or folder name
     * @returns true if increment is external (has E suffix)
     *
     * @example
     * ```typescript
     * IncrementNumberManager.isExternalIncrement('0033E-dora-fix'); // true
     * IncrementNumberManager.isExternalIncrement('0033-feature');   // false
     * ```
     *
     * @since 0.32.0
     */
    static isExternalIncrement(incrementId: string): boolean;
    /**
     * Extract the numeric part from an increment ID.
     *
     * Works with both internal and external increments.
     *
     * @param incrementId - Increment ID or folder name
     * @returns Numeric part as 4-digit string, or null if invalid
     *
     * @example
     * ```typescript
     * IncrementNumberManager.extractNumber('0033E-dora-fix'); // "0033"
     * IncrementNumberManager.extractNumber('0033-feature');   // "0033"
     * IncrementNumberManager.extractNumber('invalid');        // null
     * ```
     *
     * @since 0.32.0
     */
    static extractNumber(incrementId: string): string | null;
    /**
     * Find all existing increments with a given number (detects duplicates).
     *
     * Returns all folder names that share the same base number.
     * E.g., for "0121" returns both "0121-feature-a" and "0121E-feature-b".
     *
     * IMPORTANT: 0001 and 0001E are considered the SAME base number!
     *
     * @param incrementNumber - Increment number to search for (string or number)
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @returns Array of folder names with the same base number
     *
     * @example
     * ```typescript
     * const duplicates = IncrementNumberManager.findDuplicates("0121");
     * // ["0121-ado-jira-feature", "0121-intelligent-living-docs"]
     * ```
     *
     * @since 0.33.0
     */
    static findDuplicates(incrementNumber: string | number, projectRoot?: string): string[];
    /**
     * Find existing increments with the same name suffix in active and _backlog dirs.
     *
     * Only scans active (main) and _backlog directories — archived and abandoned
     * increments are excluded since reusing their names is acceptable.
     *
     * @param nameSuffix - The kebab-case name to search for (e.g., "user-auth")
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @returns Array of matching increment folder names (e.g., ["0010-user-auth"])
     *
     * @example
     * ```typescript
     * const dupes = IncrementNumberManager.findNameDuplicates('user-auth');
     * // ["0010-user-auth"] if active increment exists with that name
     * ```
     *
     * @since 1.0.400
     */
    static findNameDuplicates(nameSuffix: string, projectRoot?: string): string[];
    /**
     * Validate that an increment ID is unique before creation.
     *
     * Throws an error if the number already exists (including E-suffix variants).
     * Use this method to validate BEFORE creating increment directories.
     *
     * @param incrementId - Full increment ID to validate (e.g., "0121-feature-name")
     * @param projectRoot - Project root directory (defaults to process.cwd())
     * @throws Error if increment number already exists
     *
     * @example
     * ```typescript
     * // Safe increment creation
     * const id = IncrementNumberManager.generateIncrementId('my-feature');
     * IncrementNumberManager.validateUnique(id); // throws if duplicate
     * fs.mkdirSync(path.join(incrementsDir, id));
     * ```
     *
     * @since 0.33.0
     */
    static validateUnique(incrementId: string, projectRoot?: string): void;
    /**
     * Generate a guaranteed-unique increment ID with validation.
     *
     * NOTE: As of v0.34.0, generateIncrementId() also validates by default.
     * This method is kept for explicit clarity when uniqueness is critical.
     *
     * @param name - Kebab-case increment name
     * @param options - Generation options
     * @returns Validated unique increment ID
     * @throws Error if validation fails (should never happen with fresh scan)
     *
     * @example
     * ```typescript
     * const id = IncrementNumberManager.generateUniqueIncrementId('my-feature');
     * // Guaranteed unique, safe to create directory
     * ```
     *
     * @since 0.33.0
     */
    static generateUniqueIncrementId(name: string, options?: {
        isExternal?: boolean;
        projectRoot?: string;
    }): string;
    /**
     * Create an increment folder safely with full validation.
     *
     * This is the RECOMMENDED way to create new increments programmatically.
     * It validates uniqueness and creates all necessary files atomically.
     *
     * @param name - Kebab-case increment name
     * @param options - Creation options
     * @returns Created increment ID
     * @throws Error if increment number already exists
     *
     * @example
     * ```typescript
     * // For normal increments:
     * const id = await IncrementNumberManager.createIncrement('my-feature', {
     *   projectRoot: '/path/to/project'
     * });
     *
     * // For split increments, use explicit ID with validation:
     * IncrementNumberManager.validateExplicitId('0145-split-part1');
     * // Then create folder manually only if validation passes
     * ```
     *
     * @since 0.34.0
     */
    static createIncrementId(name: string, options?: {
        isExternal?: boolean;
        projectRoot?: string;
    }): string;
}
//# sourceMappingURL=increment-utils.d.ts.map