"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgentSyncFs = void 0;
const fs_1 = require("fs");
const path = __importStar(require("path"));
const fs_2 = require("fs");
class AgentSyncFs {
    static sharedCleanupInterval = null;
    static sharedBasePath = ".knowhow/processes/agents";
    static cleanupStarted = false;
    taskId;
    basePath = ".knowhow/processes/agents";
    taskPath;
    eventHandlersSetup = false;
    watcher = null;
    lastInputContent = "";
    finalizationPromise = null;
    agent;
    threadUpdateHandler;
    doneHandler;
    pendingThreadUpdatePromise = null;
    constructor() {
        AgentSyncFs.startSharedCleanupProcess();
    }
    async createTask(options) {
        this.taskId = options.taskId;
        this.taskPath = path.join(this.basePath, this.taskId);
        try {
            await fs_1.promises.mkdir(this.taskPath, { recursive: true });
            await this.writeStatus("running");
            await this.writeInput("");
            await this.writeMetadata({
                taskId: this.taskId,
                prompt: options.prompt,
                agentName: options.agentName || "unknown",
                startTime: new Date().toISOString(),
                status: "running",
            });
            console.log(`✅ Created filesystem sync at: ${this.taskPath}`);
            return this.taskId;
        }
        catch (error) {
            console.error(`❌ Failed to create filesystem sync:`, error);
            throw error;
        }
    }
    async writeStatus(status) {
        if (!this.taskPath)
            return;
        try {
            const statusPath = path.join(this.taskPath, "status.txt");
            await fs_1.promises.writeFile(statusPath, status, "utf8");
        }
        catch (error) {
            console.error(`❌ Failed to write status:`, error);
        }
    }
    async writeInput(content) {
        if (!this.taskPath)
            return;
        try {
            const inputPath = path.join(this.taskPath, "input.txt");
            await fs_1.promises.writeFile(inputPath, content, "utf8");
            this.lastInputContent = content;
        }
        catch (error) {
            console.error(`❌ Failed to write input:`, error);
        }
    }
    async writeMetadata(data) {
        if (!this.taskPath)
            return;
        try {
            const metadataPath = path.join(this.taskPath, "metadata.json");
            await fs_1.promises.writeFile(metadataPath, JSON.stringify(data, null, 2), "utf8");
        }
        catch (error) {
            console.error(`❌ Failed to write metadata:`, error);
        }
    }
    async updateMetadata(agent, inProgress, result) {
        if (!this.taskPath)
            return;
        try {
            const metadataPath = path.join(this.taskPath, "metadata.json");
            let metadata = {};
            try {
                const existingData = await fs_1.promises.readFile(metadataPath, "utf8");
                metadata = JSON.parse(existingData);
            }
            catch {
            }
            metadata.threads = agent.getThreads();
            metadata.totalCostUsd = agent.getTotalCostUsd();
            metadata.tokenUsage = agent.getTokenUsage();
            metadata.agentName = agent.name;
            metadata.inProgress = inProgress;
            metadata.lastUpdate = new Date().toISOString();
            if (result !== undefined) {
                metadata.result = result;
                metadata.status = "completed";
                await this.writeStatus("completed");
            }
            await fs_1.promises.writeFile(metadataPath, JSON.stringify(metadata, null, 2), "utf8");
        }
        catch (error) {
            console.error(`❌ Failed to update metadata:`, error);
        }
    }
    async readStatus() {
        if (!this.taskPath)
            return null;
        try {
            const statusPath = path.join(this.taskPath, "status.txt");
            const content = await fs_1.promises.readFile(statusPath, "utf8");
            return content.trim();
        }
        catch (error) {
            return null;
        }
    }
    async readInput() {
        if (!this.taskPath)
            return null;
        try {
            const inputPath = path.join(this.taskPath, "input.txt");
            const content = await fs_1.promises.readFile(inputPath, "utf8");
            return content;
        }
        catch (error) {
            return null;
        }
    }
    async checkForChanges(agent) {
        if (!this.taskPath)
            return;
        try {
            const status = await this.readStatus();
            if (status === "paused") {
                console.log(`⏸️ Agent task ${this.taskId} paused via filesystem`);
                await agent.pause();
                await this.waitForResume(agent);
            }
            else if (status === "killed") {
                console.log(`🛑 Agent task ${this.taskId} killed via filesystem`);
                await agent.kill();
            }
            const input = await this.readInput();
            if (input && input !== this.lastInputContent && input.trim() !== "") {
                console.log(`📬 New message received via filesystem for task ${this.taskId}`);
                this.lastInputContent = input;
                agent.addPendingUserMessage({
                    role: "user",
                    content: input,
                });
                await this.writeInput("");
            }
        }
        catch (error) {
            console.error(`❌ Error checking for changes:`, error);
        }
    }
    async waitForResume(agent) {
        const POLL_INTERVAL_MS = 2000;
        const MAX_WAIT_MS = 60 * 60 * 1000;
        const startTime = Date.now();
        while (Date.now() - startTime < MAX_WAIT_MS) {
            await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
            const status = await this.readStatus();
            if (status === "killed") {
                console.log(`🛑 Agent task ${this.taskId} killed while paused`);
                await agent.kill();
                return;
            }
            if (status === "running") {
                console.log(`▶️ Agent task ${this.taskId} resumed`);
                await agent.unpause();
                return;
            }
        }
        console.warn(`⚠️ Timeout waiting for resume on task ${this.taskId}`);
    }
    setupFileWatcher(agent) {
        if (!this.taskPath || this.watcher)
            return;
        try {
            this.watcher = (0, fs_2.watch)(this.taskPath, async (eventType, filename) => {
                if (filename === "status.txt" || filename === "input.txt") {
                    await this.checkForChanges(agent);
                }
            });
            console.log(`👁️ Watching filesystem at: ${this.taskPath}`);
        }
        catch (error) {
            console.error(`❌ Failed to setup file watcher:`, error);
        }
    }
    async setupAgentSync(agent, taskId) {
        if (!taskId)
            return;
        this.taskId = taskId;
        this.taskPath = path.join(this.basePath, this.taskId);
        try {
            await fs_1.promises.mkdir(this.taskPath, { recursive: true });
        }
        catch (error) {
        }
        if (!this.eventHandlersSetup) {
            this.setupEventHandlers(agent);
            this.setupFileWatcher(agent);
            this.eventHandlersSetup = true;
        }
    }
    setupEventHandlers(agent) {
        this.agent = agent;
        this.threadUpdateHandler = async () => {
            if (!this.taskId)
                return;
            try {
                this.pendingThreadUpdatePromise = (async () => {
                    await this.updateMetadata(agent, true);
                    await this.checkForChanges(agent);
                })();
                await this.pendingThreadUpdatePromise;
            }
            catch (error) {
                console.error(`❌ Error during threadUpdate sync:`, error);
            }
        };
        agent.agentEvents.on(agent.eventTypes.threadUpdate, this.threadUpdateHandler);
        this.doneHandler = (result) => {
            if (!this.taskId) {
                console.warn(`⚠️ [AgentSyncFs] Cannot finalize: taskId=${this.taskId}`);
                return;
            }
            console.log(`🎯 [AgentSyncFs] Done event received for task: ${this.taskId}`);
            this.finalizationPromise = (async () => {
                try {
                    if (this.pendingThreadUpdatePromise) {
                        console.log(`⏳ [AgentSyncFs] Awaiting pending thread update before finalizing...`);
                        await this.pendingThreadUpdatePromise.catch(() => {
                        });
                        this.pendingThreadUpdatePromise = null;
                    }
                    await this.updateMetadata(agent, false, result);
                    console.log(`✅ Completed filesystem sync for task: ${this.taskId}`);
                    await this.cleanup();
                }
                catch (error) {
                    console.error(`❌ Error finalizing task:`, error);
                    throw error;
                }
            })();
        };
        agent.agentEvents.on(agent.eventTypes.done, this.doneHandler);
    }
    async waitForFinalization() {
        if (this.finalizationPromise) {
            await this.finalizationPromise;
        }
    }
    async cleanup() {
        if (this.watcher) {
            this.watcher.close();
            this.watcher = null;
        }
    }
    static async cleanupOldTasks() {
        try {
            const agentsPath = AgentSyncFs.sharedBasePath;
            try {
                await fs_1.promises.access(agentsPath);
            }
            catch {
                return;
            }
            const entries = await fs_1.promises.readdir(agentsPath, { withFileTypes: true });
            const now = Date.now();
            const threeDaysMs = 3 * 24 * 60 * 60 * 1000;
            for (const entry of entries) {
                if (!entry.isDirectory())
                    continue;
                const taskPath = path.join(agentsPath, entry.name);
                try {
                    const stats = await fs_1.promises.stat(taskPath);
                    const age = now - stats.mtimeMs;
                    if (age > threeDaysMs) {
                        console.log(`🧹 Cleaning up old task directory: ${entry.name}`);
                        await fs_1.promises.rm(taskPath, { recursive: true, force: true });
                    }
                }
                catch (error) {
                    console.error(`❌ Error cleaning up ${entry.name}:`, error);
                }
            }
        }
        catch (error) {
            console.error(`❌ Error during cleanup:`, error);
        }
    }
    static startSharedCleanupProcess() {
        if (AgentSyncFs.cleanupStarted)
            return;
        AgentSyncFs.cleanupStarted = true;
        AgentSyncFs.sharedCleanupInterval = setInterval(() => {
            AgentSyncFs.cleanupOldTasks();
        }, 60 * 60 * 1000);
        AgentSyncFs.cleanupOldTasks();
    }
    stopCleanup() {
        if (AgentSyncFs.sharedCleanupInterval) {
            clearInterval(AgentSyncFs.sharedCleanupInterval);
            AgentSyncFs.sharedCleanupInterval = null;
            AgentSyncFs.cleanupStarted = false;
        }
    }
    reset() {
        if (this.agent) {
            if (this.threadUpdateHandler) {
                this.agent.agentEvents.removeListener(this.agent.eventTypes.threadUpdate, this.threadUpdateHandler);
                this.threadUpdateHandler = undefined;
            }
            if (this.doneHandler) {
                this.agent.agentEvents.removeListener(this.agent.eventTypes.done, this.doneHandler);
                this.doneHandler = undefined;
            }
            this.agent = undefined;
        }
        this.cleanup();
        this.taskId = undefined;
        this.taskPath = undefined;
        this.eventHandlersSetup = false;
        this.lastInputContent = "";
        this.finalizationPromise = null;
        this.pendingThreadUpdatePromise = null;
    }
}
exports.AgentSyncFs = AgentSyncFs;
//# sourceMappingURL=AgentSyncFs.js.map