vibe-cli-tool
Version:
VibeCLI v1.9 - 模板商店生态,智能部署生成,多语言支持,交互式学习系统,企业级Web全栈应用CLI工具
325 lines • 10.9 kB
JavaScript
// 增强的会话管理和断线重连机制
// 基于MCP 2025-06-18规范的Last-Event-ID协议
import { EventEmitter } from 'events';
export class SessionManager extends EventEmitter {
constructor() {
super();
this.sessions = new Map();
this.eventHistory = new Map();
this.taskStates = new Map();
this.maxEventHistory = 1000; // 每个会话最大事件历史数
this.sessionTimeout = 30 * 60 * 1000; // 30分钟会话超时
this.startCleanupTimer();
}
/**
* 创建新会话
*/
createSession(sessionId, initParams) {
const session = {
id: sessionId,
protocolVersion: initParams.protocolVersion || '2025-06-18',
clientInfo: initParams.clientInfo,
capabilities: initParams.capabilities,
createdAt: new Date().toISOString(),
lastActivity: new Date().toISOString(),
initialized: false,
currentTasks: new Map(),
eventHistory: [],
connectionStatus: 'active'
};
this.sessions.set(sessionId, session);
this.eventHistory.set(sessionId, []);
this.emit('sessionCreated', session);
return session;
}
/**
* 获取会话
*/
getSession(sessionId) {
return this.sessions.get(sessionId) || null;
}
/**
* 更新会话活动时间
*/
updateSessionActivity(sessionId) {
const session = this.sessions.get(sessionId);
if (session) {
session.lastActivity = new Date().toISOString();
session.connectionStatus = 'active';
}
}
/**
* 标记会话已初始化
*/
markSessionInitialized(sessionId) {
const session = this.sessions.get(sessionId);
if (session) {
session.initialized = true;
this.updateSessionActivity(sessionId);
}
}
/**
* 检查会话是否有效
*/
isValidSession(sessionId) {
const session = this.sessions.get(sessionId);
return session !== undefined && session.initialized;
}
/**
* 记录SSE事件
*/
recordEvent(sessionId, event) {
const fullEvent = {
...event,
timestamp: new Date().toISOString(),
sessionId
};
const history = this.eventHistory.get(sessionId) || [];
history.push(fullEvent);
// 限制历史记录大小
if (history.length > this.maxEventHistory) {
history.shift();
}
this.eventHistory.set(sessionId, history);
// 同时更新会话中的事件历史
const session = this.sessions.get(sessionId);
if (session) {
session.eventHistory.push(fullEvent);
if (session.eventHistory.length > this.maxEventHistory) {
session.eventHistory.shift();
}
}
}
/**
* 处理断线重连
*/
handleReconnection(sessionId, lastEventId) {
const session = this.sessions.get(sessionId);
if (!session) {
return {
success: false,
missedEvents: [],
currentTasks: [],
resumeInstructions: ['会话不存在,请重新初始化']
};
}
// 标记会话为重连状态
session.connectionStatus = 'reconnecting';
// 获取丢失的事件
const missedEvents = this.getMissedEvents(sessionId, lastEventId);
// 获取当前进行中的任务
const currentTasks = Array.from(session.currentTasks.values())
.filter(task => task.status === 'running' || task.status === 'pending');
// 生成恢复指令
const resumeInstructions = this.generateResumeInstructions(session, currentTasks, missedEvents);
// 更新会话状态
session.connectionStatus = 'active';
this.updateSessionActivity(sessionId);
this.emit('sessionReconnected', {
sessionId,
missedEventsCount: missedEvents.length,
activeTasks: currentTasks.length
});
return {
success: true,
missedEvents,
currentTasks,
resumeInstructions
};
}
/**
* 获取丢失的事件
*/
getMissedEvents(sessionId, lastEventId) {
const history = this.eventHistory.get(sessionId) || [];
if (!lastEventId) {
// 如果没有lastEventId,返回最近的事件
return history.slice(-10);
}
const lastIndex = history.findIndex(event => event.id === lastEventId);
if (lastIndex >= 0) {
return history.slice(lastIndex + 1);
}
// 如果找不到lastEventId,可能是因为事件太老被清理了
return history.slice(-20); // 返回最近20个事件
}
/**
* 创建任务状态
*/
createTask(sessionId, taskId, taskType) {
const task = {
id: taskId,
type: taskType,
status: 'pending',
progress: 0,
startTime: new Date().toISOString(),
lastUpdate: new Date().toISOString(),
checkpoints: []
};
this.taskStates.set(taskId, task);
const session = this.sessions.get(sessionId);
if (session) {
session.currentTasks.set(taskId, task);
}
return task;
}
/**
* 更新任务进度
*/
updateTaskProgress(taskId, progress, phase, data) {
const task = this.taskStates.get(taskId);
if (task) {
task.progress = progress;
task.lastUpdate = new Date().toISOString();
// 创建检查点
const checkpoint = {
id: `checkpoint-${Date.now()}`,
timestamp: new Date().toISOString(),
progress,
phase,
data: data || {}
};
task.checkpoints.push(checkpoint);
// 限制检查点数量
if (task.checkpoints.length > 50) {
task.checkpoints.shift();
}
this.emit('taskProgress', {
taskId,
progress,
phase,
checkpoint
});
}
}
/**
* 完成任务
*/
completeTask(taskId, result) {
const task = this.taskStates.get(taskId);
if (task) {
task.status = 'completed';
task.progress = 1.0;
task.result = result;
task.lastUpdate = new Date().toISOString();
this.emit('taskCompleted', {
taskId,
result
});
}
}
/**
* 任务失败
*/
failTask(taskId, error) {
const task = this.taskStates.get(taskId);
if (task) {
task.status = 'failed';
task.error = error;
task.lastUpdate = new Date().toISOString();
this.emit('taskFailed', {
taskId,
error
});
}
}
/**
* 生成恢复指令
*/
generateResumeInstructions(session, activeTasks, missedEvents) {
const instructions = [];
instructions.push(`🔄 会话 ${session.id} 重连成功`);
if (missedEvents.length > 0) {
instructions.push(`📡 重播了 ${missedEvents.length} 个丢失的事件`);
}
if (activeTasks.length > 0) {
instructions.push(`⚡ 检测到 ${activeTasks.length} 个进行中的任务:`);
activeTasks.forEach(task => {
const latestCheckpoint = task.checkpoints[task.checkpoints.length - 1];
if (latestCheckpoint) {
instructions.push(` • ${task.type} (${Math.round(task.progress * 100)}% - ${latestCheckpoint.phase})`);
}
else {
instructions.push(` • ${task.type} (${task.status})`);
}
});
if (activeTasks.some(task => task.status === 'running')) {
instructions.push(`🚀 任务将自动恢复执行`);
}
}
else {
instructions.push(`✅ 所有任务已完成,会话状态正常`);
}
instructions.push(`⏰ 上次活动: ${new Date(session.lastActivity).toLocaleString()}`);
return instructions;
}
/**
* 清理过期会话
*/
cleanupExpiredSessions() {
const now = Date.now();
const expiredSessions = [];
for (const [sessionId, session] of this.sessions.entries()) {
const lastActivity = new Date(session.lastActivity).getTime();
if (now - lastActivity > this.sessionTimeout) {
expiredSessions.push(sessionId);
}
}
expiredSessions.forEach(sessionId => {
this.sessions.delete(sessionId);
this.eventHistory.delete(sessionId);
// 清理该会话的任务
for (const [taskId, task] of this.taskStates.entries()) {
if (task.id.startsWith(sessionId)) {
this.taskStates.delete(taskId);
}
}
this.emit('sessionExpired', sessionId);
});
if (expiredSessions.length > 0) {
console.log(`🧹 清理了 ${expiredSessions.length} 个过期会话`);
}
}
/**
* 启动清理定时器
*/
startCleanupTimer() {
this.cleanupInterval = setInterval(() => {
this.cleanupExpiredSessions();
}, 5 * 60 * 1000); // 每5分钟清理一次
}
/**
* 停止会话管理器
*/
stop() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
}
this.sessions.clear();
this.eventHistory.clear();
this.taskStates.clear();
}
/**
* 获取会话统计信息
*/
getStats() {
const now = Date.now();
const activeSessions = Array.from(this.sessions.values())
.filter(session => {
const lastActivity = new Date(session.lastActivity).getTime();
return now - lastActivity < this.sessionTimeout;
}).length;
const runningTasks = Array.from(this.taskStates.values())
.filter(task => task.status === 'running' || task.status === 'pending').length;
const totalEvents = Array.from(this.eventHistory.values())
.reduce((sum, events) => sum + events.length, 0);
return {
totalSessions: this.sessions.size,
activeSessions,
totalTasks: this.taskStates.size,
runningTasks,
totalEvents
};
}
}
//# sourceMappingURL=session-manager.js.map