// tools/package-handoff.ts — Handoff context packager tool (SPEC-039)
import { specStore, knowledgeStore } from '../storage/index.js';
import { checkSpecReadiness } from '../engine/readiness-checker.js';
import { packageHandoff } from '../engine/handoff-packager.js';
import { detectParadigms } from '../engine/paradigm-detector.js';
import { analyzeContextPreflight, buildTokenWasteReport, formatTokenWasteReport, loadTokenWastePolicy, recommendRelevantTools, toolsFromPolicyGroups, } from '../engine/token-optimizer/index.js';
import { appendTransitionEvent } from '../storage/transition-log.js';
import { formatProjectGraphContext, queryProjectGraphSlice, } from '../engine/project-graph/index.js';
// ── Formatting helpers ───────────────────────────────────────────────────────
function formatHandoff(pkg) {
    const lines = [];
    lines.push(`# Implementation Handoff Package — ${pkg.specId}`);
    lines.push('');
    lines.push(`Generated: ${pkg.generatedAt}`);
    lines.push(`Readiness Score: ${pkg.readinessScore}/100`);
    if (pkg.handoffPath) {
        lines.push(`Handoff Path: ${pkg.handoffPath}`);
    }
    if (pkg.contextHash) {
        lines.push(`Context Hash: ${pkg.contextHash}`);
    }
    lines.push(`Blocked: ${pkg.blocked ? 'yes' : 'no'}`);
    lines.push('');
    lines.push('## Objective');
    lines.push('');
    lines.push(pkg.objective);
    lines.push('');
    lines.push('## Acceptance Criteria');
    lines.push('');
    if (pkg.criteria.length > 0) {
        for (const criterion of pkg.criteria) {
            lines.push(`- [ ] ${criterion}`);
        }
    }
    else {
        lines.push('_(No criteria found — check spec.md acceptance criteria)_');
    }
    lines.push('');
    lines.push('## Files to Modify');
    lines.push('');
    if (pkg.filesToModify.length > 0) {
        for (const f of pkg.filesToModify) {
            lines.push(`- ${f}`);
        }
    }
    else {
        lines.push('_(No files identified — check spec.md ## Technical / ## Files)_');
    }
    lines.push('');
    lines.push('## Files to Create');
    lines.push('');
    if (pkg.filesToCreate.length > 0) {
        for (const f of pkg.filesToCreate) {
            lines.push(`- ${f}`);
        }
    }
    else {
        lines.push('_(None identified)_');
    }
    lines.push('');
    lines.push('## Ownership');
    lines.push('');
    if (pkg.ownership.length > 0) {
        for (const item of pkg.ownership) {
            lines.push(`- ${item}`);
        }
    }
    else {
        lines.push('_(Missing ownership — handoff is blocked)_');
    }
    lines.push('');
    lines.push('## Test Plan');
    lines.push('');
    if (pkg.testPlan.length > 0) {
        for (const item of pkg.testPlan) {
            lines.push(`- ${item}`);
        }
    }
    else {
        lines.push('_(Missing test plan — handoff is blocked)_');
    }
    lines.push('');
    lines.push('## Risks');
    lines.push('');
    if (pkg.risks.length > 0) {
        for (const item of pkg.risks) {
            lines.push(`- ${item}`);
        }
    }
    else {
        lines.push('_(Missing risk analysis — handoff is blocked)_');
    }
    lines.push('');
    lines.push('## OUT OF SCOPE');
    lines.push('');
    lines.push('**The following must NOT be implemented:**');
    lines.push('');
    for (const item of pkg.outOfScope) {
        lines.push(`- ${item}`);
    }
    lines.push('');
    if (pkg.constraints.length > 0) {
        lines.push('## Hard Constraints');
        lines.push('');
        for (const constraint of pkg.constraints) {
            lines.push(`- [${constraint.type.toUpperCase()}] ${constraint.description}`);
            if (constraint.affectedItems.length > 0) {
                lines.push(`  Affects: ${constraint.affectedItems.join(', ')}`);
            }
        }
        lines.push('');
    }
    if (pkg.warnings.length > 0) {
        lines.push('## Warnings');
        lines.push('');
        for (const warning of pkg.warnings) {
            lines.push(`- WARNING: ${warning}`);
        }
        lines.push('');
    }
    lines.push('## Current State');
    lines.push('');
    lines.push(pkg.currentState);
    lines.push('');
    lines.push('## Next Action');
    lines.push('');
    lines.push(pkg.nextAction);
    lines.push('');
    if (pkg.blockers.length > 0) {
        lines.push('## Blockers');
        lines.push('');
        for (const blocker of pkg.blockers) {
            lines.push(`- ${blocker}`);
        }
        lines.push('');
    }
    return lines.join('\n');
}
async function buildHandoffTokenWasteReport(pkg, knowledge, spec) {
    try {
        const { policy } = await loadTokenWastePolicy(knowledge.projectPath);
        if (!policy.enabled) {
            return null;
        }
        const context = analyzeContextPreflight({
            action: 'package_handoff',
            policy,
            candidates: [...pkg.filesToModify, ...pkg.filesToCreate].map((path) => ({
                path,
                reason: 'Referenced by handoff package.',
            })),
            spec: {
                id: spec.id,
                risk: spec.risk,
                target: spec.target,
            },
        });
        const tools = recommendRelevantTools({
            action: 'package_handoff',
            intentSignals: ['handoff', spec.scope ?? '', spec.target ?? ''].filter(Boolean),
            tools: toolsFromPolicyGroups(policy),
            policy,
        });
        return buildTokenWasteReport({
            action: 'package_handoff',
            policy,
            context,
            tools,
            spec: {
                id: spec.id,
                risk: spec.risk,
                scope: spec.scope,
            },
        });
    }
    catch {
        return null;
    }
}
async function buildGraphContextSection(args) {
    if (args.projectPath === undefined) {
        return null;
    }
    try {
        const slice = await queryProjectGraphSlice({
            projectId: args.projectId,
            projectPath: args.projectPath,
            specId: args.specId,
        });
        if (slice === null || slice.nodes.length === 0) {
            return null;
        }
        return { text: await formatProjectGraphContext(slice), structured: slice };
    }
    catch {
        return null;
    }
}
// ── Handler ──────────────────────────────────────────────────────────────────
export async function handlePackageHandoff(args) {
    const { projectId, specId } = args;
    const spec = await specStore.getSpec(projectId, specId);
    if (!spec) {
        return {
            content: [
                {
                    type: 'text',
                    text: `Spec '${specId}' not found in project '${projectId}'`,
                },
            ],
            isError: true,
        };
    }
    const knowledge = await knowledgeStore.getKnowledge(projectId);
    if (!knowledge) {
        return {
            content: [
                {
                    type: 'text',
                    text: `Project '${projectId}' not found. Run init_project first.`,
                },
            ],
            isError: true,
        };
    }
    // Run readiness check to populate score
    const readinessReport = await checkSpecReadiness(spec, 'lenient');
    const pkg = await packageHandoff(spec, knowledge);
    // SPEC-035b: Inject paradigm constraint when project path is available
    const paradigmConstraints = pkg.constraints.slice();
    if (knowledge.projectPath) {
        try {
            const paradigmReport = await detectParadigms(knowledge.projectPath);
            const dominant = paradigmReport.dominant;
            if (dominant && dominant.confidence >= 0.5) {
                paradigmConstraints.push({
                    type: 'interface',
                    description: `Follow ${dominant.name} paradigm patterns — dominant paradigm (confidence: ${(dominant.confidence * 100).toFixed(0)}%)`,
                    affectedItems: ['all new code'],
                });
            }
        }
        catch {
            // Paradigm detection is best-effort — never block handoff
        }
    }
    // Inject readiness score
    const pkgWithScore = {
        ...pkg,
        readinessScore: readinessReport.score,
        constraints: paradigmConstraints,
    };
    const tokenWasteReport = await buildHandoffTokenWasteReport(pkgWithScore, knowledge, spec);
    const graphContext = await buildGraphContextSection({
        projectId,
        projectPath: knowledge.projectPath,
        specId,
    });
    const handoffText = graphContext !== null
        ? `${formatHandoff(pkgWithScore)}\n${graphContext.text}`
        : formatHandoff(pkgWithScore);
    const formatted = tokenWasteReport !== null
        ? `${handoffText}\n${formatTokenWasteReport(tokenWasteReport)}`
        : handoffText;
    void appendTransitionEvent({
        projectId,
        specId,
        eventType: 'handoff.intake',
        gateResults: { handoff: pkgWithScore.blocked ? 'fail' : 'pass' },
        meta: {
            handoffPath: pkgWithScore.handoffPath,
            contextHash: pkgWithScore.contextHash,
            blockers: pkgWithScore.blockers,
        },
    }).catch(() => {
        /* best-effort — handoff rendering should not fail because telemetry failed */
    });
    return {
        content: [{ type: 'text', text: formatted }],
        structuredContent: {
            blocked: pkgWithScore.blocked,
            blockers: pkgWithScore.blockers,
            handoffPath: pkgWithScore.handoffPath,
            contextHash: pkgWithScore.contextHash,
            ...(tokenWasteReport !== null ? { tokenWaste: tokenWasteReport } : {}),
            ...(graphContext !== null ? { graphContext: graphContext.structured } : {}),
        },
    };
}
//# sourceMappingURL=package-handoff.js.map