"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.SessionsModule = void 0;
const BaseChatModule_1 = require("./BaseChatModule");
const index_1 = require("../../services/index");
const KnowhowClient_1 = require("../../services/KnowhowClient");
const messagesToRenderEvents_1 = require("../renderer/messagesToRenderEvents");
const index_2 = require("../../utils/index");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class SessionsModule extends BaseChatModule_1.BaseChatModule {
    name = "sessions";
    description = "Session and attachment management";
    agentModule;
    constructor(agentModule) {
        super();
        this.agentModule = agentModule;
    }
    getCommands() {
        return [
            {
                name: "attach",
                description: "Attach to a RUNNING session. Use --completed to also see completed sessions.",
                handler: this.handleAttachCommand.bind(this),
            },
            {
                name: "resume",
                description: "Resume a completed/saved session with optional additional context",
                handler: this.handleResumeCommand.bind(this),
            },
            {
                name: "sessions",
                description: "List running sessions. Use --completed to also show completed/saved sessions.",
                handler: this.handleSessionsCommand.bind(this),
            },
            {
                name: "logs",
                description: "Show recent messages from attached agent [N=20]",
                handler: this.handleLogsCommand.bind(this),
                modes: ["agent:attached"],
            },
        ];
    }
    async handleLogsCommand(args) {
        const count = parseInt(args[0] || "20", 10) || 20;
        const activeSyncedWatcher = this.agentModule.getActiveSyncedWatcher();
        const renderer = this.agentModule.getRenderer();
        const taskRegistry = this.agentModule.getTaskRegistry();
        try {
            if (activeSyncedWatcher) {
                const threads = await activeSyncedWatcher.getThreads();
                const lastThread = threads[threads.length - 1] || [];
                const events = (0, messagesToRenderEvents_1.messagesToRenderEvents)(lastThread, activeSyncedWatcher.taskId, activeSyncedWatcher.agentName);
                renderer.logMessages(events, count);
                return;
            }
            const activeTaskId = renderer.getActiveTaskId();
            if (activeTaskId && taskRegistry.has(activeTaskId)) {
                const taskInfo = taskRegistry.get(activeTaskId);
                const agent = taskInfo?.agent;
                if (agent) {
                    const threads = agent.getThreads();
                    const lastThread = threads[threads.length - 1] || [];
                    const events = (0, messagesToRenderEvents_1.messagesToRenderEvents)(lastThread, activeTaskId, agent.name);
                    renderer.logMessages(events, count);
                    return;
                }
            }
            console.log("No active agent to show logs for. Use /attach <taskId> to attach to an agent first.");
        }
        catch (error) {
            console.error("Error showing logs:", error);
        }
    }
    async selectByNumber(prompt, allIds) {
        const numbers = allIds.map((_, i) => String(i + 1));
        const input = await this.chatService?.getInput(prompt, numbers);
        if (!input || !input.trim())
            return undefined;
        const idx = parseInt(input.trim(), 10);
        if (isNaN(idx) || idx < 1 || idx > allIds.length)
            return undefined;
        return allIds[idx - 1];
    }
    async handleAttachCommand(args) {
        const taskRegistry = this.agentModule.getTaskRegistry();
        const sessionManager = this.agentModule.getSessionManager();
        const showCompleted = args.includes("--completed");
        const filteredArgs = args.filter((a) => a !== "--completed");
        if (filteredArgs.length === 0) {
            const runningTasks = taskRegistry.getAll();
            const fsAgents = await this.getFsAgents(runningTasks);
            const savedSessions = showCompleted
                ? sessionManager.listAvailableSessions()
                : [];
            if (runningTasks.length === 0 &&
                fsAgents.length === 0 &&
                savedSessions.length === 0) {
                console.log("No running sessions found to attach to.\n" +
                    "Use /attach --completed to also see completed sessions.\n" +
                    "Use /resume <taskId> to resume a completed session.");
                return;
            }
            if (showCompleted) {
                this.logSessionsCompact(runningTasks, savedSessions, fsAgents);
            }
            else {
                this.printRunningTable(runningTasks, fsAgents);
            }
            const allIds = [
                ...runningTasks.map((t) => t.taskId),
                ...fsAgents.map((a) => a.taskId),
                ...(showCompleted ? savedSessions.map((s) => s.sessionId) : []),
            ];
            const selectedId = await this.selectByNumber(showCompleted
                ? "Enter number to attach/resume (or press Enter to cancel): "
                : "Enter number to attach to (or press Enter to cancel): ", allIds);
            if (selectedId) {
                const trimmed = selectedId;
                const isCompleted = showCompleted && savedSessions.some((s) => s.sessionId === trimmed);
                if (isCompleted) {
                    await this.resumeById(trimmed);
                }
                else {
                    await this.attachById(trimmed);
                }
            }
            return;
        }
        const taskId = filteredArgs[0];
        await this.attachById(taskId);
    }
    async attachById(id) {
        const taskRegistry = this.agentModule.getTaskRegistry();
        const sessionManager = this.agentModule.getSessionManager();
        if (taskRegistry.has(id)) {
            const taskInfo = taskRegistry.get(id);
            const renderer = this.agentModule.getRenderer();
            const context = this.chatService?.getContext();
            const selectedAgent = taskInfo.agent;
            if (context && selectedAgent) {
                context.selectedAgent = selectedAgent;
                context.agentMode = true;
                context.currentAgent = taskInfo.agentName;
                context.activeAgentTaskId = id;
                context.currentModel = selectedAgent.getModel();
                context.currentProvider = selectedAgent.getProvider();
            }
            this.agentModule.setActiveAgentTaskId(id);
            renderer.setActiveTaskId(id);
            if (this.chatService)
                this.chatService.setMode("agent:attached");
            console.log(`🔄 Attached to running task: ${id}`);
            console.log(`   Agent : ${taskInfo.agentName}`);
            console.log(`   Task  : ${taskInfo.initialInput}`);
            console.log(`   Status: ${taskInfo.status}`);
            console.log(`   Type /logs to see recent messages, or /detach to detach.`);
            return;
        }
        const fsAgentPath = path.join(".knowhow", "processes", "agents", id);
        if (fs.existsSync(fsAgentPath)) {
            const status = this.readFsAgentStatus(fsAgentPath);
            if (status === "completed") {
                console.log(`⚠️  Task ${id} is completed.\n` +
                    `   Use /resume ${id} to resume it with additional context.`);
                return;
            }
            await this.attachToFsAgent(id);
            return;
        }
        try {
            const session = sessionManager.loadSession(id);
            if (session) {
                if (session.status === "completed") {
                    console.log(`⚠️  Session ${id} is completed.\n` +
                        `   Use /resume ${id} to resume it with additional context.`);
                }
                else {
                    const fsPath = path.join(".knowhow", "processes", "agents", id);
                    if (fs.existsSync(fsPath)) {
                        await this.attachToFsAgent(id);
                    }
                    else {
                        await this.attachToWebAgent(id);
                    }
                }
                return;
            }
        }
        catch {
        }
        try {
            await this.attachToWebAgent(id);
            return;
        }
        catch {
        }
        console.log(`Session/Task "${id}" not found among running tasks, filesystem agents, or web.\n` +
            `Use /sessions to see all known sessions.`);
    }
    async handleResumeCommand(args) {
        const sessionManager = this.agentModule.getSessionManager();
        if (args.length === 0 || args[0] === "--all") {
            const showAll = args[0] === "--all";
            const allSessions = sessionManager.listAvailableSessions();
            const savedSessions = showAll ? allSessions : allSessions.slice(0, 10);
            if (savedSessions.length === 0) {
                console.log("No saved sessions found to resume.");
                return;
            }
            this.printSavedSessionsTable(savedSessions);
            if (!showAll && allSessions.length > 10) {
                console.log(`   ... and ${allSessions.length - 10} more. Use /resume --all to see all sessions.`);
            }
            const allIds = savedSessions.map((s) => s.sessionId);
            const selectedId = await this.selectByNumber("Enter number to resume (or press Enter to cancel): ", allIds);
            if (selectedId) {
                await this.resumeById(selectedId);
            }
            return;
        }
        await this.resumeById(args[0]);
    }
    async resumeById(id) {
        const sessionManager = this.agentModule.getSessionManager();
        try {
            const session = sessionManager.loadSession(id);
            if (session) {
                console.log(`\n📋 Session found: ${id}`);
                console.log(`   Agent  : ${session.agentName}`);
                console.log(`   Task   : ${session.initialInput}`);
                console.log(`   Status : ${session.status}`);
                const additionalContext = await this.chatService?.getInput("Add any additional context for resuming this session (or press Enter to skip): ");
                await this.agentModule.resumeSession(id, additionalContext?.trim() || undefined);
                return;
            }
        }
        catch {
        }
        const fsAgentPath = path.join(".knowhow", "processes", "agents", id);
        if (fs.existsSync(fsAgentPath)) {
            const metadataPath = path.join(fsAgentPath, "metadata.json");
            if (fs.existsSync(metadataPath)) {
                try {
                    const raw = fs.readFileSync(metadataPath, "utf-8");
                    const metadata = JSON.parse(raw);
                    const threads = metadata.threads || [];
                    const agentName = metadata.agentName || "Developer";
                    const savedSession = sessionManager.loadSession(id);
                    const initialInput = savedSession?.initialInput || metadata.initialInput || metadata.prompt || "";
                    console.log(`\n📋 Found task in filesystem: ${id}`);
                    console.log(`   Agent  : ${agentName}`);
                    console.log(`   Task   : ${initialInput}`);
                    console.log(`   Status : ${metadata.status || "unknown"}`);
                    const additionalContext = await this.chatService?.getInput("Add any additional context for resuming this session (or press Enter to skip): ");
                    const normalizedThreads = threads.length > 0 && !Array.isArray(threads[0])
                        ? [threads]
                        : threads;
                    await this.agentModule.resumeFromMessages({
                        agentName,
                        taskId: id,
                        threads: normalizedThreads,
                        input: additionalContext?.trim() || initialInput || "",
                    });
                    return;
                }
                catch (e) {
                    console.error(`⚠️  Failed to load metadata for task ${id}: ${e.message}`);
                }
            }
            console.log(`⚠️  Task ${id} exists in the filesystem but has no saved session or metadata.\n` +
                `   Use /attach ${id} if it is still running.`);
            return;
        }
        console.log(`Session "${id}" not found. Use /sessions to list available sessions.`);
    }
    async handleSessionsCommand(args) {
        try {
            const showCompleted = args.includes("--completed") || args.includes("--all");
            const showCsv = args.includes("--csv");
            const taskRegistry = this.agentModule.getTaskRegistry();
            const sessionManager = this.agentModule.getSessionManager();
            const runningTasks = taskRegistry.getAll();
            const fsAgents = await this.getFsAgents(runningTasks);
            const savedSessions = showCompleted
                ? sessionManager.listAvailableSessions()
                : [];
            if (showCompleted) {
                await this.logSessionTable(true, showCsv, true);
            }
            else {
                if (runningTasks.length === 0 && fsAgents.length === 0) {
                    console.log("No running sessions. Use /sessions --completed to also see completed sessions.");
                }
                else if (showCsv) {
                    this.logSessionsCsv(runningTasks, [], fsAgents);
                }
                else {
                    this.logSessionsCompact(runningTasks, [], fsAgents);
                }
            }
            const allIds = [
                ...runningTasks.map((t) => t.taskId),
                ...fsAgents.map((a) => a.taskId),
                ...savedSessions.map((s) => s.sessionId),
            ];
            if (allIds.length > 0) {
                const selectedId = await this.selectByNumber(showCompleted
                    ? "Enter number to attach/resume (or press Enter to skip): "
                    : "Enter number to attach to (or press Enter to skip): ", allIds);
                if (selectedId) {
                    const isRunning = taskRegistry.has(selectedId) ||
                        fsAgents.some((a) => a.taskId === selectedId);
                    if (isRunning) {
                        await this.attachById(selectedId);
                    }
                    else {
                        await this.resumeById(selectedId);
                    }
                }
            }
        }
        catch (error) {
            console.error("Error listing sessions and tasks:", error);
        }
    }
    async logSessionTable(all = false, csv = false, includeFs = false) {
        const taskRegistry = this.agentModule.getTaskRegistry();
        const sessionManager = this.agentModule.getSessionManager();
        const runningTasks = taskRegistry.getAll();
        let savedSessions = sessionManager.listAvailableSessions();
        if (!all) {
            savedSessions = savedSessions.filter((s) => s.startTime >= this.agentModule.getProcessStartTime());
            const filteredTasks = runningTasks.filter((t) => t.startTime >= this.agentModule.getProcessStartTime());
            const fsAgents = includeFs ? await this.getFsAgents(runningTasks) : [];
            if (filteredTasks.length === 0 &&
                savedSessions.length === 0 &&
                fsAgents.length === 0) {
                console.log("No sessions from this process run. Use --all to see all historical sessions.");
                return;
            }
            if (csv) {
                this.logSessionsCsv(filteredTasks, savedSessions, fsAgents);
            }
            else {
                this.logSessionsCompact(filteredTasks, savedSessions, fsAgents);
            }
            return;
        }
        const fsAgents = includeFs
            ? await this.getFsAgentsIncludingCompleted(runningTasks)
            : [];
        if (csv) {
            this.logSessionsCsv(runningTasks, savedSessions, fsAgents);
        }
        else {
            this.logSessionsCompact(runningTasks, savedSessions, fsAgents);
        }
    }
    printRunningTable(runningTasks, fsAgents) {
        const rows = [
            ...runningTasks.map((t) => ({
                id: t.taskId,
                agent: t.agentName,
                status: t.status,
                cost: `$${t.totalCost.toFixed(3)}`,
                type: "running",
            })),
            ...fsAgents.map((a) => ({
                id: a.taskId,
                agent: a.agentName,
                status: a.status,
                cost: a.totalCostUsd != null ? `$${a.totalCostUsd.toFixed(3)}` : "n/a",
                type: "fs",
            })),
        ];
        console.log("\n🏃 Running sessions (attach-able):");
        console.log("─".repeat(86));
        console.log("#".padEnd(5) +
            "taskId".padEnd(40) +
            "agent".padEnd(14) +
            "status".padEnd(12) +
            "cost");
        console.log("─".repeat(86));
        for (const r of rows) {
            const num = String(rows.indexOf(r) + 1).padEnd(5);
            const shortId = r.id.length > 38 ? r.id.substring(0, 35) + "..." : r.id;
            console.log(num +
                shortId.padEnd(40) +
                r.agent.padEnd(14) +
                r.status.padEnd(12) +
                r.cost);
        }
        console.log("─".repeat(86));
    }
    printSavedSessionsTable(savedSessions) {
        console.log("\n💾 Saved sessions (resumable):");
        console.log("─".repeat(86));
        console.log("#".padEnd(5) +
            "taskId".padEnd(40) +
            "agent".padEnd(14) +
            "status".padEnd(12) +
            "cost");
        console.log("─".repeat(86));
        for (let i = 0; i < savedSessions.length; i++) {
            const s = savedSessions[i];
            const num = String(i + 1).padEnd(5);
            const shortId = s.sessionId.length > 38
                ? s.sessionId.substring(0, 35) + "..."
                : s.sessionId;
            const cost = s.totalCost ? `$${s.totalCost.toFixed(3)}` : "$0.000";
            console.log(num +
                shortId.padEnd(40) +
                s.agentName.padEnd(14) +
                s.status.padEnd(12) +
                cost);
        }
        console.log("─".repeat(86));
    }
    logSessionsCompact(runningTasks, savedSessions, fsAgents = []) {
        const runningTaskIds = new Set(runningTasks.map((t) => t.taskId));
        const savedIds = new Set(savedSessions.map((s) => s.sessionId));
        const dedupedSaved = savedSessions.filter((s) => !runningTaskIds.has(s.sessionId));
        const allKnownIds = new Set([...runningTaskIds, ...savedIds]);
        const dedupedFs = fsAgents.filter((a) => !allKnownIds.has(a.taskId));
        const rows = [
            ...runningTasks.map((t) => ({
                id: t.taskId,
                agent: t.agentName,
                status: t.status,
                cost: `$${t.totalCost.toFixed(3)}`,
                type: "running",
                action: "/attach",
            })),
            ...dedupedFs.map((a) => ({
                id: a.taskId,
                agent: a.agentName,
                status: a.status,
                cost: a.totalCostUsd != null ? `$${a.totalCostUsd.toFixed(3)}` : "n/a",
                type: "fs",
                action: a.status === "completed" ? "/resume" : "/attach",
            })),
            ...dedupedSaved.map((s) => ({
                id: s.sessionId,
                agent: s.agentName,
                status: s.status,
                cost: s.totalCost ? `$${s.totalCost.toFixed(3)}` : "$0.000",
                type: "saved",
                action: "/resume",
            })),
        ];
        if (rows.length === 0) {
            console.log("No sessions found.");
            return;
        }
        console.log("\n📋 Sessions:");
        console.log("─".repeat(109));
        console.log("#".padEnd(5) +
            "taskId".padEnd(40) +
            "agent".padEnd(14) +
            "status".padEnd(12) +
            "type".padEnd(10) +
            "cost".padEnd(12) +
            "action");
        console.log("─".repeat(109));
        for (let i = 0; i < rows.length; i++) {
            const r = rows[i];
            const num = String(i + 1).padEnd(5);
            const shortId = r.id.length > 38 ? r.id.substring(0, 35) + "..." : r.id;
            console.log(num +
                shortId.padEnd(40) +
                r.agent.padEnd(14) +
                r.status.padEnd(12) +
                r.type.padEnd(10) +
                r.cost.padEnd(12) +
                r.action);
        }
        console.log("─".repeat(109));
    }
    logSessionsCsv(runningTasks, savedSessions, fsAgents = []) {
        const lines = ["taskId,agent,status,type,cost,startTime,initialInput"];
        const runningTaskIds = new Set(runningTasks.map((t) => t.taskId));
        const dedupedSaved = savedSessions.filter((s) => !runningTaskIds.has(s.sessionId));
        for (const t of runningTasks) {
            const input = (t.initialInput || "")
                .replace(/,/g, ";")
                .replace(/\n/g, " ");
            lines.push(`${t.taskId},${t.agentName},${t.status},running,${t.totalCost?.toFixed(3) || "0.000"},${t.startTime},"${input}"`);
        }
        for (const s of dedupedSaved) {
            const input = (s.initialInput || "")
                .replace(/,/g, ";")
                .replace(/\n/g, " ");
            lines.push(`${s.sessionId},${s.agentName},${s.status},saved,${s.totalCost?.toFixed(3) || "0.000"},${s.startTime},"${input}"`);
        }
        const allKnownIds = new Set([
            ...runningTaskIds,
            ...savedSessions.map((s) => s.sessionId),
        ]);
        for (const a of fsAgents) {
            if (!allKnownIds.has(a.taskId)) {
                lines.push(`${a.taskId},${a.agentName},${a.status},fs,${a.totalCostUsd != null ? a.totalCostUsd.toFixed(3) : "n/a"},n/a,""`);
            }
        }
        console.log(lines.join("\n"));
    }
    async attachToFsAgent(taskId) {
        const existingWatcher = this.agentModule.getActiveSyncedWatcher();
        if (existingWatcher) {
            existingWatcher.stopWatching();
            this.agentModule.setActiveSyncedWatcher(undefined);
        }
        const watcher = new index_1.FsSyncedAgentWatcher();
        await watcher.startWatching(taskId);
        this.agentModule.setActiveSyncedWatcher(watcher);
        this.agentModule.wireAgentRendering(taskId, watcher.agentEvents, watcher.eventTypes, watcher.agentName);
        watcher.agentEvents.once(watcher.eventTypes.done, (output) => {
            console.log(index_2.Marked.parse(output));
        });
        const context = this.chatService?.getContext();
        if (context)
            context.activeAgentTaskId = taskId;
        console.log(`📁 Attached to filesystem agent: ${taskId}`);
        const fsWatcherAgent = new index_1.WatcherBackedAgent(watcher);
        await this.agentModule.attachedAgentChatLoop(taskId, fsWatcherAgent);
    }
    async attachToWebAgent(taskId) {
        const client = new KnowhowClient_1.KnowhowSimpleClient();
        const details = await client.getTaskDetails(taskId);
        const webStatus = details?.data?.status;
        if (webStatus === "completed" || webStatus === "killed") {
            console.log(`⚠️  Web task ${taskId} has status: ${webStatus}.\n` +
                `   Use /resume ${taskId} to resume it with additional context.`);
            return;
        }
        const existingWatcher = this.agentModule.getActiveSyncedWatcher();
        if (existingWatcher) {
            existingWatcher.stopWatching();
            this.agentModule.setActiveSyncedWatcher(undefined);
        }
        const watcher = new index_1.WebSyncedAgentWatcher(client);
        await watcher.startWatching(taskId);
        this.agentModule.setActiveSyncedWatcher(watcher);
        this.agentModule.wireAgentRendering(taskId, watcher.agentEvents, watcher.eventTypes, watcher.agentName);
        const context = this.chatService?.getContext();
        if (context)
            context.activeAgentTaskId = taskId;
        console.log(`🌐 Attached to web agent: ${taskId}`);
        const webWatcherAgent = new index_1.WatcherBackedAgent(watcher);
        await this.agentModule.attachedAgentChatLoop(taskId, webWatcherAgent);
    }
    readFsAgentStatus(agentPath) {
        try {
            const statusPath = path.join(agentPath, "status.txt");
            if (fs.existsSync(statusPath)) {
                return fs.readFileSync(statusPath, "utf8").trim();
            }
            const metaPath = path.join(agentPath, "metadata.json");
            if (fs.existsSync(metaPath)) {
                const meta = JSON.parse(fs.readFileSync(metaPath, "utf8"));
                return meta.status || "unknown";
            }
        }
        catch {
        }
        return "unknown";
    }
    async getFsAgents(runningTasks) {
        const sessionManager = this.agentModule.getSessionManager();
        const registeredIds = new Set(runningTasks.map((t) => t.taskId));
        return sessionManager.discoverFsAgents(registeredIds);
    }
    async getFsAgentsIncludingCompleted(runningTasks) {
        const sessionManager = this.agentModule.getSessionManager();
        const registeredIds = new Set(runningTasks.map((t) => t.taskId));
        return sessionManager.discoverFsAgents(registeredIds, true);
    }
    async listAvailableSessions() {
        return this.agentModule.getSessionManager().listAvailableSessions();
    }
    async listSessionsAndTasks() {
        const taskRegistry = this.agentModule.getTaskRegistry();
        const sessionManager = this.agentModule.getSessionManager();
        return {
            runningTasks: taskRegistry.getAll(),
            savedSessions: sessionManager.listAvailableSessions(),
        };
    }
}
exports.SessionsModule = SessionsModule;
//# sourceMappingURL=SessionsModule.js.map