UNPKG

overmind-mcp

Version:

Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour

110 lines • 3.85 kB
import fs from 'fs/promises'; import path from 'path'; import { Mutex } from 'async-mutex'; import { getWorkspaceDir } from './config.js'; import { rootLogger } from './logger.js'; const logger = rootLogger.child({ module: 'sessions' }); const sessionMutex = new Mutex(); const SESSIONS_FILE = 'bridge/agents.json'; const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000; function getSessionsPath(workspaceDir) { return path.resolve(workspaceDir || getWorkspaceDir(), SESSIONS_FILE); } function buildKey(runner, agentName) { return runner ? `${runner}:${agentName}` : agentName; } async function purgeExpired(sessions) { const now = Date.now(); const purged = {}; let changed = false; for (const [key, val] of Object.entries(sessions)) { if (typeof val === 'object' && val !== null && 'ts' in val) { if (now - val.ts < SESSION_TTL_MS) { purged[key] = val; } else { changed = true; } } else { purged[key] = val; } } return changed ? purged : sessions; } function extractId(val) { if (!val) return null; if (typeof val === 'string') return val; return val.id || null; } export async function getLastSessionId(agentName, workspaceDir, runner) { return sessionMutex.runExclusive(async () => { try { const filePath = getSessionsPath(workspaceDir); const content = await fs.readFile(filePath, 'utf-8'); let sessions = JSON.parse(content); sessions = await purgeExpired(sessions); const namespacedKey = buildKey(runner, agentName); if (sessions[namespacedKey]) { return extractId(sessions[namespacedKey]); } return extractId(sessions[agentName]) || null; } catch (_error) { return null; } }); } export async function saveSessionId(agentName, sessionId, workspaceDir, runner) { return sessionMutex.runExclusive(async () => { const filePath = getSessionsPath(workspaceDir); const dir = path.dirname(filePath); try { await fs.mkdir(dir, { recursive: true }); let sessions = {}; try { const content = await fs.readFile(filePath, 'utf-8'); sessions = JSON.parse(content); sessions = await purgeExpired(sessions); } catch (_e) { // Ignore error (file new) } const key = buildKey(runner, agentName); sessions[key] = { id: sessionId, ts: Date.now() }; await fs.writeFile(filePath, JSON.stringify(sessions, null, 2), 'utf-8'); } catch (error) { logger.error({ agentName, error }, 'Failed to save session ID.'); } }); } export async function deleteSessionId(agentName, workspaceDir, runner) { return sessionMutex.runExclusive(async () => { const filePath = getSessionsPath(workspaceDir); try { const content = await fs.readFile(filePath, 'utf-8'); let sessions = JSON.parse(content); const namespacedKey = buildKey(runner, agentName); let deleted = false; if (sessions[namespacedKey]) { delete sessions[namespacedKey]; deleted = true; } if (sessions[agentName]) { delete sessions[agentName]; deleted = true; } if (deleted) { sessions = await purgeExpired(sessions); await fs.writeFile(filePath, JSON.stringify(sessions, null, 2), 'utf-8'); } } catch (_e) { // Ignore } }); } //# sourceMappingURL=sessions.js.map