fix: align cleanup actions with opfs storage

This commit is contained in:
Youzini-afk
2026-04-14 19:55:18 +08:00
parent 78db223833
commit 1867662653
6 changed files with 246 additions and 24 deletions

View File

@@ -2921,7 +2921,7 @@
<div>
<div class="bme-config-card-title">数据存储清理</div>
<div class="bme-config-card-subtitle">
删除本地 IndexedDB 缓存或服务端同步文件
删除本地 OPFS / IndexedDB 图谱存储,或清理服务端同步数据
</div>
</div>
</div>
@@ -2932,7 +2932,7 @@
type="button"
>
<i class="fa-solid fa-hard-drive"></i>
<span>清空当前聊天 IDB</span>
<span>清空当前聊天本地存储</span>
</button>
<button
class="bme-action-btn danger"
@@ -2940,7 +2940,7 @@
type="button"
>
<i class="fa-solid fa-explosion"></i>
<span>清空全部 BME IDB</span>
<span>清空全部 BME 本地存储</span>
</button>
<button
class="bme-action-btn danger"
@@ -2948,12 +2948,12 @@
type="button"
>
<i class="fa-solid fa-cloud-arrow-down"></i>
<span>清空服务端同步文件</span>
<span>清空服务端同步数据</span>
</button>
</div>
<div class="bme-config-help bme-cleanup-warning-text">
<i class="fa-solid fa-triangle-exclamation"></i>
「清空全部 BME IDB」和「清空服务端同步文件」需要输入 DELETE 确认。
「清空全部 BME 本地存储」和「清空服务端同步数据」需要输入 DELETE 确认。
</div>
</div>
</section>

View File

@@ -5246,9 +5246,9 @@ function _bindActions() {
clearGraph: "清空图谱",
clearVectorCache: "清空向量缓存",
clearBatchJournal: "清空提取历史",
deleteCurrentIdb: "清空当前 IDB",
deleteAllIdb: "清空全部 IDB",
deleteServerSyncFile: "清空服务端同步文件",
deleteCurrentIdb: "清空当前本地存储",
deleteAllIdb: "清空全部本地存储",
deleteServerSyncFile: "清空服务端同步数据",
backupToCloud: "\u5907\u4efd\u5230\u4e91\u7aef",
restoreFromCloud: "\u4ece\u4e91\u7aef\u83b7\u53d6\u5907\u4efd",
manageServerBackups: "\u7ba1\u7406\u670d\u52a1\u5668\u5907\u4efd",
@@ -11356,7 +11356,7 @@ function _formatPersistMismatchReason(reason = "") {
if (!normalized) return "—";
switch (normalized) {
case "persist-mismatch:indexeddb-behind-commit-marker":
return "本地 IndexedDB 缓存版本落后于当前聊天已确认版本";
return "本地图谱存储版本落后于当前聊天已确认版本";
default:
return normalized;
}
@@ -11366,7 +11366,7 @@ function _formatPersistMismatchHelp(reason = "") {
const normalized = String(reason || "").trim();
switch (normalized) {
case "persist-mismatch:indexeddb-behind-commit-marker":
return "当前聊天记录显示图谱已经确认到更高版本,但本地 IndexedDB 里还没有对应数据。常见于刚清空本地缓存,或写入确认还没完成。建议先点“重新探测图谱”;如果仍异常,再点“重试持久化”或执行重建/恢复。";
return "当前聊天记录显示图谱已经确认到更高版本,但本地 OPFS / IndexedDB 存储里还没有对应数据。常见于刚清空本地缓存,或写入确认还没完成。建议先点“重新探测图谱”;如果仍异常,再点“重试持久化”或执行重建/恢复。";
default:
return `检测到持久化一致性异常:${_formatPersistMismatchReason(normalized)}。建议先重新探测图谱;如果仍异常,再执行重建或恢复。`;
}
@@ -11750,7 +11750,7 @@ function _refreshCloudStorageModeUi(settings = _getSettings?.() || {}) {
if (helpText) {
helpText.textContent =
mode === "manual"
? "\u624b\u52a8\u50a8\u5b58\u53ea\u4fdd\u7559\u672c\u5730 IndexedDB \u5199\u5165\uff0c\u4e0d\u4f1a\u81ea\u52a8\u4e0a\u4f20\u6216\u8986\u76d6\u4e91\u7aef\u3002\u9700\u8981\u63a5\u529b\u65f6\uff0c\u8bf7\u624b\u52a8\u70b9\u51fb\u4e0b\u65b9\u6309\u94ae\u3002"
? "\u624b\u52a8\u50a8\u5b58\u53ea\u4fdd\u7559\u672c\u5730 OPFS / IndexedDB \u5199\u5165\uff0c\u4e0d\u4f1a\u81ea\u52a8\u4e0a\u4f20\u6216\u8986\u76d6\u4e91\u7aef\u3002\u9700\u8981\u63a5\u529b\u65f6\uff0c\u8bf7\u624b\u52a8\u70b9\u51fb\u4e0b\u65b9\u6309\u94ae\u3002"
: "\u81ea\u52a8\u50a8\u5b58\u4f1a\u7ee7\u7eed\u6cbf\u7528\u5f53\u524d\u955c\u50cf\u540c\u6b65\u903b\u8f91\u4e0e\u95f4\u9694\uff1b\u624b\u52a8\u50a8\u5b58\u53ea\u4fdd\u7559\u672c\u5730\u5199\u5165\uff0c\u9700\u8981\u4f60\u4e3b\u52a8\u5907\u4efd\u548c\u6062\u590d\u3002";
}
_renderCloudStorageModeStatus(settings, _getGraphPersistenceSnapshot());

View File

@@ -1168,9 +1168,19 @@ export async function onDeleteCurrentIdbController(runtime) {
const dbName = runtime.buildBmeDbName(chatId);
const restoreSafetyDbName = runtime.buildRestoreSafetyDbName?.(chatId) || "";
const restoreSafetyChatId =
typeof runtime.buildRestoreSafetyChatId === "function"
? runtime.buildRestoreSafetyChatId(chatId)
: `__restore_safety__${chatId}`;
const persistenceState = runtime.getGraphPersistenceState?.() || {};
const hostProfile = String(persistenceState.hostProfile || "generic-st");
const localStoreLabel =
hostProfile === "luker"
? "当前聊天的本地缓存IndexedDB / OPFS不影响 Luker 侧车主存储)"
: "当前聊天的本地图谱存储IndexedDB / OPFS";
if (
!runtime.confirm(
`确定要删除当前聊天的本地缓存数据库?\n\n目标: ${dbName}\n操作不可撤销。`,
`确定要删除${localStoreLabel}\n\n将尝试清理:\n- ${dbName}\n- OPFS 当前聊天目录\n- restore safety 本地副本\n\n操作不可撤销。`,
)
) {
return { cancelled: true };
@@ -1178,32 +1188,50 @@ export async function onDeleteCurrentIdbController(runtime) {
try {
await runtime.closeBmeDb?.(chatId);
let deletedIndexedDbCount = 0;
await new Promise((resolve, reject) => {
const req = indexedDB.deleteDatabase(dbName);
req.onsuccess = () => resolve();
req.onsuccess = () => {
deletedIndexedDbCount += 1;
resolve();
};
req.onerror = () => reject(req.error);
req.onblocked = () => resolve();
});
if (restoreSafetyDbName) {
await new Promise((resolve, reject) => {
const req = indexedDB.deleteDatabase(restoreSafetyDbName);
req.onsuccess = () => resolve();
req.onsuccess = () => {
deletedIndexedDbCount += 1;
resolve();
};
req.onerror = () => reject(req.error);
req.onblocked = () => resolve();
});
}
const currentOpfsResult = await runtime.deleteCurrentChatOpfsStorage?.(chatId);
const restoreSafetyOpfsResult =
restoreSafetyChatId && restoreSafetyChatId !== chatId
? await runtime.deleteCurrentChatOpfsStorage?.(restoreSafetyChatId)
: null;
runtime.clearCachedIndexedDbSnapshot?.(chatId);
runtime.clearCachedIndexedDbSnapshot?.(restoreSafetyChatId);
runtime.clearCurrentChatCommitMarker?.({
reason: "manual-delete-current-idb",
reason: "manual-delete-current-local-storage",
immediate: true,
resetAcceptedRevision: true,
});
runtime.syncGraphLoadFromLiveContext?.({
source: "manual-delete-current-idb",
source: "manual-delete-current-local-storage",
force: true,
});
runtime.refreshPanelLiveState?.();
runtime.toastr.success(`已删除数据库 ${dbName}`);
const deletedOpfs =
currentOpfsResult?.deleted === true ||
restoreSafetyOpfsResult?.deleted === true;
runtime.toastr.success(
`已清空当前聊天本地存储IndexedDB ${deletedIndexedDbCount > 0 ? "已处理" : "无"}OPFS ${deletedOpfs ? "已处理" : "无"}`,
);
} catch (error) {
runtime.toastr.error(`删除失败: ${error?.message || error}`);
}
@@ -1212,7 +1240,7 @@ export async function onDeleteCurrentIdbController(runtime) {
export async function onDeleteAllIdbController(runtime) {
const userInput = runtime.prompt(
"此操作会删除所有聊天的 BME 本地缓存数据库,不可恢复。\n\n请输入 DELETE 确认:",
"此操作会删除所有聊天的 BME 本地图谱存储IndexedDB / OPFS不影响 Luker 侧车主存储。\n\n请输入 DELETE 确认:",
);
if (userInput !== "DELETE") {
if (userInput != null) {
@@ -1246,22 +1274,29 @@ export async function onDeleteAllIdbController(runtime) {
// continue deleting others
}
}
const opfsResult = await runtime.deleteAllOpfsStorage?.();
runtime.clearAllCachedIndexedDbSnapshots?.();
const activeChatId = runtime.getCurrentChatId?.();
if (activeChatId) {
runtime.clearCurrentChatCommitMarker?.({
reason: "manual-delete-all-idb",
reason: "manual-delete-all-local-storage",
immediate: true,
resetAcceptedRevision: true,
});
runtime.syncGraphLoadFromLiveContext?.({
source: "manual-delete-all-idb",
source: "manual-delete-all-local-storage",
force: true,
});
}
runtime.refreshPanelLiveState?.();
runtime.toastr.success(`已删除 ${deletedCount}/${bmeDbs.length} 个 BME 数据库`);
if (bmeDbs.length === 0 && opfsResult?.deleted !== true) {
runtime.toastr.info("没有找到 BME 本地图谱存储");
return { handledToast: true };
}
runtime.toastr.success(
`已清空 BME 本地图谱存储IndexedDB ${deletedCount}/${bmeDbs.length}OPFS ${opfsResult?.deleted ? "已处理" : "无"}`,
);
} catch (error) {
runtime.toastr.error(`删除失败: ${error?.message || error}`);
}
@@ -1276,7 +1311,7 @@ export async function onDeleteServerSyncFileController(runtime) {
}
const userInput = runtime.prompt(
"此操作会删除当前聊天在服务端的同步文件,不可恢复。\n\n请输入 DELETE 确认:",
"此操作会删除当前聊天在服务端的同步数据。\n\n如果该聊天已经升级到远端 v2同步 manifest 和 chunk 文件都会一起删除。\n\n请输入 DELETE 确认:",
);
if (userInput !== "DELETE") {
if (userInput != null) {
@@ -1288,11 +1323,11 @@ export async function onDeleteServerSyncFileController(runtime) {
try {
const result = await runtime.deleteRemoteSyncFile(chatId);
if (result?.deleted) {
runtime.toastr.success(`已删除服务端同步文件: ${result.filename}`);
runtime.toastr.success(`已删除服务端同步数据: ${result.filename}`);
} else {
runtime.toastr.info(
result?.reason === "not-found"
? "服务端没有找到同步文件"
? "服务端没有找到同步数据"
: `删除未成功: ${result?.reason || "未知原因"}`,
);
}