refactor(storage): 采用 OpenCode 风格三层存储结构
重构消息存储系统,从"每条消息一个文件"改为分层存储:
- Session → Message → Parts 三层结构
- 12 种 Part 类型(TextPart, ToolPart, ReasoningPart 等)
- ToolPart 状态机(pending → running → completed/error)
- 通用 Storage API(read/write/list/remove)
新增文件:
- parts.ts: Part 类型定义(Zod schema)
- message.ts: MessageInfo 类型定义
- id.ts: ID 生成器
- storage/: 分层存储实现
删除旧文件:
- storage.ts, types.ts, migration.ts
存储路径:
~/.local/share/ai-assist/
├── session/{projectId}/{sessionId}.json
├── message/{sessionId}/{messageId}.json
├── part/{messageId}/{partId}.json
└── todo/{sessionId}.json
This commit is contained in:
@@ -1,76 +1,252 @@
|
||||
import type { ModelMessage } from 'ai';
|
||||
import type { SessionData, Todo, SessionSummary, ProjectMetadata } from './types.js';
|
||||
import { SessionStorage, sessionStorage } from './storage.js';
|
||||
import * as storage from './storage/index.js';
|
||||
import { SessionStorage, MessageStorage, PartStorage, TodoStorage } from './storage/index.js';
|
||||
import type { SessionInfo, Part, TodoItem } from './storage/index.js';
|
||||
import { generateSessionId } from './id.js';
|
||||
import { getProjectId, isGitRepository } from './project.js';
|
||||
|
||||
/**
|
||||
* 会话摘要(用于列表展示)
|
||||
*/
|
||||
export interface SessionSummary {
|
||||
id: string;
|
||||
title: string;
|
||||
workdir: string;
|
||||
messageCount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行时会话数据(兼容旧接口)
|
||||
*/
|
||||
export interface SessionData {
|
||||
id: string;
|
||||
projectId: string;
|
||||
parentId?: string;
|
||||
agentName?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
workdir: string;
|
||||
title?: string;
|
||||
messages: ModelMessage[];
|
||||
discoveredTools: string[];
|
||||
todos: TodoItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目元数据
|
||||
*/
|
||||
export interface ProjectMetadata {
|
||||
id: string;
|
||||
workdir: string;
|
||||
createdAt: string;
|
||||
isGitRepo: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话管理器
|
||||
* 提供高级会话操作接口
|
||||
* 提供高级会话操作接口,使用新的三层存储结构
|
||||
*/
|
||||
export class SessionManager {
|
||||
private storage: SessionStorage;
|
||||
private currentSession: SessionData | null = null;
|
||||
private currentProject: ProjectMetadata | null = null;
|
||||
private autoSaveInterval: ReturnType<typeof setInterval> | null = null;
|
||||
private lastSyncedCount: number = 0;
|
||||
private storageDir?: string;
|
||||
|
||||
constructor(storage?: SessionStorage) {
|
||||
this.storage = storage || sessionStorage;
|
||||
constructor(storageDir?: string) {
|
||||
this.storageDir = storageDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 - 尝试恢复或创建新会话
|
||||
*/
|
||||
async init(workdir: string): Promise<SessionData> {
|
||||
// 初始化存储
|
||||
await storage.initStorage(this.storageDir);
|
||||
|
||||
// 获取或创建项目
|
||||
this.currentProject = await this.storage.getOrCreateProject(workdir);
|
||||
this.currentProject = await this.getOrCreateProject(workdir);
|
||||
|
||||
// 尝试加载当前会话
|
||||
const currentSessionId = await this.storage.getCurrentSessionId();
|
||||
const currentSessionId = await this.getCurrentSessionId();
|
||||
|
||||
if (currentSessionId) {
|
||||
// 尝试加载会话
|
||||
const existing = await this.storage.loadSession(this.currentProject.id, currentSessionId);
|
||||
const existing = await this.loadSession(this.currentProject.id, currentSessionId);
|
||||
|
||||
if (existing && existing.workdir === workdir) {
|
||||
// 同一工作目录,恢复会话
|
||||
this.currentSession = existing;
|
||||
this.lastSyncedCount = existing.messages.length;
|
||||
this.startAutoSave();
|
||||
return this.currentSession;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新会话
|
||||
this.currentSession = this.createNewSession(workdir);
|
||||
this.lastSyncedCount = 0;
|
||||
await this.save();
|
||||
this.currentSession = await this.createNewSession(workdir);
|
||||
await this.saveSessionInfo();
|
||||
await this.setCurrentSessionPointer(this.currentSession.id);
|
||||
|
||||
// 启动自动保存
|
||||
this.startAutoSave();
|
||||
|
||||
return this.currentSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建项目
|
||||
*/
|
||||
private async getOrCreateProject(workdir: string): Promise<ProjectMetadata> {
|
||||
const projectId = await getProjectId(workdir);
|
||||
|
||||
try {
|
||||
const existing = await storage.read<ProjectMetadata>(['project', projectId]);
|
||||
return existing;
|
||||
} catch (e) {
|
||||
if (e instanceof storage.StorageNotFoundError) {
|
||||
const isGitRepo = await isGitRepository(workdir);
|
||||
const project: ProjectMetadata = {
|
||||
id: projectId,
|
||||
workdir,
|
||||
createdAt: new Date().toISOString(),
|
||||
isGitRepo,
|
||||
};
|
||||
await storage.write(['project', projectId], project);
|
||||
return project;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新会话
|
||||
*/
|
||||
private createNewSession(workdir: string): SessionData {
|
||||
private async createNewSession(workdir: string): Promise<SessionData> {
|
||||
if (!this.currentProject) {
|
||||
throw new Error('Project not initialized. Call init() first.');
|
||||
}
|
||||
|
||||
const sessionInfo = await SessionStorage.create(this.currentProject.id, workdir);
|
||||
|
||||
return {
|
||||
id: this.storage.generateSessionId(),
|
||||
projectId: this.currentProject.id,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
workdir,
|
||||
id: sessionInfo.id,
|
||||
projectId: sessionInfo.projectId,
|
||||
createdAt: new Date(sessionInfo.createdAt).toISOString(),
|
||||
updatedAt: new Date(sessionInfo.updatedAt).toISOString(),
|
||||
workdir: sessionInfo.workdir,
|
||||
title: sessionInfo.title,
|
||||
messages: [],
|
||||
discoveredTools: [],
|
||||
discoveredTools: sessionInfo.discoveredTools,
|
||||
todos: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载会话(从存储重建)
|
||||
*/
|
||||
private async loadSession(projectId: string, sessionId: string): Promise<SessionData | null> {
|
||||
const sessionInfo = await SessionStorage.get(projectId, sessionId);
|
||||
if (!sessionInfo) return null;
|
||||
|
||||
// 加载消息
|
||||
const messages = await this.loadMessagesFromStorage(sessionId);
|
||||
|
||||
// 加载 todos
|
||||
const todoList = await TodoStorage.get(sessionId);
|
||||
|
||||
return {
|
||||
id: sessionInfo.id,
|
||||
projectId: sessionInfo.projectId,
|
||||
parentId: sessionInfo.parentId,
|
||||
agentName: sessionInfo.agentName,
|
||||
createdAt: new Date(sessionInfo.createdAt).toISOString(),
|
||||
updatedAt: new Date(sessionInfo.updatedAt).toISOString(),
|
||||
workdir: sessionInfo.workdir,
|
||||
title: sessionInfo.title,
|
||||
messages,
|
||||
discoveredTools: sessionInfo.discoveredTools,
|
||||
todos: todoList?.items || [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从存储加载消息并转换为 AI SDK 格式
|
||||
*/
|
||||
private async loadMessagesFromStorage(sessionId: string): Promise<ModelMessage[]> {
|
||||
const messageInfos = await MessageStorage.listBySession(sessionId);
|
||||
const messages: ModelMessage[] = [];
|
||||
|
||||
for (const messageInfo of messageInfos) {
|
||||
const parts = await PartStorage.getByIds(messageInfo.id, messageInfo.partIds);
|
||||
const modelMessage = this.partsToModelMessage(messageInfo.role, parts);
|
||||
if (modelMessage) {
|
||||
messages.push(modelMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Parts 转换为 AI SDK ModelMessage
|
||||
*/
|
||||
private partsToModelMessage(role: string, parts: Part[]): ModelMessage | null {
|
||||
if (parts.length === 0) return null;
|
||||
|
||||
// 构建消息内容
|
||||
const content: unknown[] = [];
|
||||
|
||||
for (const part of parts) {
|
||||
switch (part.type) {
|
||||
case 'text':
|
||||
content.push({ type: 'text', text: part.text });
|
||||
break;
|
||||
case 'tool':
|
||||
if (role === 'assistant') {
|
||||
content.push({
|
||||
type: 'tool-call',
|
||||
toolCallId: part.toolCallId,
|
||||
toolName: part.toolName,
|
||||
args: part.args,
|
||||
});
|
||||
} else if (role === 'tool') {
|
||||
// Tool result message - AI SDK 的 tool message 格式
|
||||
return {
|
||||
role: 'tool',
|
||||
content: [{
|
||||
type: 'tool-result',
|
||||
toolCallId: part.toolCallId,
|
||||
toolName: part.toolName,
|
||||
result: part.result,
|
||||
}],
|
||||
} as unknown as ModelMessage;
|
||||
}
|
||||
break;
|
||||
case 'file':
|
||||
content.push({
|
||||
type: 'image',
|
||||
image: part.data,
|
||||
mimeType: part.mimeType,
|
||||
});
|
||||
break;
|
||||
case 'reasoning':
|
||||
// Reasoning 通常作为文本的一部分
|
||||
content.push({ type: 'text', text: `[Reasoning] ${part.text}` });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 简化:如果只有一个文本内容,直接使用字符串
|
||||
if (content.length === 1 && (content[0] as { type: string }).type === 'text') {
|
||||
return {
|
||||
role: role as 'user' | 'assistant' | 'system',
|
||||
content: (content[0] as { text: string }).text,
|
||||
} as ModelMessage;
|
||||
}
|
||||
|
||||
return {
|
||||
role: role as 'user' | 'assistant' | 'system' | 'tool',
|
||||
content,
|
||||
} as ModelMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话
|
||||
*/
|
||||
@@ -86,28 +262,104 @@ export class SessionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前会话(增量保存消息)
|
||||
* 保存会话信息
|
||||
*/
|
||||
async save(): Promise<void> {
|
||||
private async saveSessionInfo(): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
|
||||
// 增量保存消息
|
||||
await this.storage.saveSession(this.currentSession, this.lastSyncedCount);
|
||||
const sessionInfo: SessionInfo = {
|
||||
id: this.currentSession.id,
|
||||
projectId: this.currentSession.projectId,
|
||||
parentId: this.currentSession.parentId,
|
||||
agentName: this.currentSession.agentName,
|
||||
createdAt: new Date(this.currentSession.createdAt).getTime(),
|
||||
updatedAt: Date.now(),
|
||||
workdir: this.currentSession.workdir,
|
||||
title: this.currentSession.title,
|
||||
discoveredTools: this.currentSession.discoveredTools,
|
||||
stats: {
|
||||
messageCount: this.currentSession.messages.length,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 更新当前会话指针
|
||||
await this.storage.setCurrentSession(this.currentSession.id);
|
||||
|
||||
// 更新同步计数
|
||||
this.lastSyncedCount = this.currentSession.messages.length;
|
||||
await SessionStorage.save(sessionInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加消息
|
||||
* 保存当前会话
|
||||
*/
|
||||
async addMessage(message: ModelMessage): Promise<void> {
|
||||
async save(): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
this.currentSession.messages.push(message);
|
||||
await this.save();
|
||||
await this.saveSessionInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步消息到存储(将 AI SDK 消息转换为 Message + Parts)
|
||||
*/
|
||||
async syncMessages(messages: ModelMessage[]): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
|
||||
const sessionId = this.currentSession.id;
|
||||
|
||||
// 删除旧消息
|
||||
await MessageStorage.removeBySession(sessionId);
|
||||
|
||||
// 保存新消息
|
||||
for (const message of messages) {
|
||||
const messageInfo = await MessageStorage.create(sessionId, message.role as 'user' | 'assistant' | 'system');
|
||||
|
||||
// 将消息内容转换为 Parts
|
||||
const partIds: string[] = [];
|
||||
|
||||
if (typeof message.content === 'string') {
|
||||
// 简单文本
|
||||
const part = await PartStorage.createText(messageInfo.id, message.content);
|
||||
partIds.push(part.id);
|
||||
} else if (Array.isArray(message.content)) {
|
||||
// 复杂内容(多个 parts)
|
||||
for (const item of message.content) {
|
||||
const itemType = (item as { type: string }).type;
|
||||
if (itemType === 'text') {
|
||||
const part = await PartStorage.createText(messageInfo.id, (item as { text: string }).text);
|
||||
partIds.push(part.id);
|
||||
} else if (itemType === 'tool-call') {
|
||||
const toolCall = item as unknown as { toolCallId: string; toolName: string; args: Record<string, unknown> };
|
||||
const part = await PartStorage.createTool(
|
||||
messageInfo.id,
|
||||
toolCall.toolCallId,
|
||||
toolCall.toolName,
|
||||
toolCall.args
|
||||
);
|
||||
partIds.push(part.id);
|
||||
} else if (itemType === 'tool-result') {
|
||||
const toolResult = item as unknown as { toolCallId: string; toolName: string; result: unknown };
|
||||
const part = await PartStorage.create(messageInfo.id, 'tool', {
|
||||
toolCallId: toolResult.toolCallId,
|
||||
toolName: toolResult.toolName,
|
||||
args: {},
|
||||
status: 'completed',
|
||||
result: toolResult.result,
|
||||
});
|
||||
partIds.push(part.id);
|
||||
} else if (itemType === 'image') {
|
||||
const img = item as unknown as { image: string; mimeType: string };
|
||||
const part = await PartStorage.create(messageInfo.id, 'file', {
|
||||
filename: 'image',
|
||||
mimeType: img.mimeType,
|
||||
data: typeof img.image === 'string' ? img.image : '',
|
||||
});
|
||||
partIds.push(part.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新消息的 partIds
|
||||
if (partIds.length > 0) {
|
||||
await MessageStorage.update(sessionId, messageInfo.id, { partIds });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +368,17 @@ export class SessionManager {
|
||||
async setMessages(messages: ModelMessage[]): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
this.currentSession.messages = messages;
|
||||
await this.save();
|
||||
await this.syncMessages(messages);
|
||||
await this.saveSessionInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加消息
|
||||
*/
|
||||
async addMessage(message: ModelMessage): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
this.currentSession.messages.push(message);
|
||||
await this.setMessages(this.currentSession.messages);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +394,7 @@ export class SessionManager {
|
||||
async setDiscoveredTools(tools: string[]): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
this.currentSession.discoveredTools = tools;
|
||||
await this.save();
|
||||
await this.saveSessionInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,16 +407,16 @@ export class SessionManager {
|
||||
/**
|
||||
* 更新待办事项
|
||||
*/
|
||||
async setTodos(todos: Todo[]): Promise<void> {
|
||||
async setTodos(todos: Array<{ content: string; status: 'pending' | 'in_progress' | 'completed' }>): Promise<void> {
|
||||
if (!this.currentSession) return;
|
||||
this.currentSession.todos = todos;
|
||||
await this.save();
|
||||
const todoList = await TodoStorage.replace(this.currentSession.id, todos);
|
||||
this.currentSession.todos = todoList.items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待办事项
|
||||
*/
|
||||
getTodos(): Todo[] {
|
||||
getTodos(): TodoItem[] {
|
||||
return this.currentSession?.todos || [];
|
||||
}
|
||||
|
||||
@@ -166,26 +428,22 @@ export class SessionManager {
|
||||
throw new Error('Project not initialized. Call init() first.');
|
||||
}
|
||||
|
||||
// 创建新会话
|
||||
const newWorkdir = workdir || this.currentSession?.workdir || process.cwd();
|
||||
|
||||
// 如果工作目录变化,需要切换项目
|
||||
if (workdir && workdir !== this.currentProject.workdir) {
|
||||
this.currentProject = await this.storage.getOrCreateProject(workdir);
|
||||
this.currentProject = await this.getOrCreateProject(workdir);
|
||||
}
|
||||
|
||||
this.currentSession = this.createNewSession(newWorkdir);
|
||||
this.lastSyncedCount = 0;
|
||||
await this.save();
|
||||
this.currentSession = await this.createNewSession(newWorkdir);
|
||||
await this.saveSessionInfo();
|
||||
await this.setCurrentSessionPointer(this.currentSession.id);
|
||||
|
||||
return this.currentSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建子会话(用于 Task 工具)
|
||||
* @param parentId 父会话 ID
|
||||
* @param agentName 关联的 Agent 名称
|
||||
* @param title 会话标题
|
||||
*/
|
||||
createChildSession(parentId: string, agentName: string, title?: string): SessionData {
|
||||
if (!this.currentProject) {
|
||||
@@ -193,8 +451,8 @@ export class SessionManager {
|
||||
}
|
||||
|
||||
const workdir = this.currentSession?.workdir || process.cwd();
|
||||
const childSession: SessionData = {
|
||||
id: this.storage.generateSessionId(),
|
||||
return {
|
||||
id: generateSessionId(),
|
||||
projectId: this.currentProject.id,
|
||||
parentId,
|
||||
agentName,
|
||||
@@ -206,14 +464,24 @@ export class SessionManager {
|
||||
discoveredTools: [],
|
||||
todos: [],
|
||||
};
|
||||
return childSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存子会话
|
||||
*/
|
||||
async saveChildSession(session: SessionData): Promise<void> {
|
||||
await this.storage.saveSession(session, 0);
|
||||
const sessionInfo: SessionInfo = {
|
||||
id: session.id,
|
||||
projectId: session.projectId,
|
||||
parentId: session.parentId,
|
||||
agentName: session.agentName,
|
||||
createdAt: new Date(session.createdAt).getTime(),
|
||||
updatedAt: Date.now(),
|
||||
workdir: session.workdir,
|
||||
title: session.title,
|
||||
discoveredTools: session.discoveredTools,
|
||||
};
|
||||
await SessionStorage.save(sessionInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,12 +499,11 @@ export class SessionManager {
|
||||
throw new Error('Project not initialized. Call init() first.');
|
||||
}
|
||||
|
||||
const session = await this.storage.loadSession(this.currentProject.id, sessionId);
|
||||
const session = await this.loadSession(this.currentProject.id, sessionId);
|
||||
if (!session) return null;
|
||||
|
||||
this.currentSession = session;
|
||||
this.lastSyncedCount = session.messages.length;
|
||||
await this.storage.setCurrentSession(sessionId);
|
||||
await this.setCurrentSessionPointer(sessionId);
|
||||
|
||||
return session;
|
||||
}
|
||||
@@ -246,26 +513,78 @@ export class SessionManager {
|
||||
*/
|
||||
async listSessions(): Promise<SessionSummary[]> {
|
||||
if (!this.currentProject) {
|
||||
return this.storage.listAllSessions();
|
||||
return this.listAllSessions();
|
||||
}
|
||||
return this.storage.listSessionsByProject(this.currentProject.id);
|
||||
|
||||
const sessions = await SessionStorage.listByProject(this.currentProject.id);
|
||||
return sessions.map((s) => ({
|
||||
id: s.id,
|
||||
title: s.title || `会话 ${s.id}`,
|
||||
workdir: s.workdir,
|
||||
messageCount: s.stats?.messageCount || 0,
|
||||
createdAt: new Date(s.createdAt).toISOString(),
|
||||
updatedAt: new Date(s.updatedAt).toISOString(),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有项目的会话
|
||||
*/
|
||||
async listAllSessions(): Promise<SessionSummary[]> {
|
||||
return this.storage.listAllSessions();
|
||||
const sessions = await SessionStorage.listAll();
|
||||
return sessions.map((s) => ({
|
||||
id: s.id,
|
||||
title: s.title || `会话 ${s.id}`,
|
||||
workdir: s.workdir,
|
||||
messageCount: s.stats?.messageCount || 0,
|
||||
createdAt: new Date(s.createdAt).toISOString(),
|
||||
updatedAt: new Date(s.updatedAt).toISOString(),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除历史会话
|
||||
*/
|
||||
async deleteSession(sessionId: string): Promise<boolean> {
|
||||
if (!this.currentProject) {
|
||||
if (!this.currentProject) return false;
|
||||
|
||||
try {
|
||||
// 删除会话的消息和 Parts
|
||||
const messageInfos = await MessageStorage.listBySession(sessionId);
|
||||
for (const msg of messageInfos) {
|
||||
await PartStorage.removeByMessage(msg.id);
|
||||
}
|
||||
await MessageStorage.removeBySession(sessionId);
|
||||
|
||||
// 删除 todos
|
||||
await TodoStorage.removeBySession(sessionId);
|
||||
|
||||
// 删除会话信息
|
||||
await SessionStorage.remove(this.currentProject.id, sessionId);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return this.storage.deleteSession(this.currentProject.id, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话 ID(从存储)
|
||||
*/
|
||||
private async getCurrentSessionId(): Promise<string | null> {
|
||||
try {
|
||||
const pointer = await storage.read<{ sessionId: string }>(['current-session']);
|
||||
return pointer.sessionId;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前会话指针
|
||||
*/
|
||||
private async setCurrentSessionPointer(sessionId: string): Promise<void> {
|
||||
await storage.write(['current-session'], { sessionId });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,8 +619,29 @@ export class SessionManager {
|
||||
/**
|
||||
* 清理旧会话
|
||||
*/
|
||||
async cleanup(keepCount?: number): Promise<number> {
|
||||
return this.storage.cleanupOldSessions(keepCount);
|
||||
async cleanup(keepCount: number = 50): Promise<number> {
|
||||
const sessions = await this.listAllSessions();
|
||||
if (sessions.length <= keepCount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const toDelete = sessions.slice(keepCount);
|
||||
let deletedCount = 0;
|
||||
|
||||
for (const session of toDelete) {
|
||||
if (await this.deleteSession(session.id)) {
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储目录
|
||||
*/
|
||||
getStorageDir(): string {
|
||||
return this.storageDir || storage.getDefaultStorageDir();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user