"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.navigationPlaceholderUpstreamField = navigationPlaceholderUpstreamField;
exports.discoverValidationLinksArtifacts = discoverValidationLinksArtifacts;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const output_1 = require("../output");
const cli_constants_1 = require("../config/cli-constants");
const paths_1 = require("../paths");
const planning_artifact_document_1 = require("./planning-artifact-document");
const planning_document_utils_1 = require("./planning-document-utils");
const structured_task_plan_1 = require("./structured-task-plan");
const task_lifecycle_1 = require("./task-lifecycle");
const NAVIGATION_PLACEHOLDER_FIELDS = new Map([
    ['{{slice_overview}}', 'upstream.slice_overview'],
    ['{{phase_overview}}', 'upstream.phase_overview'],
    ['{{milestone_overview}}', 'upstream.milestone_overview'],
]);
function navigationPlaceholderUpstreamField(value) {
    return NAVIGATION_PLACEHOLDER_FIELDS.get(value) ?? null;
}
const STRUCTURED_WORK_OVERVIEW_COVERAGE = {
    family: 'other',
    artifactType: 'work_overview',
    traceFields: [
        {
            field: 'upstream.specs',
            source: 'front-matter',
            requirement: 'required',
            valueShape: 'multi-spec-list',
            relationship: 'work-overview-to-specifications',
            notes: 'Preserves the Structured overview source-spec set without collapsing multi-spec provenance.',
        },
        {
            field: 'body.Task Plan',
            source: 'body-section',
            requirement: 'required',
            valueShape: 'body-reference-list',
            relationship: 'work-overview-to-task-definitions',
            materializationPolicy: 'markdown-link',
            notes: 'Declared direct Structured tasks resolve to canonical task-definition artifacts.',
        },
    ],
    unsupportedReferences: [
        'external URLs',
        'remote provider availability',
        'package registry identifiers',
        'free-form prose mentions',
    ],
};
function discoverValidationLinksArtifacts(options) {
    const artifactPath = options.artifactPath ?? null;
    const planningRootPath = normalizeDiscoveryRootPath(options.planningRootPath, '.day-shift/planning');
    const specIndexPath = normalizeDiscoveryRootPath(options.specIndexPath, cli_constants_1.CLI_SPEC_INDEX_PATH);
    const discoveryArtifacts = artifactPath === null
        ? discoverRepositoryArtifacts(options.repositoryRoot, {
            planningRootPath,
            specIndexPath,
        })
        : discoverFocusedArtifact(options.repositoryRoot, artifactPath);
    const evidence = discoveryArtifacts
        .filter((artifact) => artifact.parseStatus !== 'parsed')
        .map((artifact) => createDiscoveryEvidence(artifact));
    return {
        mode: artifactPath === null ? 'repository' : 'artifact',
        repositoryRoot: options.repositoryRoot,
        artifact: artifactPath,
        traversalBoundaries: output_1.TRACE_LINK_TRAVERSAL_BOUNDARIES,
        artifacts: discoveryArtifacts,
        evidence,
        summary: summarizeDiscovery(discoveryArtifacts, evidence),
    };
}
function discoverRepositoryArtifacts(repositoryRoot, roots) {
    const artifactPaths = [
        ...collectMarkdownArtifactPaths(repositoryRoot, '.day-shift/specs'),
        roots.specIndexPath,
        ...collectMarkdownArtifactPaths(repositoryRoot, roots.planningRootPath),
    ];
    return artifactPaths.flatMap((artifactPath) => discoverArtifactPath(repositoryRoot, artifactPath));
}
function discoverFocusedArtifact(repositoryRoot, artifactPath) {
    if (!isInsideTraversalBoundary(artifactPath)) {
        return discoverArtifactPath(repositoryRoot, artifactPath);
    }
    const absolutePath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, artifactPath);
    try {
        if (node_fs_1.default.existsSync(absolutePath) && node_fs_1.default.statSync(absolutePath).isDirectory()) {
            return collectMarkdownArtifactPaths(repositoryRoot, artifactPath).flatMap((candidatePath) => discoverArtifactPath(repositoryRoot, candidatePath));
        }
    }
    catch (error) {
        return [
            createUnsupportedArtifact({
                path: artifactPath,
                parseStatus: 'unreadable',
                parseMessage: error instanceof Error ? error.message : 'Artifact directory could not be read.',
            }),
        ];
    }
    return discoverArtifactPath(repositoryRoot, artifactPath);
}
function discoverArtifactPath(repositoryRoot, artifactPath) {
    if (!isInsideTraversalBoundary(artifactPath)) {
        return [
            createUnsupportedArtifact({
                path: artifactPath,
                parseStatus: 'outside-coverage',
                parseMessage: 'Artifact path is outside declared links-check traversal boundaries.',
            }),
        ];
    }
    const absolutePath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, artifactPath);
    if (!node_fs_1.default.existsSync(absolutePath)) {
        return [
            createUnsupportedArtifact({
                path: artifactPath,
                parseStatus: 'missing',
                parseMessage: 'Artifact path does not exist locally.',
            }),
        ];
    }
    if (artifactPath === cli_constants_1.CLI_SPEC_INDEX_PATH || artifactPath.endsWith('/index.json')) {
        return discoverSpecIndexEntries(absolutePath, artifactPath);
    }
    if (!artifactPath.endsWith('.md')) {
        return [
            createUnsupportedArtifact({
                path: artifactPath,
                parseStatus: 'unsupported',
                parseMessage: 'Artifact extension is outside links-check coverage.',
            }),
        ];
    }
    return [discoverMarkdownArtifact(repositoryRoot, absolutePath, artifactPath)];
}
function discoverMarkdownArtifact(repositoryRoot, absolutePath, artifactPath) {
    let markdownText;
    try {
        markdownText = node_fs_1.default.readFileSync(absolutePath, 'utf8');
    }
    catch (error) {
        return createUnsupportedArtifact({
            path: artifactPath,
            parseStatus: 'unreadable',
            parseMessage: error instanceof Error ? error.message : 'Artifact could not be read.',
        });
    }
    const document = (0, planning_artifact_document_1.parsePlanningArtifactDocument)(markdownText);
    if (!document.hasFrontMatter) {
        return createUnsupportedArtifact({
            path: artifactPath,
            parseStatus: 'malformed',
            parseMessage: 'Markdown artifact is missing closed YAML front matter.',
        });
    }
    const artifactType = document.frontMatterFields.artifact_type?.trim() ?? null;
    const coverage = findCoverageByArtifactType(artifactType);
    if (coverage === null) {
        return createUnsupportedArtifact({
            path: artifactPath,
            artifactType,
            parseStatus: 'unsupported',
            parseMessage: `Artifact type '${artifactType ?? '(missing)'}' is outside links-check coverage.`,
        });
    }
    const planningDepth = document.frontMatterFields.planning_depth?.trim() ?? null;
    const workflowLevel = document.frontMatterFields.workflow_level?.trim() ?? null;
    return {
        path: artifactPath,
        family: coverage.family,
        artifactType,
        parseStatus: 'parsed',
        parseMessage: 'Artifact parsed with declared trace-field coverage.',
        coverageSource: 'traceable-artifact-coverage',
        lifecycle: discoverMarkdownArtifactLifecycle(artifactType, document.frontMatterFields.status, markdownText),
        traceFields: coverage.traceFields
            .filter((field) => isTraceFieldApplicable({
            artifactType,
            planningDepth,
            workflowLevel,
            field,
        }))
            .map((field) => discoverTraceField(field, document.frontMatterLines, markdownText, repositoryRoot)),
    };
}
function isTraceFieldApplicable(options) {
    const taskArtifact = options.artifactType === 'task_definition' || options.artifactType === 'implementation_summary';
    if (taskArtifact && options.field.field === 'upstream.work_overview') {
        return options.workflowLevel === 'structured';
    }
    if (taskArtifact &&
        (options.field.field === 'upstream.slice_overview' ||
            options.field.field === 'upstream.phase_overview' ||
            options.field.field === 'upstream.milestone_overview') &&
        (options.workflowLevel === 'basic' || options.workflowLevel === 'structured')) {
        return false;
    }
    if (options.planningDepth === 'lightweight' &&
        taskArtifact &&
        (options.field.field === 'upstream.phase_overview' || options.field.field === 'upstream.milestone_overview')) {
        return false;
    }
    return true;
}
function discoverSpecIndexEntries(indexAbsolutePath, specIndexPath) {
    let indexText;
    try {
        indexText = node_fs_1.default.readFileSync(indexAbsolutePath, 'utf8');
    }
    catch (error) {
        return [
            createUnsupportedArtifact({
                path: specIndexPath,
                parseStatus: 'unreadable',
                parseMessage: error instanceof Error ? error.message : 'Spec index could not be read.',
            }),
        ];
    }
    let parsedIndex;
    try {
        parsedIndex = JSON.parse(indexText);
    }
    catch (error) {
        return [
            createUnsupportedArtifact({
                path: specIndexPath,
                parseStatus: 'malformed',
                parseMessage: error instanceof Error ? error.message : 'Spec index JSON is malformed.',
            }),
        ];
    }
    if (!isRecord(parsedIndex) || !Array.isArray(parsedIndex.specs)) {
        return [
            createUnsupportedArtifact({
                path: specIndexPath,
                parseStatus: 'malformed',
                parseMessage: 'Spec index JSON must contain a specs array.',
            }),
        ];
    }
    const coverage = findCoverageByFamily('spec_index_entry');
    if (coverage === null) {
        return [];
    }
    return parsedIndex.specs.map((entry, index) => {
        if (!isRecord(entry)) {
            return createUnsupportedArtifact({
                path: `${specIndexPath}#specs[${index}]`,
                parseStatus: 'malformed',
                parseMessage: 'Spec index entry must be a JSON object.',
            });
        }
        return {
            path: `${specIndexPath}#specs[${index}]`,
            family: 'spec_index_entry',
            artifactType: null,
            parseStatus: 'parsed',
            parseMessage: 'Spec index entry parsed with declared trace-field coverage.',
            coverageSource: 'traceable-artifact-coverage',
            lifecycle: discoverStatusLifecycle(readObjectPathValues(entry, 'status')[0]),
            traceFields: coverage.traceFields.map((field) => discoverSpecIndexTraceField(field, entry)),
        };
    });
}
function normalizeDiscoveryRootPath(input, fallback) {
    if (typeof input !== 'string') {
        return fallback;
    }
    const trimmed = input.trim();
    return trimmed === '' ? fallback : (0, paths_1.parseRepositoryRelativePath)(trimmed).normalizedPath;
}
function discoverTraceField(field, frontMatterLines, markdownText, repositoryRoot) {
    if (field.source === 'body-section') {
        const structuredTaskPlan = field.field === 'body.Task Plan'
            ? (0, structured_task_plan_1.parseStructuredTaskPlan)(markdownText)
            : null;
        const bodyReferenceOccurrences = structuredTaskPlan === null
            ? readBodySectionReferenceOccurrences(markdownText, field.field, repositoryRoot)
            : structuredTaskPlan.declarations.map((declaration) => declaration.occurrence);
        const values = uniqueValues(bodyReferenceOccurrences.map((occurrence) => occurrence.value));
        return {
            field: field.field,
            source: field.source,
            requirement: field.requirement,
            valueShape: field.valueShape,
            relationship: field.relationship,
            notes: field.notes,
            materializationPolicy: resolveMaterializationPolicy(field),
            missingTargetPolicy: resolveMissingTargetPolicy(field),
            present: values.length > 0,
            values,
            bodyReferenceOccurrences,
            ...(structuredTaskPlan === null
                ? {}
                : { structuredTaskDeclarations: structuredTaskPlan.declarations }),
        };
    }
    const values = readFrontMatterPathValues(frontMatterLines, field.field);
    const declaredSourceType = field.valueShape === 'source-reference' ? readFrontMatterPathValues(frontMatterLines, 'source.type')[0] : undefined;
    const sourceType = field.valueShape === 'source-reference' &&
        isLegacySourceList(frontMatterLines) &&
        declaredSourceType === 'markdown' &&
        typeof values[0] === 'string' &&
        isLegacyGeneratedMessageReference(values[0])
        ? 'message'
        : declaredSourceType;
    return {
        field: field.field,
        source: field.source,
        requirement: field.requirement,
        valueShape: field.valueShape,
        relationship: field.relationship,
        notes: field.notes,
        materializationPolicy: resolveMaterializationPolicy(field),
        missingTargetPolicy: resolveMissingTargetPolicy(field),
        ...(typeof sourceType === 'string' ? { sourceType } : {}),
        present: values.length > 0,
        values,
    };
}
function discoverSpecIndexTraceField(field, entry) {
    const values = readObjectPathValues(entry, field.field);
    const sourceType = field.valueShape === 'source-reference' ? readObjectPathValues(entry, 'source.type')[0] : undefined;
    return {
        field: field.field,
        source: field.source,
        requirement: field.requirement,
        valueShape: field.valueShape,
        relationship: field.relationship,
        notes: field.notes,
        materializationPolicy: resolveMaterializationPolicy(field),
        missingTargetPolicy: resolveMissingTargetPolicy(field),
        ...(typeof sourceType === 'string' ? { sourceType } : {}),
        present: values.length > 0,
        values,
    };
}
function resolveMaterializationPolicy(field) {
    if (field.materializationPolicy !== undefined)
        return field.materializationPolicy;
    return field.source === 'body-section' ? 'markdown-link' : 'trace-only';
}
function resolveMissingTargetPolicy(field) {
    if (field.missingTargetPolicy !== undefined)
        return field.missingTargetPolicy;
    return field.requirement === 'required' ? 'required' : 'advisory';
}
function readFrontMatterPathValues(frontMatterLines, fieldPath) {
    const parts = fieldPath.split('.');
    const value = readNestedFrontMatterValue(frontMatterLines, parts);
    if (value === undefined || value === null || value === '') {
        return [];
    }
    if (Array.isArray(value)) {
        return value;
    }
    return [value];
}
function readNestedFrontMatterValue(frontMatterLines, parts) {
    if (parts.length === 1) {
        return (0, planning_document_utils_1.readTopLevelField)(frontMatterLines, parts[0]);
    }
    if (parts[0] === 'upstream' && parts[1] === 'specs') {
        return readFrontMatterObjectList(frontMatterLines, 'upstream', 'specs');
    }
    if (parts[0] === 'upstream' && parts.length === 2) {
        return readNestedScalar(frontMatterLines, 'upstream', parts[1]);
    }
    if (parts[0] === 'source' && parts.length === 2) {
        return (readNestedScalar(frontMatterLines, 'source', parts[1]) ??
            readFirstNestedListScalar(frontMatterLines, 'source', parts[1]));
    }
    return undefined;
}
function isLegacyGeneratedMessageReference(value) {
    return /\s/u.test(value) && !value.endsWith('.md') && !value.includes('/') && !value.startsWith('.');
}
function isLegacySourceList(frontMatterLines) {
    const sourceIndex = frontMatterLines.indexOf('source:');
    return sourceIndex >= 0 && /^\s{2}-\s+/u.test(frontMatterLines[sourceIndex + 1] ?? '');
}
function readFirstNestedListScalar(frontMatterLines, parentKey, childKey) {
    let inParent = false;
    let inFirstItem = false;
    for (const line of frontMatterLines) {
        if (line === `${parentKey}:`) {
            inParent = true;
            continue;
        }
        if (!inParent)
            continue;
        if (/^[^\s]/u.test(line))
            break;
        const firstField = line.match(/^\s{2}-\s+([A-Za-z0-9_]+):\s*(.*)$/u);
        if (firstField !== null) {
            if (inFirstItem)
                break;
            inFirstItem = true;
            if (firstField[1] === childKey)
                return (0, planning_document_utils_1.parseScalar)(firstField[2]);
            continue;
        }
        if (!inFirstItem)
            continue;
        const nestedField = line.match(/^\s{4}([A-Za-z0-9_]+):\s*(.*)$/u);
        if (nestedField !== null && nestedField[1] === childKey) {
            return (0, planning_document_utils_1.parseScalar)(nestedField[2]);
        }
    }
    return undefined;
}
function readNestedScalar(frontMatterLines, parentKey, childKey) {
    let inParent = false;
    for (const line of frontMatterLines) {
        if (line === `${parentKey}:`) {
            inParent = true;
            continue;
        }
        if (!inParent) {
            continue;
        }
        if (/^[^\s]/.test(line)) {
            break;
        }
        const match = line.match(/^\s{2}([A-Za-z0-9_]+):\s*(.*)$/);
        if (match !== null && match[1] === childKey) {
            return (0, planning_document_utils_1.parseScalar)(match[2]);
        }
    }
    return undefined;
}
function readFrontMatterObjectList(frontMatterLines, parentKey, listKey) {
    let inParent = false;
    let inList = false;
    const values = [];
    let current = null;
    for (const line of frontMatterLines) {
        if (line === `${parentKey}:`) {
            inParent = true;
            continue;
        }
        if (!inParent) {
            continue;
        }
        if (/^[^\s]/.test(line)) {
            break;
        }
        if (line.match(new RegExp(`^\\s{2}${listKey}:\\s*$`)) !== null) {
            inList = true;
            continue;
        }
        if (!inList) {
            continue;
        }
        const itemStartMatch = line.match(/^\s{4}-\s+([A-Za-z0-9_]+):\s*(.*)$/);
        if (itemStartMatch !== null) {
            current = { [itemStartMatch[1]]: (0, planning_document_utils_1.parseScalar)(itemStartMatch[2]) };
            values.push(current);
            continue;
        }
        const itemFieldMatch = line.match(/^\s{6}([A-Za-z0-9_]+):\s*(.*)$/);
        if (itemFieldMatch !== null && current !== null) {
            current[itemFieldMatch[1]] = (0, planning_document_utils_1.parseScalar)(itemFieldMatch[2]);
        }
    }
    return values;
}
function readBodySectionReferenceOccurrences(markdownText, fieldPath, repositoryRoot) {
    const sectionName = fieldPath.replace(/^body\./, '');
    const section = extractSectionTextWithOffset(markdownText, sectionName);
    const sectionText = section.text;
    if (sectionText.trim() === '') {
        return [];
    }
    const references = [];
    if (isDeclaredChildSectionField(fieldPath)) {
        return readDeclaredChildReferenceOccurrences(markdownText, section, sectionName);
    }
    let inFence = false;
    let lineOffset = 0;
    for (const line of sectionText.split(/(?<=\n)/u)) {
        const lineWithoutEnding = line.replace(/\r?\n$/u, '');
        if (/^\s*(```|~~~)/u.test(lineWithoutEnding)) {
            inFence = !inFence;
            lineOffset += line.length;
            continue;
        }
        if (inFence) {
            lineOffset += line.length;
            continue;
        }
        const candidates = [];
        const markdownLinkPattern = /\[[^\]\n]*\]\(([^)\n]+)\)/gu;
        let linkMatch;
        while ((linkMatch = markdownLinkPattern.exec(lineWithoutEnding)) !== null) {
            const value = (linkMatch[1] ?? '').trim();
            candidates.push({
                value,
                rawText: linkMatch[0],
                format: 'plain',
                index: linkMatch.index,
            });
        }
        const bulletMatch = lineWithoutEnding.match(/^\s*-\s+(?:`([^`\n]+)`|([^\s`[\]<>]+))/u);
        if (bulletMatch !== null) {
            const value = (bulletMatch[1] ?? bulletMatch[2] ?? '').replace(/[,:;.]$/u, '').trim();
            const rawText = bulletMatch[1] === undefined ? (bulletMatch[2] ?? '') : `\`${bulletMatch[1]}\``;
            candidates.push({
                value,
                rawText,
                format: bulletMatch[1] === undefined ? 'plain' : 'backticked',
                index: lineWithoutEnding.indexOf(rawText),
            });
        }
        for (const candidate of candidates) {
            const supportedNavigationPlaceholder = fieldPath === 'body.Navigation' &&
                candidate.format === 'plain' &&
                navigationPlaceholderUpstreamField(candidate.value) !== null;
            if (candidate.value === '' ||
                (!supportedNavigationPlaceholder &&
                    (isGlobShapedReference(candidate.value) || !isPathLikeRepositoryReference(candidate.value, repositoryRoot)))) {
                continue;
            }
            const relativeStart = lineOffset + candidate.index;
            const startOffset = section.startOffset + relativeStart;
            const endOffset = startOffset + candidate.rawText.length;
            const location = offsetToLineColumn(markdownText, startOffset);
            references.push({
                value: candidate.value,
                rawText: candidate.rawText,
                sectionName,
                format: candidate.format,
                startOffset,
                endOffset,
                line: location.line,
                column: location.column,
                occurrenceIndex: references.length,
            });
        }
        lineOffset += line.length;
    }
    return references;
}
function isPathLikeRepositoryReference(value, repositoryRoot) {
    if (/\s/u.test(value) || isGlobShapedReference(value)) {
        return false;
    }
    if (isExplicitArtifactRelativeReference(value)) {
        return value !== './' && value !== '../';
    }
    try {
        const parsed = (0, paths_1.parseRepositoryRelativePath)(value);
        if (parsed.segments.length <= 1) {
            return false;
        }
        const firstSegment = parsed.segments[0];
        if (isKnownTraceRootSegment(firstSegment)) {
            return true;
        }
        const firstSegmentPath = node_path_1.default.join(repositoryRoot, firstSegment);
        return node_fs_1.default.existsSync(firstSegmentPath) && node_fs_1.default.statSync(firstSegmentPath).isDirectory();
    }
    catch {
        return false;
    }
}
function isExplicitArtifactRelativeReference(value) {
    const normalizedSeparators = value.replace(/\\/gu, '/');
    return normalizedSeparators.startsWith('./') || normalizedSeparators.startsWith('../');
}
function isGlobShapedReference(value) {
    return /[*?[\]{}]/u.test(value);
}
function isKnownTraceRootSegment(segment) {
    return segment === '.day-shift' || segment === 'src' || segment === 'tests' || segment === 'tests_v2';
}
function readDeclaredChildReferenceOccurrences(markdownText, section, sectionName) {
    const references = [];
    const referencePattern = /^(\s*-\s*)(?:`([^`\n]+)`|\[([^\]\n]+)\]\(([^)\n]+)\)|([a-z0-9]+(?:-[a-z0-9]+)*)(?=\s*(?::|$)))/gmu;
    let match;
    while ((match = referencePattern.exec(section.text)) !== null) {
        const value = (match[4] ?? match[2] ?? match[5] ?? '').trim();
        if (value === '' || isGlobShapedReference(value)) {
            continue;
        }
        const rawText = match[4] !== undefined
            ? `[${match[3] ?? ''}](${match[4]})`
            : match[2] !== undefined
                ? `\`${match[2]}\``
                : (match[5] ?? '');
        const relativeStart = match.index + (match[1]?.length ?? 0);
        const startOffset = section.startOffset + relativeStart;
        const endOffset = startOffset + rawText.length;
        const location = offsetToLineColumn(markdownText, startOffset);
        references.push({
            value,
            rawText,
            sectionName,
            format: match[2] !== undefined ? 'backticked' : 'plain',
            startOffset,
            endOffset,
            line: location.line,
            column: location.column,
            occurrenceIndex: references.length,
        });
    }
    return references;
}
function isDeclaredChildSectionField(fieldPath) {
    return (fieldPath === 'body.Phases' ||
        fieldPath === 'body.Milestones' ||
        fieldPath === 'body.Tasks' ||
        fieldPath === 'body.Task Plan');
}
function readObjectPathValues(record, fieldPath) {
    const value = fieldPath.split('.').reduce((current, key) => {
        if (!isRecord(current)) {
            return undefined;
        }
        return current[key];
    }, record);
    if (value === undefined || value === null || value === '') {
        return [];
    }
    return [value];
}
function collectMarkdownArtifactPaths(repositoryRoot, traversalRoot) {
    const absoluteRoot = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, traversalRoot);
    if (!node_fs_1.default.existsSync(absoluteRoot)) {
        return [];
    }
    const paths = [];
    const stack = [absoluteRoot];
    while (stack.length > 0) {
        const currentPath = stack.pop();
        if (currentPath === undefined) {
            continue;
        }
        let stats;
        try {
            stats = node_fs_1.default.statSync(currentPath);
        }
        catch {
            continue;
        }
        if (stats.isFile()) {
            if (currentPath.endsWith('.md')) {
                paths.push((0, planning_document_utils_1.toRepositoryLikePath)(node_path_1.default.relative(repositoryRoot, currentPath)));
            }
            continue;
        }
        if (!stats.isDirectory()) {
            continue;
        }
        for (const child of node_fs_1.default.readdirSync(currentPath)) {
            stack.push(node_path_1.default.join(currentPath, child));
        }
    }
    return paths.sort((left, right) => left.localeCompare(right));
}
function findCoverageByArtifactType(artifactType) {
    if (artifactType === null) {
        return null;
    }
    if (artifactType === 'work_overview') {
        return STRUCTURED_WORK_OVERVIEW_COVERAGE;
    }
    return (output_1.TRACEABLE_ARTIFACT_COVERAGE.find((entry) => 'artifactType' in entry && entry.artifactType === artifactType) ?? null);
}
function findCoverageByFamily(family) {
    return output_1.TRACEABLE_ARTIFACT_COVERAGE.find((entry) => entry.family === family) ?? null;
}
function createUnsupportedArtifact(options) {
    return {
        path: options.path,
        family: 'unsupported',
        artifactType: options.artifactType ?? null,
        parseStatus: options.parseStatus,
        parseMessage: options.parseMessage,
        coverageSource: 'outside-coverage',
        lifecycle: {
            status: null,
            terminal: false,
        },
        traceFields: [],
    };
}
function discoverMarkdownArtifactLifecycle(artifactType, topLevelStatus, markdownText) {
    if (artifactType === 'implementation_summary') {
        const projection = (0, task_lifecycle_1.projectImplementationSummaryLifecycle)(markdownText).value;
        const status = projection.currentAttempt?.implementationStatus ?? projection.legacyImplementationStatus ?? null;
        return {
            status,
            terminal: status === 'completed',
        };
    }
    return discoverStatusLifecycle(topLevelStatus);
}
function discoverStatusLifecycle(value) {
    const status = typeof value === 'string' && value.trim() !== '' ? value.trim().toLowerCase() : null;
    return {
        status,
        terminal: status === 'completed' || status === 'cancelled' || status === 'archived',
    };
}
function createDiscoveryEvidence(artifact) {
    return {
        path: artifact.path,
        status: artifact.parseStatus,
        message: artifact.parseMessage,
        family: artifact.family === 'unsupported' ? null : artifact.family,
        artifactType: artifact.artifactType,
        noWriteRequired: true,
    };
}
function summarizeDiscovery(artifacts, evidence) {
    return {
        artifactCount: artifacts.length,
        evidenceCount: evidence.length,
        parsedCount: countByStatus(artifacts, 'parsed'),
        unsupportedCount: countByStatus(artifacts, 'unsupported'),
        malformedCount: countByStatus(artifacts, 'malformed'),
        unreadableCount: countByStatus(artifacts, 'unreadable'),
        missingCount: countByStatus(artifacts, 'missing'),
        outsideCoverageCount: countByStatus(artifacts, 'outside-coverage'),
    };
}
function countByStatus(artifacts, status) {
    return artifacts.filter((artifact) => artifact.parseStatus === status).length;
}
function uniqueValues(values) {
    return [...new Set(values)];
}
function extractSectionTextWithOffset(markdownText, sectionName) {
    const section = (0, planning_artifact_document_1.parsePlanningArtifactDocument)(markdownText).sections.find((candidate) => candidate.heading === sectionName);
    if (section === undefined) {
        return {
            text: '',
            startOffset: 0,
        };
    }
    return {
        text: section.contentText,
        startOffset: section.contentRange.start.offset,
    };
}
function offsetToLineColumn(markdownText, offset) {
    const prefix = markdownText.slice(0, offset);
    const lines = prefix.split(/\r?\n/);
    return {
        line: lines.length,
        column: lines[lines.length - 1].length + 1,
    };
}
function isInsideTraversalBoundary(artifactPath) {
    let normalizedPath;
    try {
        normalizedPath = (0, paths_1.parseRepositoryRelativePath)(artifactPath).normalizedPath;
    }
    catch {
        return false;
    }
    return output_1.TRACE_LINK_TRAVERSAL_BOUNDARIES.some((boundary) => {
        if (normalizedPath === boundary) {
            return true;
        }
        if (boundary.endsWith('.json')) {
            return false;
        }
        return normalizedPath.startsWith(`${boundary}/`);
    });
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
