/**
 * Global Session Store
 *
 * Tracks agent sessions across all repos on the machine.
 * Works without HQ / PMO — just needs ~/.proletariat/sessions.db.
 *
 * Schema: id, agentName, runner, task, workdir, sessionName,
 *         environment, permissionMode, status, startedAt, endedAt
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import Database from 'better-sqlite3';
import { execSync } from 'node:child_process';
// =============================================================================
// Helpers
// =============================================================================
function rowToSession(row) {
    return {
        id: row.id,
        agentName: row.agent_name,
        runner: row.runner,
        task: row.task,
        workdir: row.workdir,
        sessionName: row.session_name,
        environment: row.environment,
        permissionMode: row.permission_mode,
        status: row.status,
        startedAt: new Date(row.started_at),
        endedAt: row.ended_at ? new Date(row.ended_at) : undefined,
    };
}
function getDbPath() {
    const dir = path.join(os.homedir(), '.proletariat');
    fs.mkdirSync(dir, { recursive: true });
    return path.join(dir, 'sessions.db');
}
// =============================================================================
// Session Store
// =============================================================================
export class SessionStore {
    db;
    constructor(dbPath) {
        this.db = new Database(dbPath ?? getDbPath());
        this.ensureSchema();
    }
    ensureSchema() {
        this.db.exec(`
      CREATE TABLE IF NOT EXISTS sessions (
        id TEXT PRIMARY KEY,
        agent_name TEXT NOT NULL,
        runner TEXT NOT NULL,
        task TEXT NOT NULL,
        workdir TEXT NOT NULL,
        session_name TEXT NOT NULL,
        environment TEXT NOT NULL DEFAULT 'host',
        permission_mode TEXT NOT NULL DEFAULT 'safe',
        status TEXT NOT NULL DEFAULT 'running',
        started_at INTEGER NOT NULL,
        ended_at INTEGER
      )
    `);
    }
    /**
     * Create a new session record.
     */
    create(params) {
        const id = `SES-${Date.now().toString(36).toUpperCase()}`;
        const now = Date.now();
        this.db.prepare(`
      INSERT INTO sessions (id, agent_name, runner, task, workdir, session_name, environment, permission_mode, status, started_at)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?)
    `).run(id, params.agentName, params.runner, params.task, params.workdir, params.sessionName, params.environment, params.permissionMode, now);
        return {
            id,
            agentName: params.agentName,
            runner: params.runner,
            task: params.task,
            workdir: params.workdir,
            sessionName: params.sessionName,
            environment: params.environment,
            permissionMode: params.permissionMode,
            status: 'running',
            startedAt: new Date(now),
        };
    }
    /**
     * Get a session by ID or agent name.
     */
    get(idOrName) {
        const row = this.db.prepare(`SELECT * FROM sessions WHERE id = ? OR agent_name = ? ORDER BY started_at DESC LIMIT 1`).get(idOrName, idOrName);
        return row ? rowToSession(row) : null;
    }
    /**
     * Get a session by tmux session name.
     */
    getBySessionName(sessionName) {
        const row = this.db.prepare(`SELECT * FROM sessions WHERE session_name = ? ORDER BY started_at DESC LIMIT 1`).get(sessionName);
        return row ? rowToSession(row) : null;
    }
    /**
     * List sessions, optionally filtered by status.
     */
    list(status) {
        let rows;
        if (status) {
            rows = this.db.prepare(`SELECT * FROM sessions WHERE status = ? ORDER BY started_at DESC`).all(status);
        }
        else {
            rows = this.db.prepare(`SELECT * FROM sessions ORDER BY started_at DESC`).all();
        }
        return rows.map(rowToSession);
    }
    /**
     * Update session status.
     */
    updateStatus(id, status) {
        const endedAt = (status === 'done' || status === 'error' || status === 'stopped') ? Date.now() : null;
        this.db.prepare(`UPDATE sessions SET status = ?, ended_at = COALESCE(?, ended_at) WHERE id = ?`).run(status, endedAt, id);
    }
    /**
     * Reconcile session statuses with actual tmux sessions.
     * Marks sessions as 'done' if their tmux session no longer exists.
     */
    reconcile() {
        const running = this.list('running');
        for (const session of running) {
            if (!this.isTmuxSessionAlive(session.sessionName)) {
                this.updateStatus(session.id, 'done');
            }
        }
    }
    /**
     * Resolve an identifier to a session.
     * Tries: exact ID match, agent name, partial match on agent name or session name.
     */
    resolve(identifier) {
        // Exact ID match
        const byId = this.get(identifier);
        if (byId)
            return byId;
        // Partial agent name match (prefer running sessions)
        const allSessions = this.list();
        const running = allSessions.filter(s => s.status === 'running');
        const pool = running.length > 0 ? running : allSessions;
        const match = pool.find(s => s.agentName.includes(identifier) ||
            s.sessionName.includes(identifier) ||
            s.id.includes(identifier.toUpperCase()));
        return match ?? null;
    }
    /**
     * Check if a tmux session is alive.
     */
    isTmuxSessionAlive(sessionName) {
        try {
            execSync(`tmux has-session -t "${sessionName}" 2>/dev/null`, { stdio: 'pipe' });
            return true;
        }
        catch {
            return false;
        }
    }
    close() {
        this.db.close();
    }
}
//# sourceMappingURL=session-store.js.map