// Copyright (c) 2026 Hellmai Ltd
// SPDX-License-Identifier: AGPL-3.0-only
/**
 * WU-1650: Apply/edit operations for wu:edit command
 *
 * Extracted from wu-edit.ts to dedicated module.
 * All field-application, merge, and write operations live here.
 */
import { die } from '@lumenflow/core/error-handler';
import { createGitForPath } from '@lumenflow/core/git-adapter';
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { parseYAML, stringifyYAML, readWU } from '@lumenflow/core/wu-yaml';
import { WU_PATHS, getStateStoreDirFromBacklog } from '@lumenflow/core/wu-paths';
import { generateBacklog } from '@lumenflow/core/backlog-generator';
import { WUStateStore } from '@lumenflow/core/wu-state-store';
import { FILE_SYSTEM, LOG_PREFIX, COMMIT_FORMATS, PKG_MANAGER, SCRIPTS, PRETTIER_FLAGS, READINESS_UI, LUMENFLOW_PATHS, WU_STATUS, } from '@lumenflow/core/wu-constants';
import { validateLaneFormat } from '@lumenflow/core/lane-checker';
// WU-1442: Import date normalization to fix date corruption from js-yaml
import { normalizeToDateString } from '@lumenflow/core/date-utils';
// WU-1929: Import initiative-related modules for bidirectional initiative updates
import { INIT_PATHS } from '@lumenflow/initiatives/paths';
import { readInitiative, writeInitiative } from '@lumenflow/initiatives/yaml';
import { validateSpecCompleteness } from '@lumenflow/core/wu-done-validators';
import { execSync } from 'node:child_process';
import { validateInitiativeFormat, validateInitiativeExists, validateExposureValue, } from './wu-edit-validators.js';
const PREFIX = LOG_PREFIX.EDIT;
/**
 * WU-1039: Apply exposure edit to WU object
 *
 * Returns a new WU object with updated exposure (immutable pattern).
 *
 * @param wu - Original WU object
 * @param exposure - New exposure value
 * @returns Updated WU object (does not mutate original)
 */
export function applyExposureEdit(wu, exposure) {
    return {
        ...wu,
        exposure,
    };
}
/**
 * WU-1929: Update initiative wus: arrays bidirectionally
 *
 * When a WU's initiative field changes, this function:
 * 1. Removes the WU ID from the old initiative's wus: array (if exists)
 * 2. Adds the WU ID to the new initiative's wus: array
 *
 * @param worktreePath - Path to the worktree (for file operations)
 * @param wuId - WU ID being updated
 * @param oldInitId - Previous initiative ID (may be undefined)
 * @param newInitId - New initiative ID
 * @returns Array of relative file paths that were modified
 */
export function updateInitiativeWusArrays(worktreePath, wuId, oldInitId, newInitId) {
    const modifiedFiles = [];
    // Remove from old initiative if it exists and is different from new
    if (oldInitId && oldInitId !== newInitId) {
        const oldInitPath = join(worktreePath, INIT_PATHS.INITIATIVE(oldInitId));
        if (existsSync(oldInitPath)) {
            try {
                const oldInit = readInitiative(oldInitPath, oldInitId);
                if (Array.isArray(oldInit.wus) && oldInit.wus.includes(wuId)) {
                    oldInit.wus = oldInit.wus.filter((id) => id !== wuId);
                    writeInitiative(oldInitPath, oldInit);
                    modifiedFiles.push(INIT_PATHS.INITIATIVE(oldInitId));
                    console.log(`${PREFIX} Removed ${wuId} from ${oldInitId} wus: array`);
                }
            }
            catch (err) {
                // Old initiative may not exist or be invalid - log warning but continue
                const message = err instanceof Error ? err.message : String(err);
                console.warn(`${PREFIX} Could not update old initiative ${oldInitId}: ${message}`);
            }
        }
    }
    // Add to new initiative
    const newInitPath = join(worktreePath, INIT_PATHS.INITIATIVE(newInitId));
    if (existsSync(newInitPath)) {
        try {
            const newInit = readInitiative(newInitPath, newInitId);
            if (!Array.isArray(newInit.wus)) {
                newInit.wus = [];
            }
            if (!newInit.wus.includes(wuId)) {
                newInit.wus.push(wuId);
                writeInitiative(newInitPath, newInit);
                modifiedFiles.push(INIT_PATHS.INITIATIVE(newInitId));
                console.log(`${PREFIX} Added ${wuId} to ${newInitId} wus: array`);
            }
        }
        catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            die(`Failed to update new initiative ${newInitId}: ${message}`);
        }
    }
    return modifiedFiles;
}
/**
 * Normalize date fields in WU object to prevent date corruption
 *
 * WU-1442: js-yaml parses unquoted YYYY-MM-DD dates as Date objects.
 * When yaml.dump() serializes them back, it outputs ISO timestamps.
 * This function normalizes Date objects back to YYYY-MM-DD strings.
 */
export function normalizeWUDates(wu) {
    if (wu.created !== undefined) {
        wu.created = normalizeToDateString(wu.created);
    }
    return wu;
}
/**
 * Merge array values: replace by default, append if --append flag is set (WU-1388)
 */
export function mergeArrayField(existing, newValues, shouldAppend) {
    if (!shouldAppend) {
        return newValues;
    }
    const existingArray = Array.isArray(existing) ? existing : [];
    return [...existingArray, ...newValues];
}
/**
 * WU-1144: Merge string field values with append-by-default behavior
 *
 * Notes and acceptance criteria should append by default (preserving original),
 * with explicit --replace-notes and --replace-acceptance flags for overwrite.
 */
export function mergeStringField(existing, newValue, shouldReplace) {
    // If replace mode or no existing value, just use new value
    if (shouldReplace || !existing || existing.trim() === '') {
        return newValue;
    }
    // Append with double newline separator
    return `${existing}\n\n${newValue}`;
}
function normalizeRepoPath(pathValue) {
    return pathValue.replaceAll('\\', '/').replace(/^\.\/+/, '');
}
export function buildWuEditStampNote(wuRelativePath) {
    return `[wu:edit] path=${normalizeRepoPath(wuRelativePath)}`;
}
export async function appendWuEditStampEvent(worktreePath, wuId, wuRelativePath) {
    const stateDir = join(worktreePath, LUMENFLOW_PATHS.STATE_DIR);
    const store = new WUStateStore(stateDir);
    await store.load();
    await store.checkpoint(wuId, buildWuEditStampNote(wuRelativePath), {
        progress: 'wu:edit stamp',
        nextSteps: 'pre-commit enforcement',
    });
    return LUMENFLOW_PATHS.WU_EVENTS;
}
/**
 * WU-1594: Ensure wu:edit commits always include regenerated backlog projection.
 */
export function getWuEditCommitFiles(id, extraFiles = []) {
    return [...new Set([WU_PATHS.WU(id), ...extraFiles, WU_PATHS.BACKLOG()])];
}
/**
 * WU-1594: Regenerate backlog.md from state store after wu:edit updates.
 */
export async function regenerateBacklogFromState(backlogPath) {
    const stateDir = getStateStoreDirFromBacklog(backlogPath);
    const store = new WUStateStore(stateDir);
    await store.load();
    const content = await generateBacklog(store);
    writeFileSync(backlogPath, content, { encoding: FILE_SYSTEM.ENCODING });
}
function truncateReadinessLine(text, boxWidth, truncationSuffix) {
    const maxContentLength = Math.max(0, boxWidth - 1);
    if (text.length <= maxContentLength) {
        return text;
    }
    const sliceLength = Math.max(0, maxContentLength - truncationSuffix.length);
    return `${text.slice(0, sliceLength)}${truncationSuffix}`;
}
export function buildReadinessSummaryContent(wuDoc, id) {
    const { valid, errors } = validateSpecCompleteness(wuDoc, id);
    const status = typeof wuDoc.status === 'string' ? wuDoc.status : WU_STATUS.READY;
    if (status === WU_STATUS.READY) {
        if (valid) {
            return {
                headline: READINESS_UI.MESSAGES.READY_YES,
                command: `Run: pnpm wu:claim --id ${id}`,
            };
        }
        return {
            headline: READINESS_UI.MESSAGES.READY_NO,
            details: [READINESS_UI.MESSAGES.MISSING_HEADER],
            command: `Run: pnpm wu:edit --id ${id} --help`,
            errors,
        };
    }
    if (status === WU_STATUS.IN_PROGRESS) {
        return {
            headline: '✅ Already claimed: YES',
            details: ['Current status: in_progress'],
            command: `Next: pnpm wu:prep --id ${id}`,
        };
    }
    return {
        headline: `ℹ️  WU status: ${status}`,
        details: [valid ? 'Spec complete: YES' : 'Spec complete: NO'],
        command: `Run: pnpm wu:status --id ${id}`,
        errors: valid ? [] : errors,
    };
}
function printReadinessSummaryLine(text, boxWidth, box, truncationSuffix) {
    const content = truncateReadinessLine(text, boxWidth, truncationSuffix);
    console.log(`${box.VERTICAL} ${content}${''.padEnd(Math.max(0, boxWidth - content.length - 1))}${box.VERTICAL}`);
}
function printReadinessSummaryEmptyLine(boxWidth, box) {
    console.log(`${box.VERTICAL}${''.padEnd(boxWidth)}${box.VERTICAL}`);
}
/**
 * Runtime fields set by wu:claim that must be preserved during --spec-file edits.
 * These fields are required for subsequent wu:edit, wu:prep, and wu:done operations.
 *
 * WU-2239: Without preserving these fields, --spec-file silently overwrites them,
 * causing a chicken-and-egg problem where subsequent wu:edit calls fail because
 * worktree_path is gone.
 */
const PRESERVED_RUNTIME_FIELDS = [
    'id',
    'status',
    'worktree_path',
    'assigned_to',
    'claimed_mode',
    'session_id',
    'claimed_at',
];
/**
 * Load spec file and merge with original WU (preserving runtime fields).
 *
 * WU-2239: Preserves runtime fields (worktree_path, assigned_to, claimed_mode,
 * session_id, claimed_at) in addition to id and status from the original WU.
 * If the spec file explicitly provides a runtime field, the spec file value
 * takes precedence (except id and status which are always from the original).
 */
function loadSpecFile(specPath, originalWU) {
    const resolvedPath = resolve(specPath);
    if (!existsSync(resolvedPath)) {
        die(`Spec file not found: ${resolvedPath}`);
    }
    const specContent = readFileSync(resolvedPath, {
        encoding: FILE_SYSTEM.ENCODING,
    });
    const newSpec = parseYAML(specContent);
    // WU-2239: Build a defaults object from original runtime fields.
    // Spec file values override runtime defaults when explicitly provided,
    // except id and status which are always preserved from the original.
    const runtimeDefaults = {};
    for (const field of PRESERVED_RUNTIME_FIELDS) {
        if (originalWU[field] !== undefined) {
            runtimeDefaults[field] = originalWU[field];
        }
    }
    return {
        ...runtimeDefaults, // Runtime fields as defaults
        ...newSpec, // Spec file content overrides defaults
        id: originalWU.id, // id is always from original (cannot be changed)
        status: originalWU.status, // status is always from original (cannot be changed)
    };
}
const RENAME_DELIMITER = '=';
function normalizeRepeatableEntries(rawValues, splitOnComma) {
    if (Array.isArray(rawValues)) {
        return splitOnComma
            ? rawValues
                .flatMap((value) => value.split(','))
                .map((value) => value.trim())
                .filter(Boolean)
            : rawValues.map((value) => value.trim()).filter(Boolean);
    }
    return splitOnComma
        ? rawValues
            .split(',')
            .map((value) => value.trim())
            .filter(Boolean)
        : [rawValues.trim()].filter(Boolean);
}
function parseRenameEntries(rawValues, optionName) {
    return normalizeRepeatableEntries(rawValues, false).map((entry) => {
        const delimiterIndex = entry.indexOf(RENAME_DELIMITER);
        if (delimiterIndex <= 0 || delimiterIndex === entry.length - 1) {
            die(`Invalid ${optionName} mapping: "${entry}"\n\nExpected format: old${RENAME_DELIMITER}new`);
        }
        const from = entry.slice(0, delimiterIndex).trim();
        const to = entry.slice(delimiterIndex + 1).trim();
        if (!from || !to) {
            die(`Invalid ${optionName} mapping: "${entry}"\n\nExpected format: old${RENAME_DELIMITER}new`);
        }
        return { from, to };
    });
}
function applyArrayRemoveAndRename(currentValues, options) {
    let nextValues = [...currentValues];
    if (options.removeValues) {
        const removed = new Set(normalizeRepeatableEntries(options.removeValues, options.removeSplitOnComma));
        nextValues = nextValues.filter((value) => !removed.has(value));
    }
    if (options.renameValues) {
        const renameMap = new Map(parseRenameEntries(options.renameValues, options.renameOptionName).map(({ from, to }) => [
            from,
            to,
        ]));
        nextValues = nextValues.map((value) => renameMap.get(value) ?? value);
    }
    return nextValues;
}
/**
 * Apply edits to WU YAML
 * Returns the updated WU object
 */
// eslint-disable-next-line sonarjs/cognitive-complexity -- Pre-existing complexity, refactor tracked separately
export function applyEdits(wu, opts) {
    // Full spec replacement from file
    if (opts.specFile) {
        return loadSpecFile(opts.specFile, wu);
    }
    const updated = { ...wu };
    // Field-level updates
    // WU-2423: Handle --title
    if (opts.title) {
        updated.title = opts.title;
    }
    if (opts.description) {
        updated.description = opts.description;
    }
    // WU-1144: Handle --acceptance with append-by-default behavior
    // Appends to existing acceptance criteria unless --replace-acceptance is set
    if (opts.acceptance && opts.acceptance.length > 0) {
        // Invert the logic: append by default, replace with --replace-acceptance
        const shouldAppend = !opts.replaceAcceptance;
        updated.acceptance = mergeArrayField(wu.acceptance, opts.acceptance, shouldAppend);
    }
    // WU-1144: Handle --notes with append-by-default behavior
    // Appends to existing notes unless --replace-notes is set
    if (opts.notes) {
        const existingNotes = typeof wu.notes === 'string' ? wu.notes : undefined;
        updated.notes = mergeStringField(existingNotes, opts.notes, opts.replaceNotes ?? false);
    }
    // WU-1456: Handle lane reassignment
    if (opts.lane) {
        validateLaneFormat(opts.lane);
        updated.lane = opts.lane;
    }
    // WU-1620: Handle type and priority updates
    if (opts.type) {
        updated.type = opts.type;
    }
    if (opts.priority) {
        updated.priority = opts.priority;
    }
    // WU-1929: Handle initiative and phase updates
    // Note: Initiative bidirectional updates (initiative wus: arrays) are handled separately
    // in the main function after applyEdits, since they require file I/O
    if (opts.initiative) {
        validateInitiativeFormat(opts.initiative);
        validateInitiativeExists(opts.initiative);
        updated.initiative = opts.initiative;
    }
    if (opts.phase !== undefined) {
        const phaseNum = typeof opts.phase === 'number' ? opts.phase : parseInt(opts.phase, 10);
        if (isNaN(phaseNum) || phaseNum < 1) {
            die(`Invalid phase number: "${opts.phase}"\n\nPhase must be a positive integer (e.g., 1, 2, 3)`);
        }
        updated.phase = phaseNum;
    }
    // Handle repeatable --code-paths flags (WU-1225: append by default, replace with --replace-code-paths)
    // WU-1816: Split comma-separated string into array (same pattern as test paths)
    // WU-1870: Fix to split comma-separated values WITHIN array elements (Commander passes ['a,b'] not 'a,b')
    const hasCodePathEdits = Boolean(opts.codePaths && opts.codePaths.length > 0) ||
        Boolean(opts.removeCodePaths && opts.removeCodePaths.length > 0) ||
        Boolean(opts.renameCodePaths && opts.renameCodePaths.length > 0);
    if (hasCodePathEdits) {
        let nextCodePaths = Array.isArray(wu.code_paths) ? [...wu.code_paths] : [];
        if (opts.codePaths && opts.codePaths.length > 0) {
            const codePaths = normalizeRepeatableEntries(opts.codePaths, true);
            const shouldAppend = !opts.replaceCodePaths || Boolean(opts.append);
            nextCodePaths = mergeArrayField(wu.code_paths, codePaths, shouldAppend);
        }
        updated.code_paths = applyArrayRemoveAndRename(nextCodePaths, {
            removeValues: opts.removeCodePaths,
            renameValues: opts.renameCodePaths,
            removeSplitOnComma: true,
            renameOptionName: '--rename-code-paths',
        });
    }
    // WU-1225: Handle repeatable --risks flags (append by default, replace with --replace-risks)
    // WU-2381: Risks are free-text descriptions — do NOT split on commas
    if (opts.risks && opts.risks.length > 0) {
        const rawRisks = opts.risks;
        const risks = Array.isArray(rawRisks)
            ? rawRisks.map((risk) => risk.trim()).filter(Boolean)
            : [rawRisks.trim()].filter(Boolean);
        // WU-1225: Invert logic - append by default
        const shouldAppend = !opts.replaceRisks || Boolean(opts.append);
        updated.risks = mergeArrayField(wu.risks, risks, shouldAppend);
    }
    // WU-1390: Handle test path flags (DRY refactor)
    // WU-1225: Test paths now append by default (consistent with --acceptance and --code-paths)
    // WU-2369: Added --replace-test-paths-* flags for parity with other --replace-* flags
    // WU-2381: manual is free-text (no comma split); unit/e2e are file paths (comma split OK)
    const testPathMappings = [
        {
            optKey: 'testPathsManual',
            replaceKey: 'replaceTestPathsManual',
            field: 'manual',
            freeText: true,
        },
        { optKey: 'testPathsUnit', replaceKey: 'replaceTestPathsUnit', field: 'unit', freeText: false },
        { optKey: 'testPathsE2e', replaceKey: 'replaceTestPathsE2e', field: 'e2e', freeText: false },
    ];
    for (const { optKey, replaceKey, field, freeText } of testPathMappings) {
        const rawPaths = opts[optKey];
        const removeKey = `removeTestPaths${field.charAt(0).toUpperCase()}${field.slice(1)}`;
        const renameKey = `renameTestPaths${field.charAt(0).toUpperCase()}${field.slice(1)}`;
        const rawRemovePaths = opts[removeKey];
        const rawRenamePaths = opts[renameKey];
        if ((rawPaths && (typeof rawPaths === 'string' || rawPaths.length > 0)) ||
            (rawRemovePaths && (typeof rawRemovePaths === 'string' || rawRemovePaths.length > 0)) ||
            (rawRenamePaths && (typeof rawRenamePaths === 'string' || rawRenamePaths.length > 0))) {
            const existingTests = typeof updated.tests === 'object' && updated.tests !== null
                ? updated.tests
                : {};
            updated.tests = existingTests;
            const shouldAppend = !opts[replaceKey];
            const wuTests = typeof wu.tests === 'object' && wu.tests !== null
                ? wu.tests
                : {};
            let nextPaths = Array.isArray(wuTests[field]) ? [...wuTests[field]] : [];
            if (rawPaths && (typeof rawPaths === 'string' || rawPaths.length > 0)) {
                const paths = normalizeRepeatableEntries(rawPaths, !freeText);
                nextPaths = mergeArrayField(wuTests[field], paths, shouldAppend);
            }
            existingTests[field] = applyArrayRemoveAndRename(nextPaths, {
                removeValues: rawRemovePaths,
                renameValues: rawRenamePaths,
                removeSplitOnComma: !freeText,
                renameOptionName: `--rename-test-paths-${field}`,
            });
        }
    }
    // WU-2564: Handle --blocked-by flag
    // WU-1225: Append by default, replace with --replace-blocked-by
    if (opts.blockedBy) {
        const rawBlockedBy = opts.blockedBy;
        const blockedByIds = rawBlockedBy
            .split(',')
            .map((id) => id.trim())
            .filter(Boolean);
        const shouldAppend = !opts.replaceBlockedBy || Boolean(opts.append);
        updated.blocked_by = mergeArrayField(wu.blocked_by, blockedByIds, shouldAppend);
    }
    // WU-2564: Handle --add-dep flag
    // WU-1225: Append by default, replace with --replace-dependencies
    if (opts.addDep) {
        const rawAddDep = opts.addDep;
        const depIds = rawAddDep
            .split(',')
            .map((id) => id.trim())
            .filter(Boolean);
        const shouldAppend = !opts.replaceDependencies || Boolean(opts.append);
        updated.dependencies = mergeArrayField(wu.dependencies, depIds, shouldAppend);
    }
    // WU-1039: Handle --exposure flag with validation
    if (opts.exposure) {
        const exposureResult = validateExposureValue(opts.exposure);
        if (!exposureResult.valid) {
            die(exposureResult.error ?? 'Invalid exposure value');
        }
        updated.exposure = opts.exposure;
    }
    // WU-1683: Handle --plan flag (simple scalar replacement)
    if (opts.plan) {
        updated.plan = opts.plan;
    }
    return updated;
}
export async function applyEditsInWorktree({ worktreePath, id, updatedWU }) {
    const wuPath = join(worktreePath, WU_PATHS.WU(id));
    // WU-1442: Normalize dates before dumping to prevent ISO timestamp corruption
    normalizeWUDates(updatedWU);
    // Emergency fix Session 2: Use centralized stringifyYAML helper
    const yamlContent = stringifyYAML(updatedWU);
    writeFileSync(wuPath, yamlContent, { encoding: FILE_SYSTEM.ENCODING });
    console.log(`${PREFIX} Updated ${id}.yaml in worktree`);
    const wuEventsRelativePath = await appendWuEditStampEvent(worktreePath, id, WU_PATHS.WU(id));
    const wuEventsAbsolutePath = join(worktreePath, wuEventsRelativePath);
    console.log(`${PREFIX} Appended wu:edit stamp event for ${id}`);
    // Format the file
    try {
        execSync(`${PKG_MANAGER} ${SCRIPTS.PRETTIER} ${PRETTIER_FLAGS.WRITE} "${wuPath}"`, {
            cwd: worktreePath,
            encoding: FILE_SYSTEM.ENCODING,
            stdio: 'pipe',
        });
        console.log(`${PREFIX} Formatted ${id}.yaml`);
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        console.warn(`${PREFIX} Could not format file: ${message}`);
    }
    // Stage and commit using git adapter (library-first)
    const commitMsg = COMMIT_FORMATS.SPEC_UPDATE(id);
    try {
        const gitAdapter = createGitForPath(worktreePath);
        await gitAdapter.add([wuPath, wuEventsAbsolutePath]);
        await gitAdapter.commit(commitMsg);
        console.log(`${PREFIX} Committed: ${commitMsg}`);
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        die(`Failed to commit edit in worktree.\n\n` +
            `Error: ${message}\n\n` +
            `The WU file was updated but could not be committed.\n` +
            `You may need to commit manually in the worktree.`);
    }
}
/**
 * WU-1620: Display readiness summary after edit
 *
 * Shows whether WU is ready for wu:claim based on spec completeness.
 * Non-blocking - just informational to help agents understand what's missing.
 */
export function displayReadinessSummary(id) {
    try {
        const wuPath = WU_PATHS.WU(id);
        const wuDoc = readWU(wuPath, id);
        const summary = buildReadinessSummaryContent(wuDoc, id);
        const { BOX, BOX_WIDTH, ERROR_MAX_LENGTH, ERROR_TRUNCATE_LENGTH, TRUNCATION_SUFFIX } = READINESS_UI;
        console.log(`\n${BOX.TOP_LEFT}${BOX.HORIZONTAL.repeat(BOX_WIDTH)}${BOX.TOP_RIGHT}`);
        printReadinessSummaryLine(summary.headline, BOX_WIDTH, BOX, TRUNCATION_SUFFIX);
        if (summary.details && summary.details.length > 0) {
            for (const detail of summary.details) {
                printReadinessSummaryLine(detail, BOX_WIDTH, BOX, TRUNCATION_SUFFIX);
            }
        }
        if (summary.errors && summary.errors.length > 0) {
            for (const error of summary.errors) {
                const truncated = error.length > ERROR_MAX_LENGTH
                    ? `${error.substring(0, ERROR_TRUNCATE_LENGTH)}${TRUNCATION_SUFFIX}`
                    : error;
                printReadinessSummaryLine(`${READINESS_UI.MESSAGES.BULLET} ${truncated}`, BOX_WIDTH, BOX, TRUNCATION_SUFFIX);
            }
        }
        printReadinessSummaryEmptyLine(BOX_WIDTH, BOX);
        printReadinessSummaryLine(summary.command, BOX_WIDTH, BOX, TRUNCATION_SUFFIX);
        console.log(`${BOX.BOTTOM_LEFT}${BOX.HORIZONTAL.repeat(BOX_WIDTH)}${BOX.BOTTOM_RIGHT}`);
    }
    catch (err) {
        // Non-blocking - if validation fails, just warn
        const message = err instanceof Error ? err.message : String(err);
        console.warn(`${PREFIX} Could not validate readiness: ${message}`);
    }
}
//# sourceMappingURL=wu-edit-operations.js.map