/**
 * 任务上下文管理器 — 管理任务的完整生命周期状态持久化。
 *
 * 核心职责:
 * - 创建/加载/保存任务上下文（JSON 文件存储）
 * - 管理状态机转换（classifying → expanding → executing → verifying → learning → done）
 * - 追踪执行结果（变更文件、失败记录）
 * - 修复循环追踪（能力 3: 自动修复尝试计数和复发检测）
 * - 返工历史追踪（能力 6: 返工次数阈值检查和阶段指令计算）
 * - 任务清理（过期任务和超量任务淘汰）
 *
 * 状态转换遵循 VALID_TRANSITIONS 严格定义的合法路径。
 */
import fs from "node:fs/promises";
import fss from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { scanTextSensitivity, redactSensitiveText } from "../../audit/privacy_secret_contract.js";
import { scanExpansionForPrivacy } from "./expansion_privacy.js";
import { cleanupStaleTasks } from "./cleanup.js";
import { AuditPool } from "../../audit/audit_pool.js";
import { DiffOwnershipStore } from "../diff_ownership_store.js";
import { ScopeLeaseStore } from "../scope_lease.js";
import { ConflictGate } from "../conflict_gate.js";
import { debug } from "../../core/logger.js";
import { migrateTaskContext } from "../../workflow/legacy_type_migration.js";
import { VALID_TRANSITIONS } from "./constants.js";
import { validateAndUpdateStatus } from "./status_transitions.js";
import { createSetterMethods } from "./manager_setters.js";
import { errorMessage, safeJsonParse } from "../../core/helpers.js";
export class TaskContextManager {
    stateDir;
    auditPool;
    diffOwnership;
    scopeLease;
    conflictGate;
    templatesDir;
    systemType;
    _setters;
    constructor(stateDir, options) {
        this.stateDir = stateDir;
        fss.mkdirSync(stateDir, { recursive: true });
        this.auditPool = new AuditPool(stateDir);
        this.diffOwnership = new DiffOwnershipStore(stateDir);
        this.scopeLease = new ScopeLeaseStore(stateDir);
        this.conflictGate = new ConflictGate(this.diffOwnership, this.scopeLease);
        this.templatesDir = options?.templatesDir;
        this.systemType = options?.systemType;
        this._setters = createSetterMethods(this.load.bind(this), this.save.bind(this));
    }
    /** 获取状态存储目录路径 */
    getStateDir() {
        return this.stateDir;
    }
    /** 获取审计池实例 */
    getAuditPool() {
        return this.auditPool;
    }
    /** 获取 Diff 归属追踪实例 */
    getDiffOwnership() {
        return this.diffOwnership;
    }
    /** 获取 Scope Lease 实例 */
    getScopeLease() {
        return this.scopeLease;
    }
    /** 获取冲突合并门实例 */
    getConflictGate() {
        return this.conflictGate;
    }
    /**
     * 创建新任务上下文，生成唯一 ID 并持久化到磁盘。
     */
    async create(intent, productProfile) {
        const taskId = `task-${crypto.randomUUID().slice(0, 8)}`;
        const ctx = {
            task_id: taskId,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString(),
            intent,
            product_profile: productProfile,
            status: "classifying",
        };
        // 隐私门禁: 扫描用户意图中的密钥/凭证信息
        const intentLabels = scanTextSensitivity(intent, "intent");
        const secretLabels = intentLabels.filter((l) => l.label === "secret" || l.label === "credential");
        if (secretLabels.length > 0) {
            throw new Error(`TaskContext.create 阻断: 用户意图包含禁止级别的敏感信息 (${secretLabels.map((l) => l.label).join(", ")}), 不允许保存`);
        }
        // PII/客户/生产数据: 保存前对意图进行脱敏处理
        const piiLabels = intentLabels.filter((l) => l.label === "pii" || l.label === "customer_data" || l.label === "production_data");
        if (piiLabels.length > 0) {
            const redacted = redactSensitiveText(intent, "intent");
            ctx.intent = redacted.redacted;
            ctx.sensitivity_labels = intentLabels;
            ctx.redaction_records = redacted.records;
        }
        await this.save(ctx);
        await this.writeCurrentPointer(taskId);
        debug("任务上下文", "创建任务 " + taskId);
        return ctx;
    }
    /**
     * 从磁盘加载任务上下文。
     */
    async load(taskId) {
        const filePath = this.taskFilePath(taskId);
        try {
            const data = await fs.readFile(filePath, "utf-8");
            const raw = safeJsonParse(data);
            if (!raw)
                return null;
            return migrateTaskContext(raw);
        }
        catch (e) {
            debug("任务上下文", "加载任务文件失败(预期行为: 文件不存在或解析错误) —", taskId, e);
            return null;
        }
    }
    /**
     * 持久化任务上下文到磁盘（先写临时文件再 rename，保证原子性）。
     */
    async save(ctx) {
        // problem-17: 保存前校验 StateFact 分区合规性
        const { validateStateFactPartition } = await import("../../state_fact_classifier.js");
        const violations = validateStateFactPartition(ctx);
        const hardFails = violations.filter(v => v.severity === "hard_fail");
        if (hardFails.length > 0) {
            const msgs = hardFails.map(v => v.message_zh).join("; ");
            throw new Error(`StateFact 分区违规: ${msgs}`);
        }
        const filePath = this.taskFilePath(ctx.task_id);
        ctx.updated_at = new Date().toISOString();
        // 原子写入: 使用任务级唯一 tmp 文件名，避免并发写同一个 .tmp
        const tmpPath = `${filePath}.${ctx.task_id}.tmp`;
        try {
            await fs.writeFile(tmpPath, JSON.stringify(ctx, null, 2));
            await fs.rename(tmpPath, filePath);
        }
        catch (e) {
            await fs.unlink(tmpPath).catch((e) => { debug("任务上下文", "清理文件失败", e); });
            throw e;
        }
    }
    /**
     * 更新任务状态，严格校验状态转换合法性。
     */
    async updateStatus(taskId, status, existingCtx) {
        const ctx = existingCtx ?? await this.load(taskId);
        if (!ctx)
            return null;
        // 委托给提取的验证和转换函数
        validateAndUpdateStatus(ctx, status, this.templatesDir, this.systemType);
        const prevStatus = ctx.status;
        ctx.status = status;
        await this.save(ctx);
        debug("任务上下文", "任务 " + taskId + " 状态转换 " + prevStatus + " → " + status);
        if (status === "executing") {
            // CAP-011: 进入执行阶段时自动从膨胀范围捕获 baseline
            const scopePaths = ctx.expansion?.scope?.allowed_paths;
            if (scopePaths && scopePaths.length > 0) {
                this.diffOwnership.captureBaselineFromScope(taskId, scopePaths);
                this.scopeLease.acquire(taskId, scopePaths);
            }
        }
        if (status === "done" || status === "failed") {
            if (status === "done") {
                this.auditPool.append({
                    task_id: ctx.task_id,
                    risk: (ctx.classification?.risk ?? "low"),
                    changed_files: ctx.execution?.changed_files ?? [],
                    evidence: ctx.classification?.strategy ?? "",
                    capability_refs: [],
                    created_at: new Date().toISOString(),
                });
            }
            // CAP-011: 终态时清理 Diff 归属和 Scope Lease
            this.diffOwnership.clearTask(taskId);
            this.scopeLease.release(taskId);
            await this.clearCurrentPointerIfMatches(taskId);
        }
        return ctx;
    }
    /**
     * 设置任务的分类结果。
     */
    async setClassification(taskId, result) {
        const ctx = await this.load(taskId);
        if (!ctx)
            return null;
        ctx.classification = result;
        if (result.route_decision) {
            ctx.route_decision = result.route_decision;
        }
        await this.save(ctx);
        return ctx;
    }
    /**
     * 设置任务的意图膨胀结果。
     */
    async setExpansion(taskId, result, existingCtx) {
        const ctx = existingCtx ?? await this.load(taskId);
        if (!ctx)
            return null;
        // 使用提取的隐私扫描函数处理膨胀结果
        const { result: scannedResult, allLabels, promptRedactionRecords } = scanExpansionForPrivacy(result);
        result = scannedResult;
        ctx.expansion = result;
        if (result.workflow_trace) {
            ctx.workflow_trace = result.workflow_trace;
        }
        ctx.ingestion_evidences = result.ingestion_evidences?.length ? result.ingestion_evidences : undefined;
        if (result.sensitivity_labels && result.sensitivity_labels.length > 0) {
            const existingLabels = ctx.sensitivity_labels ?? [];
            const all = [...existingLabels, ...result.sensitivity_labels, ...allLabels];
            ctx.sensitivity_labels = [...new Map(all.map((l) => [`${l.label}:${l.source_ref}`, l])).values()];
        }
        else if (allLabels.length > 0) {
            const existingLabels = ctx.sensitivity_labels ?? [];
            ctx.sensitivity_labels = [...existingLabels, ...allLabels];
        }
        const existingRecords = ctx.redaction_records ?? [];
        const resultRecords = result.redaction_records ?? [];
        const allRecords = [...existingRecords, ...resultRecords, ...promptRedactionRecords];
        ctx.redaction_records = allRecords.length > 0 ? allRecords : undefined;
        await this.save(ctx);
        return ctx;
    }
    /**
     * 记录执行结果: 变更文件列表和可选的失败记录。
     */
    async setExecution(taskId, changedFiles, failure) {
        const ctx = await this.load(taskId);
        if (!ctx)
            return null;
        if (!ctx.execution) {
            ctx.execution = {
                changed_files: [],
                attempt_count: 0,
                max_attempts: 3,
                failure_history: [],
            };
        }
        ctx.execution.changed_files = [
            ...new Set([...ctx.execution.changed_files, ...changedFiles]),
        ];
        if (failure) {
            ctx.execution.attempt_count++;
            ctx.execution.failure_history.push(failure);
        }
        for (const f of changedFiles) {
            this.diffOwnership.recordWrite(taskId, f);
        }
        await this.save(ctx);
        return ctx;
    }
    /**
     * 设置任务的验证结果。
     */
    async setVerification(taskId, result) {
        const ctx = await this.load(taskId);
        if (!ctx)
            return null;
        ctx.verification = result;
        await this.save(ctx);
        return ctx;
    }
    /**
     * 获取当前活跃任务。
     */
    async getCurrentTask() {
        try {
            const data = await fs.readFile(this.pointerPath, "utf-8");
            const { task_id } = safeJsonParse(data) ?? {};
            if (!task_id)
                return null;
            const ctx = await this.load(task_id);
            if (!ctx) {
                await this.clearCurrentPointerIfMatches(task_id);
                return null;
            }
            if (ctx.status === "done" || ctx.status === "failed") {
                await this.clearCurrentPointerIfMatches(task_id);
                return null;
            }
            return ctx;
        }
        catch (e) {
            debug("任务上下文", "获取当前任务失败(预期行为: 指针文件不存在或解析错误) —", e);
            return null;
        }
    }
    /**
     * 取消/关闭任务。
     */
    async cancel(taskId) {
        const ctx = await this.load(taskId);
        if (!ctx)
            return false;
        if (ctx.status === "done" || ctx.status === "failed") {
            this.diffOwnership.clearTask(taskId);
            this.scopeLease.release(taskId);
            await this.clearCurrentPointerIfMatches(taskId);
            debug("任务上下文", "已关闭终态任务 " + taskId);
            return true;
        }
        const allowed = VALID_TRANSITIONS[ctx.status];
        if (!allowed || !allowed.includes("failed")) {
            debug("任务上下文", `无法从 ${ctx.status} 取消到 failed`);
            return false;
        }
        ctx.status = "failed";
        await this.save(ctx);
        this.diffOwnership.clearTask(taskId);
        this.scopeLease.release(taskId);
        await this.clearCurrentPointerIfMatches(taskId);
        debug("任务上下文", "已取消任务 " + taskId);
        return true;
    }
    /**
     * 将失败任务恢复到 expanding 状态以重试 sf_expand。
     */
    async retryExpand(taskId) {
        const ctx = await this.load(taskId);
        if (!ctx || ctx.status !== "failed")
            return false;
        try {
            if (!ctx.classification) {
                const updated = await this.updateStatus(taskId, "classifying");
                if (!updated)
                    return false;
                await this.writeCurrentPointer(taskId);
                debug("任务上下文", "已恢复任务到 classifying (无 classification): " + taskId);
                return true;
            }
            const updated = await this.updateStatus(taskId, "expanding");
            if (!updated)
                return false;
            await this.writeCurrentPointer(taskId);
            debug("任务上下文", "已恢复任务到 expanding: " + taskId);
            return true;
        }
        catch (e) {
            debug("任务上下文", "恢复任务失败: " + (errorMessage(e)));
            return false;
        }
    }
    /**
     * 判断任务是否可恢复。
     */
    isResumable(ctx) {
        return !["done", "failed", "classifying"].includes(ctx.status);
    }
    /**
     * 根据当前状态生成恢复提示信息。
     */
    getResumeHint(ctx) {
        const hints = {
            expanding: "意图膨胀未完成，需重新执行 sf_expand",
            executing: "代码执行中断，需重新执行代码修改",
            verifying: "验证未完成，需调用 sf_verify",
            retrying: "重试中断，需继续修复",
            learning: "自进化未完成，需调用 sf_learn",
            reworking: "返工中，需回溯到上游阶段重新执行",
        };
        return hints[ctx.status] || "未知状态";
    }
    /**
     * 列出最近的任务。
     */
    async listRecent(limit = 10) {
        const files = await fs.readdir(this.stateDir);
        const taskFiles = files.filter((f) => f.startsWith("task-") && f.endsWith(".json"));
        const tasks = await Promise.all(taskFiles.map(async (f) => {
            const data = await fs.readFile(path.join(this.stateDir, f), "utf-8");
            const ctx = safeJsonParse(data);
            if (!ctx)
                return null;
            return {
                task_id: ctx.task_id,
                intent: ctx.intent,
                status: ctx.status,
                created_at: ctx.created_at,
            };
        }));
        return tasks.filter((t) => t !== null)
            .sort((a, b) => b.created_at.localeCompare(a.created_at))
            .slice(0, limit);
    }
    /**
     * 自动终结陈旧的非终态任务。
     */
    async autoFailStale() {
        const STALE_MS_EXECUTING = 30 * 60 * 1000;
        const STALE_MS_OTHER = 60 * 60 * 1000;
        const TERMINAL = new Set(["done", "failed"]);
        const now = Date.now();
        const failed = [];
        const files = await fs.readdir(this.stateDir);
        const taskFiles = files.filter((f) => f.startsWith("task-") && f.endsWith(".json"));
        for (const f of taskFiles) {
            try {
                const filePath = path.join(this.stateDir, f);
                const content = await fs.readFile(filePath, "utf-8");
                const ctx = safeJsonParse(content);
                if (!ctx || !ctx.task_id || !ctx.status || TERMINAL.has(ctx.status))
                    continue;
                const ageMs = new Date(ctx.updated_at ?? ctx.created_at).getTime();
                const elapsed = now - ageMs;
                const isStale = ctx.status === "executing" || ctx.status === "verifying" || ctx.status === "learning"
                    ? elapsed > STALE_MS_EXECUTING
                    : elapsed > STALE_MS_OTHER;
                if (isStale) {
                    const prevStatus = ctx.status;
                    try {
                        await this.updateStatus(ctx.task_id, "failed");
                        failed.push(ctx.task_id);
                        debug("任务上下文", `自动终结陈旧任务 ${ctx.task_id} (${prevStatus}, ${Math.round(elapsed / 60000)}min)`);
                    }
                    catch {
                        // 状态转换不合法时跳过
                    }
                }
            }
            catch {
                // 跳过不可读文件
            }
        }
        return failed;
    }
    /**
     * 清理过期和超量任务。
     */
    async cleanup(dryRun = true) {
        return cleanupStaleTasks(this.stateDir, dryRun);
    }
    // ── 委托到 manager_setters ──
    /** 设置任务计划结果 */
    async setPlanning(taskId, result) {
        return this._setters.setPlanning(taskId, result);
    }
    /** 设置代码审查结果 */
    async setCodeReview(taskId, result) {
        return this._setters.setCodeReview(taskId, result);
    }
    /** 设置交付结果 */
    async setDelivery(taskId, result) {
        return this._setters.setDelivery(taskId, result);
    }
    /** 设置工具调用追踪和违规记录 */
    async setToolTrace(taskId, trace, violations) {
        return this._setters.setToolTrace(taskId, trace, violations);
    }
    /** 持久化 Plan Proposal Gate 评估结果 */
    async setPlanProposalGate(taskId, gate, existingCtx) {
        return this._setters.setPlanProposalGate(taskId, gate, existingCtx);
    }
    /** 持久化 Plan Proposal Evidence */
    async setPlanProposalEvidence(taskId, evidence) {
        return this._setters.setPlanProposalEvidence(taskId, evidence);
    }
    /** 在执行动作前检查 Plan Gate */
    checkPlanGateBeforeWrite(ctx) {
        return this._setters.checkPlanGateBeforeWrite(ctx);
    }
    /** 设置任务产物输出 */
    async setArtifact(taskId, artifact, existingCtx) {
        return this._setters.setArtifact(taskId, artifact, existingCtx);
    }
    /** 更新产物状态并追加 evidence_ref */
    async updateArtifactStatus(taskId, params) {
        return this._setters.updateArtifactStatus(taskId, params);
    }
    /** 更新修复循环状态（能力 3） */
    async updateRepairLoop(taskId, failurePhase, autoRepairable, escalationReason) {
        return this._setters.updateRepairLoop(taskId, failurePhase, autoRepairable, escalationReason);
    }
    /** 证据驱动门禁结果写入 */
    async setEvidenceGroundingResult(taskId, payload) {
        return this._setters.setEvidenceGroundingResult(taskId, payload);
    }
    /** 记录返工事件（能力 6） */
    async recordRework(taskId, fromPhase, toPhase, reason) {
        return this._setters.recordRework(taskId, fromPhase, toPhase, reason);
    }
    // ── 私有方法 ──
    async clearCurrentPointerIfMatches(taskId) {
        try {
            const data = await fs.readFile(this.pointerPath, "utf-8");
            const parsed = safeJsonParse(data);
            const task_id = parsed?.task_id;
            if (!task_id) {
                await fs.unlink(this.pointerPath).catch((e) => { debug("任务上下文", "清理文件失败", e); });
                return;
            }
            if (task_id === taskId) {
                await fs.unlink(this.pointerPath).catch((e) => { debug("任务上下文", "清理文件失败", e); });
            }
        }
        catch (e) {
            debug("任务上下文", "清除当前任务指针失败(预期行为: 指针文件不存在或解析错误) —", e);
            await fs.unlink(this.pointerPath).catch((e) => { debug("任务上下文", "清理文件失败", e); });
        }
    }
    taskFilePath(taskId) {
        return path.join(this.stateDir, `${taskId}.json`);
    }
    get pointerPath() {
        return path.join(this.stateDir, "current-task.json");
    }
    async writeCurrentPointer(taskId) {
        await fs.mkdir(this.stateDir, { recursive: true });
        const tmpPath = `${this.pointerPath}.${taskId}.tmp`;
        try {
            await fs.writeFile(tmpPath, JSON.stringify({ task_id: taskId }));
            await fs.rename(tmpPath, this.pointerPath);
        }
        catch (e) {
            await fs.unlink(tmpPath).catch((e) => { debug("任务上下文", "清理文件失败", e); });
            throw e;
        }
    }
}
//# sourceMappingURL=manager.js.map